How to fill a primitive with a gradient color?

Magick++ is an object-oriented C++ interface to ImageMagick. Use this forum to discuss, make suggestions about, or report bugs concerning Magick++.
Post Reply
Airon65
Posts: 75
Joined: 2017-02-26T02:19:38-07:00
Authentication code: 1151

How to fill a primitive with a gradient color?

Post by Airon65 »

Is there a way to fill a primitive with a gradient color?
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to fill a primitive with a gradient color?

Post by snibgo »

Not directly. It can be made transparent, and the image then composited over a gradient image.
snibgo's IM pages: im.snibgo.com
Airon65
Posts: 75
Joined: 2017-02-26T02:19:38-07:00
Authentication code: 1151

Re: How to fill a primitive with a gradient color?

Post by Airon65 »

snibgo wrote: 2017-04-20T13:01:54-07:00 Not directly. It can be made transparent, and the image then composited over a gradient image.
Such an interesting technique. You mean I can draw a primitive with a transparent fill and put that primitive over the gradient image? Do I need to have a white background outside the primitive? Then how to draw two or more primitives with different gradients on the same image?
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to fill a primitive with a gradient color?

Post by snibgo »

An example may clarify.

Code: Select all

%IM%convert ^
  ( ^
    -size 300x300 gradient:red-blue ^
    ( +clone -fill Black -colorize 100 ^
      -fill White -draw "polygon 50,50 250,50 200,200" ^
    ) ^
    -alpha off ^
    -compose CopyOpacity -composite ^
  ) ^
  ( ^
    -size 300x300 gradient:#f80-#08f ^
    ( +clone -fill Black -colorize 100 ^
      -fill White -draw "polygon 50,150 250,150 200,300" ^
    ) ^
    -alpha off ^
    -compose CopyOpacity -composite ^
  ) ^
  -compose Over -composite ^
  grad_shapes.png
Image

This makes a gradient, then a same-size image with a white polygon (a triangle) on black background, and this is applied as opacity to the gradient. The result is a gradient triangle of transparent background.

We repeat this with a second triangle.

Then we composite the second triangle over the first.

I expect there are other ways of doing this.
snibgo's IM pages: im.snibgo.com
Airon65
Posts: 75
Joined: 2017-02-26T02:19:38-07:00
Authentication code: 1151

Re: How to fill a primitive with a gradient color?

Post by Airon65 »

Wow that works really cool but how to convert it to Magick++ format? :)

The first problem is with the colorize function. I see two definitions of colorize function:

Code: Select all

// Colorize image with pen color, using specified percent alpha.
void colorize(const unsigned int alpha_,const Color &penColor_);

// Colorize image with pen color, using specified percent alpha
// for red, green, and blue quantums
void colorize(const unsigned int alphaRed_,const unsigned int alphaGreen_,
   const unsigned int alphaBlue_,const Color &penColor_);
how to properly do that step?

Code: Select all

-colorize 100
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to fill a primitive with a gradient color?

Post by snibgo »

"-fill Black -colorize 100" simply makes all the pixels opaque black. It's a slightly clumsy way of doing it at the command line. In the C APIs, there are cleaner ways. I don't use Magick++, but "erase" looks likely, after setting the background colour.
snibgo's IM pages: im.snibgo.com
Airon65
Posts: 75
Joined: 2017-02-26T02:19:38-07:00
Authentication code: 1151

Re: How to fill a primitive with a gradient color?

Post by Airon65 »

1. What do the "-alpha off" command do? Is it just remove the alpha channel from an image?

2. I try to convert it to C++ so I did:

Code: Select all

Magick::Image gradImg( Magick::Geometry( 500, 500 ), Magick::Color( "white" ) );
gradImg.read( "gradient:red-blue" );

Magick::Image testImg( Magick::Geometry( 500, 500 ), Magick::Color( "black" ) );

testImg.strokeWidth( 0 );
testImg.fillColor( Magick::Color( QuantumRange, QuantumRange, QuantumRange, QuantumRange ) ); // white color!

float centerX = 250, centerY = 250;
float xr = 150, yr = 150;
testImg.draw( Magick::DrawableEllipse( centerX, centerY, xr, yr, 0, 360 ) );

gradImg.composite( testImg, gradImg.columns() / 2 - testImg.columns() / 2, gradImg.rows() / 2 - testImg.rows() / 2, Magick::ColorizeCompositeOp );

gradImg.write( "images/grad.png" );
testImg.write( "images/test2.png" );
it looks like ColorizeCompositeOp is not the right operator for achieving this goal :) I don't know what's the CopyOpacity operator? In the include.h I see only these compose operators:

Code: Select all

// Composition operations
  using MagickCore::CompositeOperator;
  using MagickCore::AlphaCompositeOp;
  using MagickCore::AtopCompositeOp;
  using MagickCore::BlendCompositeOp;
  using MagickCore::BlurCompositeOp;
  using MagickCore::BumpmapCompositeOp;
  using MagickCore::ChangeMaskCompositeOp;
  using MagickCore::ClearCompositeOp;
  using MagickCore::ColorBurnCompositeOp;
  using MagickCore::ColorDodgeCompositeOp;
  using MagickCore::ColorizeCompositeOp;
  using MagickCore::CopyBlackCompositeOp;
  using MagickCore::CopyBlueCompositeOp;
  using MagickCore::CopyCompositeOp;
  using MagickCore::CopyCyanCompositeOp;
  using MagickCore::CopyGreenCompositeOp;
  using MagickCore::CopyMagentaCompositeOp;
  using MagickCore::CopyAlphaCompositeOp;
  using MagickCore::CopyRedCompositeOp;
  using MagickCore::CopyYellowCompositeOp;
  using MagickCore::DarkenCompositeOp;
  using MagickCore::DarkenIntensityCompositeOp;
  using MagickCore::DifferenceCompositeOp;
  using MagickCore::DisplaceCompositeOp;
  using MagickCore::DissolveCompositeOp;
  using MagickCore::DistortCompositeOp;
  using MagickCore::DivideDstCompositeOp;
  using MagickCore::DivideSrcCompositeOp;
  using MagickCore::DstAtopCompositeOp;
  using MagickCore::DstCompositeOp;
  using MagickCore::DstInCompositeOp;
  using MagickCore::DstOutCompositeOp;
  using MagickCore::DstOverCompositeOp;
  using MagickCore::ExclusionCompositeOp;
  using MagickCore::HardLightCompositeOp;
  using MagickCore::HardMixCompositeOp;
  using MagickCore::HueCompositeOp;
  using MagickCore::InCompositeOp;
  using MagickCore::IntensityCompositeOp;
  using MagickCore::LightenCompositeOp;
  using MagickCore::LightenIntensityCompositeOp;
  using MagickCore::LinearBurnCompositeOp;
  using MagickCore::LinearDodgeCompositeOp;
  using MagickCore::LinearLightCompositeOp;
  using MagickCore::LuminizeCompositeOp;
  using MagickCore::MathematicsCompositeOp;
  using MagickCore::MinusDstCompositeOp;
  using MagickCore::MinusSrcCompositeOp;
  using MagickCore::ModulateCompositeOp;
  using MagickCore::ModulusAddCompositeOp;
  using MagickCore::ModulusSubtractCompositeOp;
  using MagickCore::MultiplyCompositeOp;
  using MagickCore::NoCompositeOp;
  using MagickCore::OutCompositeOp;
  using MagickCore::OverCompositeOp;
  using MagickCore::OverlayCompositeOp;
  using MagickCore::PegtopLightCompositeOp;
  using MagickCore::PinLightCompositeOp;
  using MagickCore::PlusCompositeOp;
  using MagickCore::ReplaceCompositeOp;
  using MagickCore::SaturateCompositeOp;
  using MagickCore::ScreenCompositeOp;
  using MagickCore::SoftLightCompositeOp;
  using MagickCore::SrcAtopCompositeOp;
  using MagickCore::SrcCompositeOp;
  using MagickCore::SrcInCompositeOp;
  using MagickCore::SrcOutCompositeOp;
  using MagickCore::SrcOverCompositeOp;
  using MagickCore::ThresholdCompositeOp;
  using MagickCore::UndefinedCompositeOp;
  using MagickCore::VividLightCompositeOp;
  using MagickCore::XorCompositeOp;
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to fill a primitive with a gradient color?

Post by snibgo »

For translating between command-line and C (or C++), a very useful source is MagickCore\option.c. This file translates command-line options to the internals. Search that file for "CopyOpacity".
snibgo's IM pages: im.snibgo.com
Airon65
Posts: 75
Joined: 2017-02-26T02:19:38-07:00
Authentication code: 1151

Re: How to fill a primitive with a gradient color?

Post by Airon65 »

snibgo wrote: 2017-04-21T15:42:22-07:00 For translating between command-line and C (or C++), a very useful source is MagickCore\option.c. This file translates command-line options to the internals. Search that file for "CopyOpacity".
Thanks, it's very useful file! :) Didn't know about it. Now I know that ColorizeCompositeOp is the "Magick::CopyAlphaCompositeOp". Now I don't know how to do: "-alpha off" :) Why do you do this step?
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to fill a primitive with a gradient color?

Post by snibgo »

"CopyOpacity" normally copies the opacity from Src to Dst. If Src is fully opaque, this would make the result white. But if alpha is off, it doesn't copy the opacity; instead, it copies the intensity of Src to the opacity of Dst.

I think "-alpha off" is "MagickSetImageAlphaChannel (wand, OffAlphaChannel)". In v7, traits should probably be used.
snibgo's IM pages: im.snibgo.com
Airon65
Posts: 75
Joined: 2017-02-26T02:19:38-07:00
Authentication code: 1151

Re: How to fill a primitive with a gradient color?

Post by Airon65 »

Oh finally I've got it. You mean simply masks technique. Now I understand what did you mean.
Here is the way for doing this:

Code: Select all

Magick::Image gradImg( Magick::Geometry( 500, 500 ), Magick::Color( "white" ) );
gradImg.read( "gradient:red-blue" );

Magick::Image maskImg( Magick::Geometry( 500, 500 ), Magick::Color( "black" ) );
maskImg.strokeWidth( 0 );
maskImg.fillColor( Magick::Color( "white" ) ); // white color!
maskImg.draw( Magick::DrawableEllipse( 250, 250, 150, 150, 0, 360 ) );

maskImg.alphaChannel( MagickCore::DeactivateAlphaChannel );
gradImg.alphaChannel( MagickCore::DeactivateAlphaChannel );
maskImg.negate();
gradImg.composite( maskImg, 0, 0, Magick::BlendCompositeOp ); // applying a mask

gradImg.write( "images/grad.png" );
maskImg.write( "images/mask.png" );
Looks like all work fine :) Thank you!
Post Reply