Page 1 of 1

replace a solid colour with a gradient

Posted: 2012-07-04T12:11:12-07:00
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.

Re: replace a solid colour with a gradient

Posted: 2012-07-04T14:55:34-07:00
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

Re: replace a solid colour with a gradient

Posted: 2012-07-04T16:56:43-07:00
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

Re: replace a solid colour with a gradient

Posted: 2012-07-04T17:01:33-07:00
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.

Re: replace a solid colour with a gradient

Posted: 2012-07-04T18:16:06-07:00
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

Re: replace a solid colour with a gradient

Posted: 2012-07-05T16:15:06-07:00
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.

Re: replace a solid colour with a gradient

Posted: 2012-07-05T17:30:37-07:00
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) ;-)

Re: replace a solid colour with a gradient

Posted: 2012-07-06T08:20:30-07:00
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.

Re: replace a solid colour with a gradient

Posted: 2012-07-06T09:44:55-07:00
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.

Re: replace a solid colour with a gradient

Posted: 2012-07-07T04:10:45-07:00
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?

Re: replace a solid colour with a gradient

Posted: 2012-07-08T19:17:49-07:00
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.