combine two commands that swap white for black into one - imagemagick

I have a large number of images that are white with transparent backgrounds, and I would like to make them black with transparent backgrounds. It's simple enough to do with GIMP or BIMP, but with thousands of images, command-line seems a better way to go.
In ImageMagick, I've found that the following two commands do what I want:
mogrify -alpha set -channel RGBA -background black -flatten +repage -negate *.png
mogrify -alpha set -channel RGBA -transparent white *.png
However, I'd rather not make two passes. I've tried to combine them a number of different ways:
mogrify -alpha set -channel RGBA -background black -flatten +repage -negate +repage -transparent white *.png
mogrify -alpha set -channel RGBA -background black -flatten +repage -negate -alpha set -channel RGBA -transparent white *.png
mogrify -alpha set -channel RGBA -background black -flatten +repage -negate +repage -alpha set -channel RGBA -transparent white *.png
as well as a couple other permutations of the same ideas. All of them result in a purely black image. What am I missing?
Is there an easier way to invert black and white or at least convert white to black, but leaving the alpha layer untouched?
mogrify -negate *.png
converts white to transparent and transparent to white, and
mogrify -fill black -opaque white *.png
leaves behind messy white edges.

In ImageMagick you can do:
mogrify -format png -fill "rgba(0,0,0,1)" -opaque "rgba(255,255,255,1)" *.png
If your white is not perfectly white, then add -fuzz XX%
mogrify -format png -fuzz 5% -fill "rgba(0,0,0,1)" -opaque "rgba(255,255,255,1)" *.png
The issue is that you need to specify alpha values in your colors, since your image has transparency. Thus use rgba(r,g,b,a) values (note the a) or use hex values with #RRGGBBAA
If using IM 7, then mogrify is replace with magick mogrify
Here is an example using convert. I created a white image with transparency elsewhere from the logo: image.
http://www.fmwconcepts.com/misc_tests/transparency_invert/logot.png
Then ran
convert logot.png -fill "rgba(0,0,0,1)" -opaque "rgba(255,255,255,1)" logot_invert.png
Which returns black where the input was white and keeps the transparency unchanged.
http://www.fmwconcepts.com/misc_tests/transparency_invert/logot_invert.png
Is this not what you want?

Perhaps what you want is the following in ImageMagick. Just a guess until I can see your actual input files.
mogrify -format png -alpha off -negate -alpha on *.png

In ImageMagick, try
mogrify -alpha off -negate -alpha on *.png
This turns off the alpha channel inverts the black and white and then turns on the original alpha channel.
As a test, I did
convert aircon.png -alpha off -negate -alpha on aircon_fred.png
The equivalent of your two mogrify command is
mogrify -background black -alpha background -alpha off -negate -transparent white *.png
I had to replace your -flatten with the equivalent since one needs to reset the compose method to over afterwards for the -transparent to work. But mogrify does not accept -compose over.
As a simple test, I did
convert aircon.png -background black -flatten -negate -transparent white aircon_fred2.png
Another method similar to the first is just to make the whole underlying image black and keep the alpha channel.
mogrify -alpha off -fill black -opaque white -alpha on *.png
Again as a test, I did
convert aircon.png -alpha off -fill black -opaque white -alpha on aircon_fred3.png
However, my first method should give better antialiasing, since it keeps your original alpha channel. Your method will recreate the alpha via -transparent white and will have more stair-stepped aliasing.

Related

how to autocrop a deskewed scanned image

Following this approach, deskewing works great, how do I autocrop so it the outer border comes in until it finds a mostly white contiguous rectangle, so it could be auto-cropped after deskewing?
If you are using Imagemagick 7, you can do an extreme trim using the new -define trim:percent-background=0% to remove all the background from the image. See https://imagemagick.org/script/command-line-options.php#trim
Input:
magick skewed_1500.jpeg -background black -deskew 60% -background black -define trim:percent-background=0% -fuzz 1% -trim +repage x.jpg
Result:
ADDITION:
You can trim even more by trimming before the deskew. I had to use a large fuzz value to remove the bottom white. There must be some slight gray spot somewhere down there that I cannot see. But if there is no black border to start, you may trim too much white all around. That is the downside.
magick skewed_1500.jpeg -bordercolor white -border 1 -fuzz 75% -trim +repage -background black -deskew 60% -background black -define trim:percent-background=0% -fuzz 1% -trim +repage x.jpg
Result:

Auto crop text(signature) from image and change background color using Imagemagick

Need to auto crop text(signature)from an images(sample image:Image1 )and Need to change background color of cropped image.
Need to achieve this using Imagemagick.
Is it any possible way to achieve these ?
I am using version ImageMagick 7.0.7-28
williamson image
example image
What do you mean by auto-crop? You can use ImageMagick -trim to get the signature cropped to its bounding box and then use -fuzz -opaque to change the background.
Input:
magick signature.png -fuzz 20% -trim +repage -fill pink -opaque white result.png
Or you can just make the background transparent.
magick signature.png -fuzz 20% -trim +repage -transparent white result2.png
I do not see any color change in the text, though it is not quite as smooth. Adjust the fuzz value as desired to remove the gray and keep the text as smooth as you can.
Input:
ImageMagick 7 command:
magick signature3.jpeg -fuzz 15% -fill white +opaque "#5B000C" -trim +repage result.png

How to find out the average color (rgb) of masked area of an Image

I would like to get the average color in rgb of the mask area of a png image.
the following just outputs the average color of the whole image
convert demo.png -mask demo_mask.png -resize 1x1 txt:-
In ImageMagick, -scale 1x1! will ignore the transparent pixels and give you the average of the opaque pixels. So if you want the average of the masked region, you can put the mask into the alpha channel and then use -scale 1x1! to average it down to one pixel. The mask should be white where you want to get the average and black where it should be transparent and ignore those pixels in the average. So this should do it.
convert image.png mask.png -alpha off -compose copy_opacity -composite -scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:
For example if I make the logo: image transparent where it is white and then get the average, I get
convert logo: -transparent white -scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:
srgb(100,81,99)
You can show that this works, by doing it the long way. Multiply the mask by the image, then get the average of each channel of the product. Then get the average of the mask. Then compute the ratios scaled to the range 0 to 255.
convert logo: -transparent white logot.png
convert logot.png -alpha extract mask.png
declare `convert \( logot.png -alpha off \) mask.png -compose multiply -composite -format "IR=%[fx:mean.r]\nIG=%[fx:mean.g]\nIB=%[fx:mean.b]\n" info:`
echo "IR=$IR; IG=$IG; IB=$IB"
IR=0.0651798; IG=0.0529989; IB=0.0641607
MM=`convert mask.png -format "%[fx:mean]\n" info:`
echo "MM=$MM"
MM=0.165872
convert xc: -format "srgb(%[fx:round(255*$IR/$MM)],%[fx:round(255*$IG/$MM)],%[fx:round(255*$IB/$MM)])\n" info:
srgb(100,81,99)
Result is the same as above.
ASIDE: Note that
convert \( logot.png -alpha off \) mask.png -compose multiply -composite ...
in this case is the same as just
convert logot.png -alpha remove ...
But I show it the long way, if the user has a separate mask and image with no transparency.
You should be able to get very nearly what you want with a command something like this...
convert image.png mask.png -compose copyopacity -composite -resize 1x1! txt:-
To output only the color information you can try something like this...
convert image.png mask.png \
-compose copyopacity -composite -resize 1x1! -format "%[pixel:p]" info:
I haven't tried it, but you may have to "-negate" your mask image depending on which version of IM you're using because there have been changes in the way the alpha channel is handled.
You'll get a very slightly different result if you "-trim" before the "-resize".
If you don't want to output the alpha channel information, you can add "-alpha off" after the "-resize".
Perhaps...
convert demo.png -mask demo_mask.png -trim -fx mean -extent 1x1 txt:- |\
tail -1 | cut -d ' ' -f 4
This would work because -trim will reduce the masked image down to the MBR of the ROI. Fx operator -fx mean will convert all pixels into the overall average. And finally the -extent 1x1 will isolate the first pixel in the image. The rest is basic unix utilities.
Another option with better performance...
MEAN=$(convert demo.png -mask demo_mask.png -trim -format '%[fx:mean]' info:-)
convert null: -depth 8 -format "%[pixel:$MEAN]" info:-
Or from the Quantization documentation...
convert demo.png -mask demo_mask.png -trim -scale 1x1\! '%[pixel:s]' info:-

Replace Colors in Image with Transparency

How do I replace a color in an image which contains transparency with ImageMagick, but afterwards retain the transparency of the original image.
This is very useful for batch-changing of colors in icons.
Updated Answer
Option 1
A simpler option might be like this:
convert start.png -alpha deactivate -fill blue -opaque red -alpha activate result.png
which changes this:
to this:
Option 2
Another option, which uses an in-memory copy of the image, can also avoid the need to create 2 processes and write an intermediate file to disk:
convert start.png -write MPR:orig \
-alpha off -fill blue -opaque red \
MPR:orig -compose CopyOpacity -composite result.png
Option 3
Yet another method, that uses clone instead of MPR:
convert start.png \
\( +clone -alpha off -fill blue -opaque red \) \
+swap -compose CopyOpacity -composite result.png
Original Answer
If I create an image that contains transparency like this:
convert -size 400x400 xc:none -fill red -draw "rectangle 10,10 100,100" -fill blue -draw "rectangle 200,200 300,300" -bordercolor black -border 5 start.png
I'll get this (I am showing it overlaid on a checkerboard just to visualise the transparency):
If I now run this
convert start.png -fill yellow -opaque red result.png
I'll get this (again overlaid on a checkerboard):
Not sure why you need a more complicated, 2-stage process - or have I misunderstood your question?
convert file-in.png -alpha off -fill REPLACEMENT -opaque COLOR file-out.png
then
convert file-out.png file-in.png -compose CopyOpacity -composite PNG32:file-final.png

ImageMagick: How to make both black and white transparent?

Converting black and dark shades to transparent works fine with ImageMagick.
I even managed to perform a crop and resize in the same line.
convert input.png -background none -fuzz 45% -transparent black -flatten -crop 640x480+12+9 -resize 105% output.png
However, the input image also contains a number of almost white lines, which I also would like to convert to transparent in the output.
How do I go about that? Is it possible to do it within the same command line?
Sure, just add a second -transparent.
convert -size 512x512 gradient:black-white a.png # create initial black-to-white gradient
convert -fuzz 20% a.png -transparent black -transparent white result.png # lose 20% off black end and white end
Or, with extra fuzz...
convert -fuzz 40% a.png -transparent black -transparent white result.png

Resources