I'm trying to create a transparent PNG with ImageMagick. No matter the incantations to "convert", when I use identify against the image, it always says:
Depth: 8/1 bit
Channel depth:
gray: 1 bit
alpha: 1 bit
When I look at a transparent PNG found on the web, it says:
Depth: 8 bit
gray: 8 bit
alpha: 8 bit
The reason this seems to matter is that I'm using the transparent PNGs I create as a watermark within FFMPEG. When I use the PNG that ImageMagick creates, it causes the video to appear to have like a 50% gray opacity. However, when I use the PNG I found on the web, it works fine. According to identify, the only difference is the depth.
Here are some of the things I've tried:
convert -size 640x480 xc:none -depth 8 test.png
convert -size 640x480 xc:transparent -depth 8 test.png
The other thing I noticed is that Gimp shows the ImageMagick image to have a Colorspace of Grayscale, even though identify says it's RGB. The image that I found on the web, that works, shows a Colorspace of RGB in both Gimp and identify.
Any ideas?
First, about ImageMagick's 'grayscale'.
ImageMagick doesn't actually have such a colorspace. It only fakes it within RGB space, by setting all values in the R (red), G (green) and B (blue) channels to the same values. (If the three values are not the same, the image is no longer grayscale.)
Second, about your (seemingly) unsuccessful attempts to create images with 8-bit alpha channel.
This is caused by you not putting any different 'color' values into your transparent areas -- they are all plain (fully transparent).
Try this command which converts the built-in ImageMagick logo: picture:
convert \
logo: \
-bordercolor white \
-background black \
+polaroid \
polaroid.png
The output image:
will happily show your required 8-bit alpha values:
identify -verbose polaroid.png | grep -A 4 "Channel depth:"
Channel depth:
red: 8-bit
green: 8-bit
blue: 8-bit
alpha: 8-bit
Or try to convert the built-in rose: image to a semi-transparent one:
convert rose: -alpha set -channel A -fx '0.5' semitransp-rose.png
Same result: 8-bit depth for alpha channel.
To modify one of your original commands:
convert -size 640x480 xc:none -depth 8 -channel A -fx 0.5 test.png
If you identify -verbose the resulting image, you'll find the R, G and B channels to be only 1-bit depth, while the A channel is 8-bit. That's because it's actually using a value different from 0, while the other channels are all 0.
Related
I'm trying to convert some small PNG images from 32-bit color mode to indexed color mode.
For color images, I ran the command convert IMGS/FLAME.png INDEXED_IMGS/FLAME.png and it converted fine. For an image that had only grayscale colors, I ran that same command (with the filename changed obviously) but I got a warning:
convert: profile 'icc': 'RGB ': RGB color space not permitted on grayscale PNG 'INDEXED_IMGS/SHADOW.png' # warning/png.c/MagickPNGWarningHandler/1748.
I ran file IMGS/*.pngand got
IMGS/FLAME.png: PNG image data, 16 x 16, 8-bit/color RGBA, non-interlaced
IMGS/SHADOW.png: PNG image data, 8 x 8, 8-bit/color RGBA, non-interlaced
which is expected; both images are in 8-bit RGBA mode (since that's the mode I created them in Photoshop). However, when I run file INDEXED_IMGS/*.png I get
INDEXED_IMGS/FLAME.png: PNG image data, 16 x 16, 4-bit colormap, non-interlaced
INDEXED_IMGS/SHADOW.png: PNG image data, 8 x 8, 8-bit grayscale, non-interlaced
The 4-bit colormap part checks out, but the grayscale part does not.
So my question is: how can I convert a grayscale image to indexed mode? What really gets me is that it starts out in RGBA mode like the color image, but for some reason it converts automatically to grayscale mode. Is there a way to prevent it from doing that?
I should add that I have a bash script that looks like this:
#!/bin/bash
for img in IMGS/*.png; do
file=$(basename $img)
convert $img INDEXED_IMGS/$file
done
so I don't wanna manually distinguish between grayscale and colored images. If there's a way to do so automatically with some command that's fine though.
Here is info about my ImageMagick tool:
Version: ImageMagick 7.0.8-42 Q16 x86_64 2019-04-24 https://imagemagick.org
Copyright: © 1999-2019 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP
Delegates (built-in): bzlib freetype heic jng jp2 jpeg lcms ltdl lzma openexr png tiff webp xml zlib
With ImageMagick, for 24-bit color, append the output with PNG8:output
convert input.png PNG8:output.png
PNG grayscale images do not support color profiles, so you get that warning. But the resulting image should be 8-bit palette.
If you have 32-bit color, then this needs more to be done. The color under the alpha channel must be one constant color and one not used elsewhere in the image. Find such a color after converting to 256 colors and set the color under the transparency to that color. For example if you have no opaque black in your image after converting to 256 colors, then set the alpha base color to black.
convert image.png +dither -colors 256 -background black -alpha background PNG8:output.png
You can get a list of unique colors from the image as follows:
convert image.png +dither -colors 256 -unique-colors txt:
Here is an example:
Make it 32-bit transparent:
convert rose.png -fuzz 20% -transparent red rose_trans32.png
identify -verbose rose_trans32.png
...
Colorspace: sRGB
Type: TrueColorAlpha
...
Convert to palette alpha:
convert rose_trans32.png -alpha off +dither -colors 256 -unique-colors txt:
List shows no black
convert rose_trans32.png +dither -colors 256 -background black -alpha background PNG8:rose_trans8.png
Or if you already know that the 32-bit version has not black, then just:
convert rose_trans32.png -background black -alpha background PNG8:rose_trans8.png
identify -verbose rose_trans8.png
...
Colorspace: sRGB
Type: PaletteAlpha
...
If you do this adding -colorspace gray, ImageMagick will still report as type grayscalealpha, since it recognizes it as a single channel image with transparency. But using EXIFTOOL, it will report 9 ColorType: 3, which is 3 = RGB Palette
NOTE: For ImageMagick 7, change convert to magick.
I want to get the mean of a sequence of images by using Imagemagick. Therefore I use the following command:
convert *.png -evaluate-sequence mean MEAN.png
Each of my images does contain an alpha channel. What I want is: Combine all the images by ignoring the alpha channel.
When I combine the images, the alpha channel is considered in the "mean" method and my final image has transparency. That isn't what I want.
Result:
I tried to add the parameter -alpha off, but then Imagemagick converts the alpha channel to black.
convert *.png -alpha off -evaluate-sequence mean MEAN.png
Result:
Photoshop does it right. I load all images in a stack and create a smart object. When I use the "mean" method in Photoshop, the alpha channel is not considdered in the final result.
Result that I want with Imagemagick:
Does someone have an idea how to do that with Imagemagick?
What you need to do is to use the alpha channels as weighting images for each image. The total fraction of white values at each pixel from all the alpha channels would be the weight to use for the average. So something like this should do what you want or at least be close.
First, cd to your directory of images. Then run the following.
convert *.png -evaluate-sequence mean \
\( -clone 0 -alpha off \) \
\( -clone 0 -alpha extract \) \
-delete 0 +swap -compose divide -composite result.png
This will work if there is some image texture at each pixel coming from al least one image. That is at a given pixel all images are not totally black (transparent).
compare -metric rmse result.png mean_photoshop.png null:
125.167 (0.00190993)
So this shows that there is about 0.2% difference between my result and what you got from photoshop
Maybe this way of working will help you get there - or at least explain the problem:
convert xc:"rgba(255,0,0,1)" xc:"rgba(0,0,0,1)" xc:"rgba(0,0,0,0)" -depth 8 -evaluate-sequence mean txt:
Output
# ImageMagick pixel enumeration: 1,1,65535,srgba
0,0: (21845,0,0,43690) #550000AA srgba(85,0,0,0.666667)
Using IM 6.8.9.4 Q16 or IM 7.0.5.5 Q16 Mac OSX Sierra, this seems to work fine for me:
Make transparent image
convert logo: -transparent white logot.png
Get mean
convert logot.png logot.png logot.png -alpha off -evaluate-sequence mean result.png
magick logot.png logot.png logot.png -alpha off -evaluate-sequence mean result.png
This also seems to work:
convert logot.png logot.png logot.png -channel rgb -evaluate-sequence mean -alpha off result.png
So perhaps you need to upgrade your ImageMagick (and/or libpng?)
Can you post a zip file of some of your input images, so we can test with your images?
One problem that I see is that the PNG images that you provided have black under the transparent areas and not image texture. So when you disable alpha as in my commands above, you see black and the black gets averaged into the final result. Did you use these same PNG images in Photoshop or did you have Photoshop PSD images or some other images that you used and then exported to PNG, which may have put black under the transparent areas. Have you tried using the same PNG images in Photoshop to do the average?
In fact, you have 8-bit color (palette) images, which have one color (black) assigned to be the transparent color.
The source is an RGBA PNG image (color_type=6 and bit_depth=8).
I need an image with indexed color and 2 palette items (color_type=3, bit_depth=1).
I tried with ImageMagick, but was able to reach only 1bit grayscale image (color_type=0, bit_depth=1) or 2bit indexed color image (color_type=3, bit_depth=2) in which only 2 colors are in use.
According to the PNG specification such image is possible, but how to create it?
Here is an image I am trying to convert:
The result of "convert input.png -type palette -depth 1 output.png":
The result of "convert input.png -type palette -depth 1 -colors 2 output.png"
Both results have bit_depth=2, but the second one uses only 2 colors of 4 possible.
Use one of the following 3, ordered from least to most ancillary tags in the output file:
convert -colors 2 -define png:include-chunk=none -verbose input.png output.png
convert -colors 2 -define png:exclude-chunk=bkgd -verbose input.png output.png
convert -colors 2 -background #000000 -verbose input.png output.png
The root of this problem is that ImageMagick by default tags the image with a white background color (bKGD) PNG chunk (unnecessarily I'd say), and then adds this color to the palette if it's not already there, even if the image has no pixels of that color. Your particular image doesn't have white after converting to 2-color, so the unneeded background color tag becomes a 3rd color and it can no longer be saved as a 1-bit indexed color image. See also this from the author of IM.
The reason others have failed to reproduce the problem is probably that they've tested with images where one of the 2 colors happened to be white.
The 1st option with -define png:include-chunk=none avoids the problem by not outputting any ancillary PNG chunks at all (e.g. bKGD, gAMA, cHRM, tEXt, tIME). Like pngcrush -rem alla. I'd prefer this for a less cluttered file (without it IM will add a few of these even if they weren't in the input file). Note: There's also the simple -strip option which should avoid most of these, but as of v6.9.3 it won't cut bKGD due to a bug.
The 2nd with -define png:exclude-chunk=bkgd removes only the offending background chunk.
The 3rd option with -background #000000 retains all ancillary PNG chunks including bKGD but sets it black, one of the 2 colors present in your image, so it can still be 1-bit. Adjust the color for an image with neither white nor black in it.
Note that for all these I'm including the -verbose switch. Not overly verbose; just goes from zero to two lines of status output where you'll notice a "2c" if the image stayed 2-color or a "3c" if not. It will also tell you if the palette reduction was lossy or not. It also outputs "8-bit sRGB" for most images, even paletted ones with fewer than 8 bits-per-pixel; that's not a bug as in your comment to another answer #johnfound, this refers not to the bits-per-pixel but to the bits-per-color component. It can be more than 8-bit for (rare) deep color images.
convert input.png -background white -type palette -depth 1 -colors 2 output.png
works for me.
(Why -depth=1 is not enough? No idea.)
BTW, the tweakpng tool is useful for checking this kind of things.
Update: if the images have transparency, you might play safer by removing it explicitly:
convert input.png -background white -flatten -type palette -depth 1 -colors 2 output.png
(You can replace white for your preference)
I think the command you need is this:
convert input.png -type palette -depth 1 output.png
If not, please post your input image and say how/where you find the color_type and bit_depth fields you refer to.
Exiftool tells me this:
ExifTool Version Number : 9.76
File Name : output.png
Directory : .
File Size : 2.3 kB
File Modification Date/Time : 2015:01:10 19:20:33+00:00
File Access Date/Time : 2015:01:10 19:21:46+00:00
File Inode Change Date/Time : 2015:01:10 19:20:33+00:00
File Permissions : rw-r--r--
File Type : PNG
MIME Type : image/png
Image Width : 640
Image Height : 427
Bit Depth : 1
Color Type : Grayscale
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
Gamma : 2.2
Background Color : 1
Datecreate : 2015-01-10T10:21:30+00:00
Datemodify : 2015-01-10T10:21:30+00:00
Image Size : 640x427
ImageMagick identify tells me this:
Image: output.png
Format: PNG (Portable Network Graphics)
Mime type: image/png
Class: PseudoClass
Geometry: 640x427+0+0
Units: Undefined
Type: Bilevel
Base type: Bilevel
Endianess: Undefined
Colorspace: Gray
Depth: 8/1-bit
Channel depth:
gray: 1-bit
Channel statistics:
Pixels: 273280
Gray:
min: 0 (0)
max: 255 (1)
mean: 1.90168 (0.00745755)
standard deviation: 21.9388 (0.0860345)
kurtosis: 129.1
skewness: 11.4499
Colors: 2
Histogram:
271242: ( 0, 0, 0) #000000 gray(0)
2038: (255,255,255) #FFFFFF gray(255)
Colormap entries: 2
Colormap:
0: ( 0, 0, 0) #000000 gray(0)
1: (255,255,255) #FFFFFF gray(255)
Rendering intent: Undefined
Gamma: 0.45455
Background color: gray(255)
Border color: gray(223)
Matte color: gray(189)
Transparent color: gray(0)
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 640x427+0+0
Dispose: Undefined
Iterations: 0
Compression: Zip
Orientation: Undefined
Properties:
date:create: 2015-01-10T19:20:33+00:00
date:modify: 2015-01-10T19:20:33+00:00
png:bKGD: chunk was found (see Background color, above)
png:gAMA: gamma=0.45455 (See Gamma, above)
png:IHDR.bit-depth-orig: 1
png:IHDR.bit_depth: 1
png:IHDR.color-type-orig: 0
png:IHDR.color_type: 0 (Grayscale)
png:IHDR.interlace_method: 0 (Not interlaced)
png:IHDR.width,height: 640, 427
png:text: 2 tEXt/zTXt/iTXt chunks were found
signature: 3e08d7fea7bc7aeb0659ac2e2696084083d35ce30b0e3075dc561ad94259eaec
Artifacts:
filename: output.png
verbose: true
Tainted: True
Filesize: 2.33KB
Number pixels: 273K
Pixels per second: 27.33MB
User time: 0.000u
Elapsed time: 0:01.009
Version: ImageMagick 6.8.9-8 Q16 x86_64 2014-11-10 http://www.imagemagick.org
Is there a way to move all gray colors of a CMYK image (e.g. a CMYK .tiff) into the black (K) plate with ImageMagick?
(In Adobe Acrobat Pro, this functionality is labeled: "Promote grays to CMYK black")
Here's an image to experiment with:
You can view an example of this process on Wikipedia.
Also not a full answer as such, but hopefully useful towards producing one - by Kurt, myself or others. I looked at the Photoshop method of GCR and am adding the characteristic curves that Adobe seem to use for GCR. There are 5 levels, ranging from "None", through "Light", "Medium", "Heavy" and "Full".
I presume the "Light" curve is showing that no black ink is added into the mix till it would be over 50%, and the "Medium" shows the black would have to be only 25% before any gets added, and the "Heavy" shows that only 12-15% of black is needed before black ink gets added into the mixture.
I also add the following reference to assist any other answerers... see PDF here.
Taking into account that the provided example image is NOT a TIFF (as announced), and does NOT use a CMYK color space (as announced), but is a JPEG using sRGB, here is how you would convert it into a TIFF file using CMYK, where the black channel is used:
convert \
http://i.stack.imgur.com/HFnCz.jpg \
-colorspace cmy \
-colorspace cmyk \
cmyk.tiff
To separate out the different colors again and show them as grayscale images each, use these commands:
convert HFnCz.tiff -colorspace cmyk -channel c -separate channel_c.png
convert HFnCz.tiff -colorspace cmyk -channel m -separate channel_m.png
convert HFnCz.tiff -colorspace cmyk -channel y -separate channel_y.png
convert HFnCz.tiff -colorspace cmyk -channel k -negate -separate channel_k.png
I did output to PNG in order to keep the file size a bit smaller...
Here are the 4 color separations. Top left is C, top right is M, bottom left is Y, bottom right is K:
Update
I made a mistake in my original answer. The -negate command parameter should only be there for the blacK channel.
I have some PNG files I wish to convert to 256 colors (i.e. GIF-like). Each image has transparency, but when I try to convert I always end up with a black background on the resulting image.
Here is my current command:
convert file.png -colors 255 file256.png
I'm using 255 colors because I read that you need one color for the alpha channel (though I don't think that should apply to PNGs). I've tried many other options such as -background none, -channel RGBA and -matte but nothing is working at all.
Interestingly, this command did work when converting to grayscale:
convert file.png -channel RGBA -matte -colorspace gray file256.png
It kept the transparent background. But replacing -colorspace gray with -colors 256 doesn't work.
The reason to use 255 instead of 256 colors is that one color needs to be reserved for "binary" / "boolean" transparency, i.e. all pixels of that color are interpreted as completely transparent. There (usually) is no such thing like an alpha channel with 256-color / palette-based images. For reference, you may want to read the ImageMagick usage sections about Color Quantization and Transparency and GIF Boolean Transparency. That said, this should convert your 32-bit true-color PNG with alpha channel to an 8-bit PNG with palette where all pixels that are fully transparent in the input image are also fully transparent in the output image:
convert file.png png8:file256.png
The png8 instructs ImageMagick to write a GIF-like "8-bit indexed with optional binary transparency" PNG and implies to use 255 "real" colors.
Have you tried -colorspace transparent to preserve the Alpha channel?