├── LICENSE
├── README.md
├── README.md.d
├── a-transparent-transparent (with -S).png
├── a-transparent-transparent (without -S).png
├── a-transparent.png
└── a.png
├── a-transparent-transparent (with -S).png
├── a-transparent-transparent (without -S).png
├── a-transparent.png
├── a.png
├── astrolabe.md
└── mktrans
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 hackerb9
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # mktrans
4 |
5 | Convert images into shaped transparent pngs by floodfilling the
6 | background with transparency (antialiased alpha channel).
7 |
8 | Top left pixel is assumed to be the background color and floodfill
9 | is from image edges, unless a different starting pixel is specified.
10 |
11 | ## Example
12 |
13 | This program is meant to be quick and simple to use, so most of the
14 | time simply specifying a filename, such as foo.jpg, is all you need.
15 |
16 | mktrans foo.jpg
17 |
18 | (Result will be in foo*-transparent.png*.)
19 |
20 | If too much or too little of the image is turning transparent, you can
21 | specify a different "fuzz" factor.
22 |
23 | mktrans -f 10 foo.jpg
24 |
25 | ## Sample results
26 |
27 | For a quick sample using the ImageMagick logo, run these commands:
28 |
29 | convert logo: logo.png
30 | mktrans logo.png
31 | display logo-transparent.png
32 |
33 | [](https://i.imgur.com/PReCAca.png)
34 |
35 | ## Installation
36 |
37 | It's just a shell script, so just download the mktrans file, mark it executable, and put it in your bin directory.
38 |
39 | wget https://github.com/hackerb9/mktrans/raw/master/mktrans
40 | chmod +x mktrans
41 | mv mktrans /usr/local/bin/
42 |
43 | Note: You will need to have [**imagemagick**](https://imagemagick.org/index.php) for it to work. You can find instructions on how to download it [here](https://imagemagick.org/script/download.php).
44 |
45 | ## All flags and complete usage
46 |
47 | Usage: mktrans [-f ] [-s|-S] [-v]
48 |
49 | -f : How loosely to match the background color (default 20%)
50 | -s: Use speedy antialiasing (much faster, slightly less acurate)
51 | -S: Do not antialias transparency (useful for repeated runs)
52 | -p ,: Floodfills from pixel at x,y instead of 0,0
53 | -v: Verbose
54 |
55 | Output filenames will be the same as input, except suffixed with
56 | `-transparent.png`. E.g., `mktrans foo.gif bar.jpg` creates
57 | `foo-transparent.png` and `bar-transparent.png`.
58 |
59 | ### About -f *fuzz*
60 |
61 | *Fuzz* is how far off the background color can be (in percent). You
62 | usually won't have to change this. If fuzz is too high, parts of the
63 | foreground image will be missing. If fuzz is too low, parts of the
64 | background will not be removed. On certain images it may help to tweak
65 | the fuzz level to get good antialiasing. (Not losing too much of the
66 | edge, nor leaving any halos).
67 |
68 | ### About -s (speedily skip subpixels)
69 |
70 | By default this script creates an antialiased (blurred) alpha channel
71 | that is also eroded by half a pixel to avoid halos. Of course,
72 | ImageMagick's morphological operations don't (yet?) work at the
73 | subpixel level, so I'm blowing up the alpha channel to 200% before
74 | eroding. Since this can be slow on large images, consider using the
75 | '-s' option which tries to antialias without the subpixel eroding.
76 |
77 | ### About -S (Supress antialiasing completely)
78 |
79 | Similar to -s, but does not antialias at all. Useful with with -p, below.
80 | See an example of why you'd use -S in [astrolabe.md](astrolabe.md).
81 |
82 | ### About -p *x*,*y*
83 |
84 | *X*,*y* specifies which pixel to start floodfilling from, instead of 0,0.
85 | You probably should just _ignore_ this option and use The GIMP for
86 | more fiddly, complex images.
87 |
88 | Theoretically you can use -p to remove any lagoons that got missed by
89 | a first floodfill. Note the letters 'a' and 'g' in the example below.
90 |
91 | convert logo: foo.png
92 | mktrans -p 160,100 foo.png
93 | mv foo-transparent.png foo.png
94 | mktrans -S -p 170,80 foo.png
95 | mv foo-transparent.png foo.png
96 | mktrans -S -p 195,65 foo.png
97 | mv foo-transparent.png foo.png
98 | mktrans -S -p 260,60 foo.png
99 | mv foo-transparent.png foo.png
100 | mktrans -S -p 285,55 foo.png
101 | mv foo-transparent.png foo.png
102 | mktrans foo.png
103 | mv foo-transparent.png logo-transparent.png
104 |
105 | [](https://i.imgur.com/CmbUnHk.png)
106 |
107 | You can find the correct coordinates for a pixel by using
108 | ImageMagick's `display` command and then middle-clicking on the image.
109 | Unfortunately, ImageMagick has no way to use that feature from a shell
110 | script. If it did, this script could simply ask you to click on all
111 | the start points of the image.
112 |
113 | ## Bugs
114 |
115 | * The -p option is ugly and probably nobody wants to use it. Maybe I
116 | should remove it just to make the documentation shorter and clearer.
117 | Also, nearly every single bug listed here is due to -p existing.
118 |
119 | * Running this script on an image that already has transparency will
120 | erode the image due to the antialiasing. Using -S is a workaround,
121 | but is not very satisfactory. Perhaps this script should remove any
122 | existing transparency before manipulating the image and then add it
123 | back in at the end. But then again, how often are people going to
124 | want to do that? The only use I can think of is when using -p.
125 |
126 | * Because of the previous bug, if you do use -p to fill lots of
127 | lagoons, you'll probably want to use -S at the same time.
128 | (Should this be done automatically if the image already has
129 | transparency? Yuck, more complexity.)
130 |
131 | See the [astrolabe](astrolabe.md) example where running mktrans a
132 | second time on a specific pixel requires the use of -S so as to
133 | not cause the image to be eroded.
134 |
135 | mktrans a.png
136 | mktrans -p 258,54 a-transparent.png
137 | mv a-transparent-transparent.png a-transparent-transparent' without -S).png
138 | mktrans -S -p 258,54 a-transparent.png
139 | mv a-transparent-transparent.png a-transparent-transparent' with -S).png
140 |
141 | * Finding the coordinates for -p is a pain. (Tip: middle click on
142 | image when viewing with `display`). It'd be nice if there was a -P
143 | option which let the user click on a point (or multiple points) in
144 | the image to start the floodfill.
145 |
146 | * Instead of choosing coordinates, we could use ImageMagick's
147 | connected components labeling (blob extraction) to give people a
148 | choice of which lagoons to fill.
149 |
150 |
151 | ## See Also
152 |
153 | This is similar to ImageMagick's
154 | ["bg_removal"](https://www.imagemagick.org/Usage/scripts/bg_removal)
155 | script, but much higher quality. (It's also faster and simpler to use.)
156 |
157 |
--------------------------------------------------------------------------------
/README.md.d/a-transparent-transparent (with -S).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackerb9/mktrans/12baf082ea0e74d5f116f0e86094106dc7b81b54/README.md.d/a-transparent-transparent (with -S).png
--------------------------------------------------------------------------------
/README.md.d/a-transparent-transparent (without -S).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackerb9/mktrans/12baf082ea0e74d5f116f0e86094106dc7b81b54/README.md.d/a-transparent-transparent (without -S).png
--------------------------------------------------------------------------------
/README.md.d/a-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackerb9/mktrans/12baf082ea0e74d5f116f0e86094106dc7b81b54/README.md.d/a-transparent.png
--------------------------------------------------------------------------------
/README.md.d/a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackerb9/mktrans/12baf082ea0e74d5f116f0e86094106dc7b81b54/README.md.d/a.png
--------------------------------------------------------------------------------
/a-transparent-transparent (with -S).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackerb9/mktrans/12baf082ea0e74d5f116f0e86094106dc7b81b54/a-transparent-transparent (with -S).png
--------------------------------------------------------------------------------
/a-transparent-transparent (without -S).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackerb9/mktrans/12baf082ea0e74d5f116f0e86094106dc7b81b54/a-transparent-transparent (without -S).png
--------------------------------------------------------------------------------
/a-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackerb9/mktrans/12baf082ea0e74d5f116f0e86094106dc7b81b54/a-transparent.png
--------------------------------------------------------------------------------
/a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hackerb9/mktrans/12baf082ea0e74d5f116f0e86094106dc7b81b54/a.png
--------------------------------------------------------------------------------
/astrolabe.md:
--------------------------------------------------------------------------------
1 | # Using -S to deal with multiple runs
2 |
3 | If you run this script on a file that already has transparency, you'll
4 | probably want to use the `-S` option to suppress antialiasing. But why
5 | would you want multiple runs of mktrans on the same file? Because one
6 | can clear out "lagoons", areas that should have been transparent but
7 | the floodfill didn't reach them. You do that by using the `-p x,y`
8 | option to specify which pixel to start floodfilling at.
9 |
10 | ## Lagoon problem
11 |
12 | Here's an example image which has already been run through `mktrans` once. As you can see, it left a black lagoon in the middle of the loop on this astrolabe.
13 |
14 |
15 |
16 | ## Eroded pixels problem
17 |
18 | We can find the coordinates of the lagoon by running `display
19 | a-transparent.png` and clicking the middle mouse button. In this case,
20 | 256,64 is one of the black pixels.
21 |
22 | If we did the most obvious thing and just ran
23 |
24 | ```bash
25 | mktrans -p 256,64 a-transparent.png
26 | ```
27 |
28 | then the output file (a-transparent-transparent.png) would lose some pixels due to rerunning the antialiasing step on the old transparency.
29 |
30 |
31 |
32 | ## Kludge: Using -S on subsequent runs
33 |
34 | Running `mktrans -S` supresses antialiasing completely.
35 |
36 | ```bash
37 | mktrans -S -p 256,64 a-transparent.png
38 | ```
39 | As you can see this looks much better:
40 |
41 |
42 |
43 | ## But wait... isn't there a better way?
44 |
45 | Yes. There are at least two ways this could be better, but there are no plans to implement them.
46 |
47 | 1. mktrans could automatically use `-S` when it detects a file already contains transparency.
48 |
49 | 2. More importantly, `-S` isn't even the right solution. The proper thing to do is to extract and remove the alpha channel from the original image, run mktrans, and
50 | then composite the original alpha channel with the new one.
51 |
52 | But, both of those improvements are only necessary if people are going to be running `mktrans` iteratively and the author (hackerb9) is not convinced that
53 | people want to do that. The only use case is when people are using the `-p` option, which is already a pain in the butt to use as it requires firing up a graphical
54 | program, like ImageMagick's `display`, to find the coordinates of lagoons. Wouldn't people just want to use a program like the [GNU Image Manipulation Program](https://gimp.org/)
55 | instead of using mktrans?
56 |
57 | If you think these or other improvements should be made, please file a bug with an explanation of your reasoning.
58 |
59 |
--------------------------------------------------------------------------------
/mktrans:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # B9 June 2017
3 |
4 | # mktrans
5 | # This is similar to ImageMagick's bg_removal script, but much higher
6 | # quality. (It's also faster and simpler to use.)
7 | #
8 | # For a sample, run these commands:
9 | # convert logo: logo.png
10 | # mktrans logo.png
11 | # display logo-transparent.png
12 |
13 |
14 | # Fuzz is how far off the background color can be (in percent).
15 | # This is important for getting good antialiasing.
16 | defaultfuzz=20
17 |
18 | usage() {
19 | cat <] [-s|-S] [-p ,] [-v]
32 |
33 | -f : How loosely to match the background color (default $defaultfuzz%)
34 |
35 | Advanced options:
36 | -s: Use speedy antialiasing (much faster, slightly less acurate)
37 | -S: Supress antialiasing completely. (Useful for repeated runs)
38 | p ,: Floodfill from pixel at x,y instead of 0,0
39 | -v: Verbose
40 | EOF
41 |
42 | # * Side note: This creates an antialiased (blurred) alpha channel
43 | # that is also eroded by half a pixel to avoid halos. ImageMagick's
44 | # morphological operations don't (yet?) work at the subpixel level,
45 | # so I'm blowing up the alpha channel to 200% before eroding. Since
46 | # this can be slow on large images, consider using the '-s' option
47 | # which uses a faster, lower quality antialiasing.
48 |
49 | # * Running this script on an image that already has transparency will
50 | # erode the image due to the antialiasing. Using -S is a workaround,
51 | # but is not very satisfactory. Perhaps this script should remove any
52 | # existing transparency before manipulating the image and then add it
53 | # back in at the end. But then again, how often are people going to
54 | # want to do that? The only use I can think of is when using -p.
55 |
56 | # * Because of the previous bug, if you do use -p to fill lots of
57 | # lagoons, you'll probably want to use -A at the same time.
58 |
59 | # * Finding the coordinates for -p is a pain. It'd be nice if there was
60 | # a -P option which let the user click on a point (or multiple points)
61 | # in the image to start the floodfill.
62 |
63 | exit 0
64 | }
65 |
66 | # Work around MS Windows having a program called "convert".
67 | if [[ "$COMSPEC" ]]; then
68 | shopt -s expand_aliases # Allow aliases to workaround quirks.
69 | alias convert="magick convert" # Shun MS Windows' "convert" command.
70 | fi
71 |
72 |
73 | fuzz=$defaultfuzz
74 | pixelcomma="0,0"
75 | pixelplus="+0+0"
76 |
77 | while getopts f:sAShp:v name; do
78 | case $name in
79 | f) fuzz=$OPTARG
80 | ;;
81 | s) sflag=True
82 | ;;
83 | S|A) noantialias=True
84 | ;;
85 | v) vflag=True
86 | ;;
87 | h) usage
88 | ;;
89 | p) pixelcomma=$OPTARG
90 | pixelplus=+${OPTARG%,*}+${OPTARG#*,}
91 | pflag=True
92 | ;;
93 | *) usage
94 | ;;
95 | esac
96 | done
97 |
98 | shift $((OPTIND-1))
99 | [[ "$#" != 0 ]] || usage
100 |
101 |
102 | for filename; do
103 | # Get color of 0,0 (top left) pixel
104 | color=$(convert "$filename" -format "%[pixel:p{$pixelcomma}]" info:-)
105 | if [[ "$color" == *rgba*",0)" ]]; then
106 | color="${color%,0)},1)" # Floodfill only works with opaque colors.
107 | fi
108 | if [[ "$color" == "none" ]]; then
109 | echo "Error: $filename: pixel at $pixelcomma is completely transparent. Cannot floodfill." >&2
110 | continue
111 | fi
112 |
113 | options=""
114 | if [ -z "$pflag" ]; then
115 | # Add a 1 pixel border so we'll fill from the bottom and sides as well.
116 | options+=" -bordercolor $color -border 1 "
117 | fi
118 | # In a new stack, make a copy of the image
119 | options+=" ( +clone "
120 | # [copy] floodfill with transparency ("none") starting at top-left
121 | options+=" -fuzz $fuzz% -fill none -floodfill $pixelplus $color"
122 | # [copy] extract just the transparency (alpha channel)
123 | options+=" -alpha extract"
124 |
125 | if [ -z "$noantialias" ]; then
126 | if [ -z "$sflag" ]; then
127 | # [copy] blow up the alpha channel so we can do sub-pixel morphology
128 | options+=" -geometry 200%"
129 | # [copy] blur the alpha channel to make it antialiased
130 | options+=" -blur 0x0.5"
131 | # [copy] shrink the region that is opaque by half a pixel.
132 | options+=" -morphology erode square:1"
133 | # [copy] scale the alpha channel back to normal size.
134 | options+=" -geometry 50%"
135 | else # sflag: speedy antialias
136 | # [copy] blur the alpha channel to make it antialiased
137 | options+=" -blur 0x1"
138 | # [copy] only antialias inside the figure (<50% opacity becomes 0%)
139 | options+=" -level 50%,100%"
140 | fi
141 | fi
142 | # [copy] end the stack.
143 | options+=" ) "
144 | # Compose the original image and the copy's alpha channel.
145 | options+=" -compose CopyOpacity -composite"
146 | if [ -z "$pflag" ]; then
147 | # Remove the 1 pixel border we added
148 | options+=" -shave 1"
149 | fi
150 |
151 | [ "$vflag" ] && echo convert "$filename" $options "${filename%.*}-transparent.png"
152 |
153 | convert "$filename" $options "${filename%.*}-transparent.png"
154 | done
155 |
--------------------------------------------------------------------------------