Using GraphicsMagick or ImageMagick, how do I replace transparency with a fill colour?

5

1

Using GraphicsMagick, it's fairly easy to replace one colour with transparency...

gm convert -transparent magenta src.png dst.png

Unfortunately, I can't figure out a simple way to do the exact opposite. If I have an image file with alpha-channel transparency, how do I compose it on a constant-colour background then discard the now redundant alpha channel? The background colour should affect pixels that were partially transparent as well as fully transparent.

I've spotted the +matte option, but it literally discards the alpha layer - normally leaving junk colour pixels where the transparency was, rather than e.g. using the -background option to specify a background colour to use.

The only way I've managed this so far is using multiple calls - one to generate a solid-colour rectangle image file, another to composite the original image with the solid-colour image, and a third to discard the alpha channel. This seems crazy - surely it should be possible with a single fairly simple call?

I currently use GraphicsMagick, but there's no commitment - I'll switch to ImageMagick if it makes things easier.

EDIT

When I say "The background colour should affect pixels that were partially transparent as well as fully transparent.", I mean the result should be visibly what I would normally expect from blitting a transparent sprite onto a solid colour background. The partially transparent pixels should be blended.

This means that if I then reversed the process - turning the background colour key into transparency - I would expect to see a halo around the original image, where the background colour is blended into the pixels so the colour key doesn't precisely match and therefore isn't converted back to transparency. It's not what most people would want for that reason. It's what I want, though, as I won't be converting the background back to transparency - I'll still have the original image with the original transparency if I need it.

Steve314

Posted 2010-11-21T05:59:22.343

Reputation: 1 569

Answers

7

Using GraphicsMagick, -background color -extent 0x0 should be able to replace the first two steps in your process (for ImageMagick, it'd be -mosaic instead of -extent). I'm not sure about the third step, but it sounds like you're just running +matte on the image from the first two steps, so the final call would look something like this:

gm convert -background color -extent 0x0 +matte src.png dst.png

or for ImageMagick,

convert src.png -background color -mosaic +matte dst.png

kate

Posted 2010-11-21T05:59:22.343

Reputation: 357

Hmmm - a background image constructed as a mosaic of zero images on a solid colour background. Clever. Not tested yet, but I think you'll be getting the accept. – Steve314 – 2010-11-23T05:26:06.180

Sorry - no accept because it didn't work. gm complains that it needs an image list for -mosaic. It only needs one image to work around that, but even by e.g. having the same source image twice, you get a result but it doesn't draw a background of the colour specified under the transparency. I get roughly the same as a simple gm convert using only the +matte option, basically, which also doesn't use -background even if you specify it - you just get the junk pixels that were previously hidden by the transparency. – Steve314 – 2010-11-23T20:15:04.690

Oops, sorry. I've edited my answer with a working solution. I made the mistake of assuming GraphicsMagick and ImageMagick solutions were more interchangeable than they are. – kate – 2010-11-24T03:55:16.830

Success! - or apparent success, anyway. I couldn't find an image with real transparency to test just at the moment, so made one using -transparent, but that doesn't give any semi-transparent pixels. Still, it seems OK for the moment - thanks and accepted. – Steve314 – 2010-11-24T22:44:21.630

I found that the following command works for both GraphicsMagick and ImageMagick (with or without 'gm'):

gm convert -geometry 50x50! -background white -extent 0x0 +matte in.png out.jpg – PowerKiKi – 2012-01-17T05:49:16.160

1

What you're searching for almost fits the description of -opaque, but with a twist. Assuming a constant-color background, the command below might work for you (I only have ImageMagick to test on).

gm convert -channel matte -threshold 0% -channel RGB -fill [your background color] -opaque transparent -channel matte -threshold 100% src.png dst.png

-channel matte -threshold 0% sets pixels with any transparency to fully transparent, -channel RGB -fill [your background color] -opaque transparent replaces fully transparent pixels with the given fill color, and -channel matte -threshold 100% removes transparency from all pixels.

Georgette Samson

Posted 2010-11-21T05:59:22.343

Reputation: 11

Interesting and +1, but I wasn't clear about what I want - see the edit to the question. The "-opaque transparent" replaces fully transparent pixels only, as you say, so even when I drop the original threshold I won't get blending of partially transparent pixels into the background colour. The dream solution (not valid) would be something like gm convert -bgfill magenta +matte src.png dst.png. -draw Rectangle would be ok, if only there was a -compose Under to complement the -compose Over. – Steve314 – 2010-11-21T18:32:59.787

1

It looks to me like you just want to composite the transparent (or partially) image over the background, with alpha blending. This page suggests that the code:

composite smile.gif rose: rose-over.png

is the basis. In the examples given, it blends one image over another.

Now, if you want to blend an image with transparency over a solid background color, you can either have a second image with the background (if it's static), or create a basic single-color/flood-filled image of the same dimensions at runtime. How you'd do that depends on if you're using the shell or some kind of script (Perl, PHP, etc).

ssube

Posted 2010-11-21T05:59:22.343

Reputation: 900

This is what I'm doing now, but it seems overcomplicated. As I said, it takes three calls - one to create the solid-colour background bitmap, one to compose the two bitmaps, and one to discard the alpha channel from the result. I can work around that if I have to, but when a simple job seems difficult, it often means you're missing something - and I want to know what it is that I'm missing. – Steve314 – 2010-11-23T05:21:39.243

I don't know if I've ever seen what you're trying to do done any other way. You might be able to find some method, but alpha blending is how it's done in hardware, so there's something to the method. I'd bet if you do find another method, it's wrapping something like this into a single call. – ssube – 2010-11-23T05:43:51.713

I missed something when I read this before - that rose: syntax. This may be exactly what I was looking for in a single simple call after all. – Steve314 – 2010-11-23T20:17:53.580

Ah - rose: seems to refer to a built-in image of a rose, not a solid rose colour. A shame - being able to specify a solid colour as if it were an image would be a very simple solution. – Steve314 – 2010-11-23T20:39:42.820