开发者

Detect Alpha Channel with ImageMagick

Scenario

I would like to save images with alpha transparency as .png 开发者_Go百科and images without alpha transparency as .jpg (even if their original format is .png or .gif). How can I detect whether or not an image has alpha transparency using ImageMagick?


Check if the image has an alpha channel

Use -format %A, as per serhiy.h's answer. From the documentation:

%A    image transparency channel enabled (true/false)

Check if the image has no transparent or translucent pixels

Use -format %[opaque]. From the documentation:

%[opaque]    CALCULATED: is image fully-opaque?


Example

To demonstrate, lets create an image a.png that has an alpha channel but is fully opaque, and an image b.png that is the same except for one translucent pixel:

$ convert rose: PNG32:a.png
$ convert rose: -fill '#0008' -draw "matte 10,10 point" PNG32:b.png

As expected, the %A escape produces True for both images, since both have an alpha channel:

$ identify -format '%A' a.png
True
$ identify -format '%A' b.png  
True

Whereas the %[opaque] escape produces true in one case, and false in the other due to the one transparent pixel:

$ identify -format '%[opaque]' a.png
true
$ identify -format '%[opaque]' b.png
false


The ImageMagik command:

identify -format '%[channels]' foo.png 

will print rgba or rgb if there is or is not an alpha channel, respectively.

There could be an alpha channel present with no data in it which wouldn't actually have any transparency, but that is a bit more complicated.


If you want to check that a picture is actually transparent... (not only an alpha channel which might be unused)

Use this command:

convert some_pic.png -verbose info:

(yes, there is a : at the end of the command)

It is quite verbose. Look for the channels list:

(...)
Channel depth:
  red: 16-bit
  green: 16-bit
  blue: 16-bit
Channel statistics:
(...)

In this example, there are three channels, one for each primary color. But non for alpha. So this image is not transparent.

But you can also get this kind of output:

(...)
Channel depth:
  red: 16-bit
  green: 16-bit
  blue: 16-bit
  alpha: 1-bit
Channel statistics:
(...)

Here, there is an alpha channel. However, this does no prove that the image is transparent. It just says that it might be. In the outputs of the command, look for the information about alpha channel:

(...)
  Alpha:
    min: 255 (1)
    max: 255 (1)
    mean: 255 (1)
    standard deviation: 0 (0)
    kurtosis: 0
    skewness: 0
(...)

In this example, the alpha says that the picture is opaque: min = max = 1 (1 = opaque, 0 = transparent). So even if the image has an alpha channel, the user sees an opaque picture.

You can also get this:

(...)
  Alpha:
    min: 95 (0.372549)
    max: 212 (0.831373)
    mean: 111.187 (0.436028)
    standard deviation: 19.5635 (0.0767196)
    kurtosis: 7.52139
    skewness: -2.80445
(...)

This time, min = 0.372549. This means that some pixels are partly transparent. mean is also low. It seems that a large part of the image uses transparency.

Depending of the type of check you want to achieve (full opacity, "almost opaque", etc.), you should check min, mean and maybe standard deviation if your request is a bit tricky.

Note: you might be tempted to check integer values for min, mean and others, as I did in the first place. After all, it is easier to deal with 95 than 0.372549. If you choose this route, beware the alpha channel depth. If it is 8 bits, then 255 is the maximum and means "opaque". If it is 16 bits, the maximum is now 65535 and 255 means "almost transparent". Better check the floats in parenthesis, which always range from 0 to 1.

If you suspect that a lot of pictures you will process have no alpha channel at all, it might be useful to first run:

identify -format '%[channels]' some_pic.png

If it dumps:

rgba

there is an alpha channel (the a in the output) and convert should be used to check min, etc.. But if there isn't, there is no need to run convert. Although I didn't benchmarked these two commands, identify should be much faster than convert.


identify -format %A some_pic.png

Will return True if image contains alpha channel.


If you want to be sure that alpha transparency is really used, the only solution I see it to iterate all pixels and get the color info to check if it's transparent or not. For large images this will be very slow, so, as an optimization you can first make a thumbnail of the image (let's say 20x20) and then check the thumbnail pixels. This was a good solution for me.


Here's a couple of bash functions to check if a png has transparency or not, using ImageMagick.

Fast check, which just checks for the presence of an alpha channel:

checkAlphaFast() {
    test $(identify -format %A "$1") == True
}

Slow check, verifies the pixels themselves (even if alpha channel is present):

checkAlphaSlow() {
    test $(identify -format '%[opaque]' "$1") == false
}

You should only consider using the fast check if you're doing this a whole lot, because it's pretty fast either way. Thanks to the other people who answered, from which I made these functions :)

As a bonus: I did not make any benchmarking, but this may be almost as fast as the fast mode and as accurate as the slow mode:

checkAlpha() {
    checkAlphaFast "$1" && checkAlphaSlow "$1"
}

Use these functions like this:

if checkAlpha "$myPNG"; then
    # is transparent
else
    # is opaque
fi

And this will give you the opaqueness of the image, where 0 is fully transparent and 1 is fully opaque:

checkOpaqueness() {
    if checkAlphaFast "$1"; then
        convert "$1" -verbose info: | grep -A3 Alpha: | tail +4 | head -n1 | sed -r 's/.*\(|\)//g'
    else
        echo 1
    fi
}

And this one outputs as a rounded percentage, because integers are so much more natural for bash:

checkPercentage() {
    printf %3.2f $(checkOpaqueness "$1") | tr -d . | sed -r 's/^0?0?//'
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜