How do I make a new image with a transparent background?

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
bobp

How do I make a new image with a transparent background?

Post by bobp »

Hi,

I'm trying to use the MagickWand API to create an image that's composed of multiple layers. The first layer should have an opaque background but all layers after that should have transparent backgrounds.

This is more or less how the code looks:

Code: Select all

MagickWand *mw1 = NewMagickWand();
PixelWand *bgw1 = NewPixelWand();
MagickNewImage(mw1, 100, 100, bgw1); // this image should have an opaque background

//... paint on the image

// now create another layer
MagickWand mw2 = NewMagickWand();
PixelWand *bgw2 = NewPixelWand();
MagickNewImage(mw2, 100, 100, bgw2); // this image should have a transparent background

// ... paint on the second image

// create the final image
MagickAddImage(mw1, mw2);
MagickWand *merged = MagickMergeImageLayers(mw1, MergeLayer);
MagickWriteImage(merged, "foo.png");
The problem is that the image from the second wand completely hides the image from the first wand because of its opaque background. I'm trying to make it so only the strokes from the second image are visible, but not the background, which should be transparent. I tried setting the opacity value of bgw2 to 0 to no effect. I'm not sure what else I can do to. Any help is appreciated.

Thanks,
Bob
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: How do I make a new image with a transparent background?

Post by el_supremo »

Hi Bob:
You aren't setting the pixelwand's colour.
After this statement:
PixelWand *bgw2 = NewPixelWand();

add this:
PixelSetColor(bgw2,"none");

If the Merge doesn't work try MagickFlattenImages(mw1) instead.

Pete
bobp

Re: How do I make a new image with a transparent background?

Post by bobp »

Hi Pete,

Thanks for the reply! I tried following your suggestions but unfortunately it didn't work. Setting the color to "none" is equivalent to setting it to black. And using MagicFlattenImages() didn't make a difference. I also tried calling PixelSetOpacity(bgw2, 0) and it didn't help.

Any other ideas?

Thanks again,
Bob
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: How do I make a new image with a transparent background?

Post by el_supremo »

My bad, MagickFlattenImages is deprecated in favour of MagickMergeImageLayers.

This code creates two separate magickwands, writes text on them and then merges them into one image.
The first image has a red background and the second has a transparent background ("none" is the same as "transparent");

Code: Select all

	MagickWand *mw1 = NewMagickWand();
	PixelWand *bgw1 = NewPixelWand();
	DrawingWand *dw1 = NewDrawingWand();

	MagickWand *mw2 = NewMagickWand();
	PixelWand *bgw2 = NewPixelWand();
	DrawingWand *dw2 = NewDrawingWand();

	MagickWand *merged;

	MagickWandGenesis();
	PixelSetColor(bgw1,"red");
	MagickNewImage(mw1, 100, 100, bgw1); // this image should have an opaque background


//... paint on the image
	PixelSetColor(bgw1,"white");
	DrawSetFillColor(dw1,bgw1);
	DrawSetFontSize(dw1,12);
	DrawSetFont(dw1,"Times-New-Roman");
	MagickAnnotateImage(mw1,dw1,0,15,0.0,"Hello");
	
// now create another layer


	PixelSetColor(bgw2,"none");
	MagickNewImage(mw2, 100, 100, bgw2); // this image should have a transparent background

// ... paint on the second image
	PixelSetColor(bgw2,"red");
	DrawSetFillColor(dw2,bgw1);
	DrawSetFontSize(dw2,12);
	DrawSetFont(dw2,"Times-New-Roman");
	MagickAnnotateImage(mw2,dw2,0,50,0.0,"Magick");

// create the final image
	MagickAddImage(mw1, mw2);
	merged = MagickMergeImageLayers(mw1, MergeLayer);
	MagickWriteImage(merged, "foo.png");

	merged = DestroyMagickWand(merged);
	mw1 = DestroyMagickWand(mw1);
	mw2 = DestroyMagickWand(mw2);
	bgw1 = DestroyPixelWand(bgw1);
	bgw2 = DestroyPixelWand(bgw2);
	dw1 = DestroyDrawingWand(dw1);
	dw2 = DestroyDrawingWand(dw2);
Pete
bobp

Re: How do I make a new image with a transparent background?

Post by bobp »

Ok, I think I realize what I did wrong. I was calling 'MagickSetImageOpacity(mw2, 0.5)' before MagickAddImage(mw1, mw2). I thought this would only affect the opacity of the foreground strokes, but not the background. Apparently, calling MagickSetImageOpacity() sets the value for both the foreground and the background. So, if previously your background was transparent, calling MagickSetImageOpacity(mw2, 0.5) would make it semi transparent. This was overwriting the value I set previously for the background transparency.

This leads to the following question: is it possible to set the opacity only for the image's foreground, but not the background? I basically want to paint a bunch of strokes on the second image and then apply the alpha value to the whole image, not to each stroke individually. I also want the background to stay transparent. Is this possible?
bobp

Re: How do I make a new image with a transparent background?

Post by bobp »

By the way, thanks again for the reply! I really appreciate your help.
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: How do I make a new image with a transparent background?

Post by el_supremo »

is it possible to set the opacity only for the image's foreground, but not the background?
I'm sure it can be done but at the moment I can't think how to do it when you've already created the second image.

If you can change the colours involved in the painting, you can just specify the opacity when the second image is painted. In my code you can replace this:
// ... paint on the second image
PixelSetColor(bgw2,"red");
DrawSetFillColor(dw2,bgw1);

with this (which corrects a bug in the original):
// ... paint on the second image
PixelSetColor(bgw2,"rgba(0,0,100%,0.4)");
DrawSetFillColor(dw2,bgw2);

This will draw with blue but also with the alpha set to 0.4 so that you will have a partial transparency when it is merged with the first magickwand.

Pete
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: How do I make a new image with a transparent background?

Post by anthony »

Please note the differences between methods
FlattenLayers, MosaicLayers, and MergeLayers.

The difference is how they handle multiple image layers with offsets.

See IM examples, Layering Images, Flatten
http://www.imagemagick.org/Usage/#flatten
for details of their differences.

For a plain no-offset image the result should be the same though.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: How do I make a new image with a transparent background?

Post by el_supremo »

I haven't figured out how to merge the two wands using only MagickWand but by calling one MagickCore function the Dissolve (or Blend) composite operator can be used to combine the two wands.
First add this include:
#include <wand/magick-wand-private.h>

Then replace these three statements:
MagickAddImage(mw1, mw2);
merged = MagickMergeImageLayers(mw1, MergeLayer);
MagickWriteImage(merged, "foo.png");

with this:
// Fudge to set the geometry of the second magickwand
(void) CloneString(&mw2->images->geometry,"30x100+0+0");
// Dissolve the second image over the first
MagickCompositeImage(mw1,mw2,DissolveCompositeOp,0,0);
MagickWriteImage(mw1, "foo.png");

This combines mw2 (30%) and mw1 (100%) and leaves the result in mw1 so the "merged" MagickWand isn't needed any more.

@magick: Is there a way to do the composite command's -dissolve and -blend using only MagickWand? If not, can a mechanism be added?

Pete
Pete
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: How do I make a new image with a transparent background?

Post by anthony »

'Dissolve' and 'Blend' is really just multiplying the 'alpha' channel values by the percentages given, then, composing them using 'Over' or 'Plus' respectively. You should be able to do this using a channel restricted '-evaluate multiply' onto each of the images.

Note I am not a MagickWand user, But I know the Magickcore, and command line, so know what should be possible.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: How do I make a new image with a transparent background?

Post by el_supremo »

It works! Multiply the alpha channel of mw2 by 0.3 and then composite with Over.

MagickEvaluateImageChannel(mw2,AlphaChannel,MultiplyEvaluateOperator,0.3);

MagickCompositeImage(mw1,mw2, OverCompositeOp,0,0);

Thanks Anthony

Pete
Post Reply