├── 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 | Astrolabe 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 | [![After flattening on a saddle brown background](https://i.imgur.com/Exrm0tD.png)](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 | [![Using -p to fill lagoons](https://i.imgur.com/Hxl1a1A.png)](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 | After first run of mktrans 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 | Second run, but without -S 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 | Second run, with  -S 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 | --------------------------------------------------------------------------------