Apply gradient mask on image that already has transparency with ImageMagick?


I've got a PNG image with transparency:

original.png
Original

Now I want to use ImageMagick to apply a diagonal gradient to its alpha channel. I mean so that its opacity remains in the top left corner, and gradually fades out to completely transparent in the bottom right corner. Like this:

result.png
Result

So basically I want to generate a gradient, and use that as a mask for the image. But the image already has an alpha channel (transparency) of its own. Here's a visualisation of what I'm trying:

Operation

(original and result here displayed on checkerboard for visiblity, but I mean actual transparency)

I think I understand how to generate a diagonal gradient (the barycentric gradient command is very useful for this). But this creates a gradient in the color channels i.e. a colored or grayscale gradient. Whereas I want to apply the gradient on the alpha channel.

From the IM manual I understand the -compose CopyOpacity operator could be used for this. However this seems to copy the alpha from the mask on to my image. I need to "apply" this gradient color on my existing alpha channel, so basically I need my image's alpha channel to be multiplied by the grayscale color from the gradient image.

What would be the correct IM command line to perform the operation displayed above?


Answers:


Here is one way you could do it:

convert tree.png -write MPR:orig -alpha extract \
  \( +clone -colorspace gray -fx "1-j/h" \)     \
  -compose multiply -composite -write alpha.png \
  MPR:orig +swap -compose copyopacity -composite result.png

enter image description here

enter image description here

The -write alpha.png can be omitted - it just shows the alpha layer for debugging and illustration purposes.

The MPR is just a temporary copy of the original image that I hold in memory while I am dinking around with the alpha channel and which I bring back near the end. The gradient in the alpha channel is generated by the -fx and I made the colorspace gray first so it only has to run once, instead of three times.

If you knew the dimensions of the tree image up front, you could replace the part in parentheses with:

-size WxH gradient:black-white

but I don't know the dimensions up front and I don't want a second convert command to get them, so I basically clone the original image's alpha channel to get a canvas the right size and fill it in with -fx.