replace a solid colour with a gradient

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
User avatar
Draoidh
Posts: 69
Joined: 2012-07-03T11:29:44-07:00
Authentication code: 13
Location: soon to be independent Scotland

replace a solid colour with a gradient

Post by Draoidh »

I created a shell script, which I stitches together two simple svg graphics consisting of black symbols on a transparent background. The script takes size, foreground and background colours as input parameters.

Code: Select all

convert pic1.svg pic2.svg \
    -fuzz 40% -fill $FG -opaque black \
    -background $BG -alpha remove -bordercolor $BG -border 5% \
    -append \
    -resize $SIZE \
    output.png
Optionally, I would like to apply a gradient fill either to the transparent background or the black foreground.

Any advice would be greatly appreciated.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: replace a solid colour with a gradient

Post by fmw42 »

For the former, take your result and flatten it onto a gradient image of the same size as your result. see http://www.imagemagick.org/Usage/canvas/#gradient.

For the latter, take the alpha channel as a (binary) mask and use it to composite your image with the same gradient image. In fact by changing the polarity of the gradient (via -negate) or the order of the gradient and your result, you can make the gradient be the foreground or the background.

see
http://www.imagemagick.org/Usage/compose/#compose
User avatar
Draoidh
Posts: 69
Joined: 2012-07-03T11:29:44-07:00
Authentication code: 13
Location: soon to be independent Scotland

Re: replace a solid colour with a gradient

Post by Draoidh »

Many thanks for your response. I had looked at those manual pages yesterday but I am struggling a bit to integrate this into my process.

Lets look at the gradient background first:

Ignoring the image append, border, foreground colouring, and resizing, I get manage to apply a gradient background by

Code: Select all

convert -size 1000x496  gradient:yellow-green pic1.svg  -composite output.png
That's straight-forward because I know the size of the image pic1.svg.

However, in my previous example, I apply a 5% border (not because I want a border but because I want to extend the background without scaling the image). And I don't know the overall size of the appended output image.

The best I can come up with is a two-step process leaving the transparent background in step one, acquiring the size and then applying the gradient:

Code: Select all

convert pic1.svg pic2.svg \
    -fuzz 40% -fill $FG -opaque black \
    -bordercolor none -border 5% \
    -append \
    -resize $SIZE \
    /tmp/output.png

DIMENSION=$(identify -format %wx%h /tmp/output.png)
convert -size $DIMENSION  gradient:yellow-green /tmp/output.png  -composite output.png
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: replace a solid colour with a gradient

Post by fmw42 »

That is probably all you can do. In IM 6, gradient cannot be told the size of the other image in the same command line. I believe that will be one of the changes that Anthony will be adding to IM 7.
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: replace a solid colour with a gradient

Post by anthony »

A example of flattening black text on white background is provided in IM Examples, Text Handling, Coloring a Gray-scale Text Image
http://www.imagemagick.org/Usage/text/#coloring_text
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
Draoidh
Posts: 69
Joined: 2012-07-03T11:29:44-07:00
Authentication code: 13
Location: soon to be independent Scotland

Re: replace a solid colour with a gradient

Post by Draoidh »

Anthony, thanks for the link. Colouring my black and white image is just what I want to do and this is much more elegant than my attempt.

My input images have a transparent background. So, I make that white first, then colour background and foreground with a gradient or solid colour:

Code: Select all

convert pic1.png pic2.png \
    -background white -alpha remove -bordercolor white -border 5% \
    -append \
    -resize $SIZE \
    /tmp/output.png

DIMENSION=$(identify -format %wx%h /tmp/output.png

convert /tmp/output.png \
     \( +clone -size $DIMENSION -tile $BG -draw "color 0,0 reset" \) \
     \( +clone -size $DIMENSION -tile $FG -draw "color 0,0 reset" \) \
    -reverse -composite output.png
I presume I need to do this operation in two steps to determine the size of the canvas/gradient image?


That works a treat. I only have a problem if the input colour parameter is "none" for transparency: I thought I could just add -transparent white or black as appropriate.
However, I end up with a white (or black) pixel line around the shape due to anti-aliasing. I tried to apply -fuzz 40% but that didn't help.
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: replace a solid colour with a gradient

Post by anthony »

draw reset and the -tile (fill with image rather than color) does NOT require a size. so you can remove the -size part.

It then means you can do it all in one command.

NOTE: even if you did need to set size, IMv7 will let you do it in one command (or script file) ;-)
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
Draoidh
Posts: 69
Joined: 2012-07-03T11:29:44-07:00
Authentication code: 13
Location: soon to be independent Scotland

Re: replace a solid colour with a gradient

Post by Draoidh »

anthony wrote:draw reset and the -tile (fill with image rather than color) does NOT require a size [...]
I am not quite sure I understand. If I need to create a gradient as per my colour commandline parameter, for example (BG=gradient:blue-green")

Code: Select all

\( +clone -tile $BG  -draw "color 0,0 reset" \) 
I get an error message if I don't specify the size.

How can I create a gradient on the fly without specifying the size? Just curious - it's not the end of th world if I need to split it into two commands.
anthony wrote:NOTE: even if you did need to set size, IMv7 will let you do it in one command (or script file) ;-)
I am on IM 6.7.7 (latest greatest on Debian wheezy).


I have sorted my transparency problem; so my script can currently take none, solid colour or gradient as input. Just one more option I'd like to cover: stripes.

I'd like to create a canvas of six equally sized stripes, again to be used in the composite operation above.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: replace a solid colour with a gradient

Post by fmw42 »

How can I create a gradient on the fly without specifying the size? Just curious - it's not the end of th world if I need to split it into two commands.
As far as I know, in IM 6, you cannot. I think it will be available in IM 7, but that is a long way off.
User avatar
Draoidh
Posts: 69
Joined: 2012-07-03T11:29:44-07:00
Authentication code: 13
Location: soon to be independent Scotland

Re: replace a solid colour with a gradient

Post by Draoidh »

This works like a charm! I have now got the following process:

1) create mask from 2 sitched images (pic1.svg + pic2.svg)
2) determine size of mask
3) using -composite, colour foreground + background as per the script's parameters (which can be none, solid or gradient colours)

Step 3) :

Code: Select all

convert /tmp/output.png \
     \( +clone -size $DIMENSION -tile $BG -draw "color 0,0 reset" \) \
     \( +clone -size $DIMENSION -tile $FG -draw "color 0,0 reset" \) \
    -reverse -compose Src -composite output.png
If I wanted to colourize the black symbols originating from pic2 in a different colour to those from pic1, how would I go about it?

Can I somehow do this with one convert command by specifying two cloned foreground images covering different areas of the stitched image?
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: replace a solid colour with a gradient

Post by anthony »

Draoidh wrote:
anthony wrote:draw reset and the -tile (fill with image rather than color) does NOT require a size [...]
I am not quite sure I understand. If I need to create a gradient as per my colour commandline parameter, for example (BG=gradient:blue-green")

Code: Select all

\( +clone -tile $BG  -draw "color 0,0 reset" \) 
I get an error message if I don't specify the size.
Oh yes of course the size is for gradient: not -draw or -tile.

Apologies for the ms-information.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
Post Reply