Page 1 of 1

Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T01:05:17-07:00
by elmimmo
The color that -trim cuts out seems to be of a higher color depth than the output's, and therefore leaves in colors that in the output will be the same as the corner pixels onced rounded down to the output's color depth. How do I reduce the bit depth of ImageMagick's buffer so that -trim works based on the bit depth of the output? -depth seems to alter only the bit depth of the output, but not ImageMagick's internal buffer.

I am trying to apply a drop shadow to non-square images on a transparent canvas (say, a solid circle on a transparent canvas), and then trimming out all transparent pixels before outputting. But -trim leaves in some pixels around the drop shadow that in the output are 100% transparent, seemingly due to them not being completely so while still inside ImageMagick. I know I could use -fuzz to get approximate results, but I need -trim to be 100% accurate, not fuzzy.

Code: Select all

convert "input.png" \
        \( "input.png" -alpha extract \) \
        -matte -bordercolor none -border 100x100 \
        -alpha off -compose copy_opacity -composite -compose over \
        \( -clone 0 -background black -shadow 25x4+3+4 \) \
        +swap \
        -background none -layers merge \
        -trim \
        "output.png"
That command does this:
  1. expands the canvas to give the drop shadow a bit of room
  2. creates a drop shadow from the alpha
  3. places the drop shadow under the original image
  4. and finally trims out transparent pixels.
That, though leaves a margin of six 100% transparent pixels or so around the image.

Getting pixel enumeration, by appending txt: >out.txt to the command above, reveals the disparity between ImageMagick's image buffer and the output:

Code: Select all

# ImageMagick pixel enumeration: 522,322,65535,srgba
0,0: (0,0,0,0)  #00000000  none
[…]
487,0: (0,0,0,1)  #00000000  srgba(0,0,0,1.5259e-05)
So ImageMagick's image buffer is 16 bit per channel, whereas I am exporting to 8 bit per channel. The pixel 487,0 is not 100% transparent in 16 bit but it becomes so in 8 bit. How do I get -trim to look at the image in 8 bit.

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T05:12:16-07:00
by snibgo
What version IM are you using? What Q-number, with or without HDRI?
elmimmo wrote:-depth seems to alter only the bit depth of the output, but not ImageMagick's internal buffer.
Correct. The internal buffer has the depth defined at compile-time: Q8, 16, 32 or 64.
elmimmo wrote:How do I reduce the bit depth of ImageMagick's buffer so that -trim works based on the bit depth of the output?
You can use eg Q8 instead of Q16. For a similar effect, use "-colors 256" on the extracted alpha channel.

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T07:45:26-07:00
by elmimmo
snibgo wrote:What version IM are you using? What Q-number, with or without HDRI?

Code: Select all

$ convert --version
Version: ImageMagick 6.9.5-5 Q16 x86_64 2016-08-07 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2016 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC Modules 
Delegates (built-in): bzlib freetype jng jpeg ltdl lzma png tiff xml zlib
snibgo wrote:The internal buffer has the depth defined at compile-time: Q8, 16, 32 or 64.

You can use eg Q8 instead of Q16. For a similar effect, use "-colors 256" on the extracted alpha channel.
My question was more about how to downgrade the bit-depth of the image stored in the buffer (rather than the buffer itself) at some point within the command chain (specifically once the drop shadow has been drawn and placed below the original image, no before) so that -trim works predictably as one would assume by looking at the untrimmed output.

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T08:16:24-07:00
by snibgo
elmimmo wrote:So ImageMagick's image buffer is 16 bit per channel, whereas I am exporting to 8 bit per channel.
Your command doesn't explicitly define the output as 8 bits/channel. I suppose your input is 8 b/c, so IM reduces the output. Personally, I would work in the opposite direction, using "+depth" before the output, so it isn't reduced.

But you are trimming based on the alpha channel, and you want that to be 8 bits. As I said, the obvious way to do that is to extract the alpha, "-colors 256", and CopyOpacity it back to the image.

IM doesn't have a simple command to reduce the depth of pixels, to "knock out" trailing bits. But the way to do this is to divide, then multiply. If we divide by 256 then multiply by 256, this will zero the bottom 8 bits. We don't normally want exactly that. Instead, we want bit reduction and bit replication, so we use 257 instead of 256.

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T08:46:21-07:00
by elmimmo
snibgo wrote:the obvious way to do that is to extract the alpha, "-colors 256", and CopyOpacity it back to the image.
Could you please rewrite my command above to include your suggested modification? I tried, but am not too sure would it should go (the alpha must be reduced to 8 bit after the generation of the drop shadow) nor whether I need to add additional commands. I did not get it to behave differently than how it is working now.

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T09:02:05-07:00
by snibgo
You haven't supplied input.png so I can't test this:

Code: Select all

convert "input.png" \
\( "input.png" -alpha extract \) \
-matte -bordercolor none -border 100x100 \
-alpha off -compose copy_opacity -composite -compose over \
\( -clone 0 -background black -shadow 25x4+3+4 \) \
+swap \
-background none -layers merge \
\( -alpha extract -colors 256 -alpha off -compose copy_opacity -composite -compose over \) \
-trim \
"output.png"
If that doesn't work, please supply a link to input.png.

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T10:00:40-07:00
by elmimmo
snibgo wrote:

Code: Select all

convert "input.png" \
\( "input.png" -alpha extract \) \
-matte -bordercolor none -border 100x100 \
-alpha off -compose copy_opacity -composite -compose over \
\( -clone 0 -background black -shadow 25x4+3+4 \) \
+swap \
-background none -layers merge \
\( -alpha extract -colors 256 -alpha off -compose copy_opacity -composite -compose over \) \
-trim \
"output.png"
If that doesn't work, please supply a link to input.png.
It does not work:

Code: Select all

convert: no images defined `output.png' @ error/convert.c/ConvertImageCommand/3257.
Here you have a sample input.png.

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T10:45:16-07:00
by snibgo
Oops, sorry, I forgot to "clone", and put the end-parens in the wrong place. Try:

Code: Select all

convert "input.png" \
\( "input.png" -alpha extract \) \
-matte -bordercolor none -border 100x100 \
-alpha off -compose copy_opacity -composite -compose over \
\( -clone 0 -background black -shadow 25x4+3+4 \) \
+swap \
-background none -layers merge \
\( +clone -alpha extract -colors 256 \) -alpha off -compose copy_opacity -composite -compose over \
-trim \
"output.png"
Your link doesn't work for me (I get a blank page).

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T10:47:52-07:00
by fmw42
The link works for me. I get a black ellipse on transparent background. But the base image is black and the alpha channel has all the detail.

Re: Transparent bg + drop shadow + trim does not trim out transparent pixels

Posted: 2016-12-08T11:41:30-07:00
by elmimmo
Works. Thanks!