Page 1 of 1

Weighted Multi-Color Gradients to Mimic CSS Gradients

Posted: 2011-11-11T13:12:16-07:00
by nicknotfound
I'd like to create weighted, multi-color gradients to match those that can be created using CSS3.

I know it's possible to create a simple two-color gradient as described in the docs at http://www.imagemagick.org/Usage/canvas/#gradient. What I'm not sure about is how to make more than two colors where each color can be placed at a specific percentage (for weighting).

I know I can use ImageMagick to create a two-color gradient, with one color at the 0,0 and the other color at the [100% width],0. For example, this command:

Code: Select all

convert -size 100x500 gradient:'#f00-#00f' gradient-2.png
will produce the same gradient as this CSS:

Code: Select all

#gradient {
  width: 100px;
  height: 500px;
  background-image: -webkit-linear-gradient(top, #f00, #00f);
}
Specifically, I'd like to use ImageMagick to create a gradient image matching the gradient a browser would render for the following CSS:

Code: Select all

#gradient {
  width: 100px;
  height: 500px;
  background-image: -webkit-linear-gradient(top, #f00 10%, #ff0 20%, #00f 80%);
}
This CSS gradient differs from the top CSS gradient in two ways:
1. This gradient has three colors instead of two, and
2. The color stops in this gradient are not evenly spaced.

An example of the above can be seen here in Chrome/Safari or Firefox: http://jsfiddle.net/aMhL8/

Ideally, I'd be able to use an arbitrary number of colors (three was just a simple example). Does anyone know how to accomplish this with ImageMagick? Any help would be greatly appreciated.

Re: Weighted Multi-Color Gradients to Mimic CSS Gradients

Posted: 2011-11-11T13:21:37-07:00
by fmw42
I do not see the resulting gradient image/graphic on your link. Can you provide a link to the simple graphic image that it creates?

See the rainbow gradient at http://www.imagemagick.org/Usage/canvas ... ent_resize which should provide a means to create gradients with any number of colors. Changing the spacing can be done by replicating a color multiple times.

I have a script, tricolorize, at the link below that uses that technique to make 3 color gradients and then adjust to positioning.

Re: Weighted Multi-Color Gradients to Mimic CSS Gradients

Posted: 2011-11-14T10:26:25-07:00
by nicknotfound
Hi Fred,

Thanks for the quick response! Here's a screenshot of the browser-generated image at my original link (which only works in Chrome, Safari, and Firefox) :

Image

Also, I tried looking at your tricolorize link, but it appears there's a missing "<" in your closing </title> tag, so all I see is a blank page.

Let me know if there's anything else I can clarify about what I'm trying to accomplish.

Re: Weighted Multi-Color Gradients to Mimic CSS Gradients

Posted: 2011-11-14T11:48:27-07:00
by fmw42
Is this image supposed to match #f00 10%, #ff0 20%, #00f 80%?

If so it adds up to 110%.

I tried the following by proportions. It is similar but not close enough. I will have to think about how to handle the 110 percent issue differently.

Try this and see what I mean. (1 pixel #f00, 2 pixels #ff0 and 8 pixels #00f)


convert \( xc:"#f00" \) \( xc:"#ff0" -duplicate 1 \) \( xc:"#00f" -duplicate 7 \) \
-append -filter Cubic -resize 100x500! rainbow1.png

I fixed the missing < on </title>, but I will have to check all my scripts to be sure there are no others. Thanks for pointing that out.

Re: Weighted Multi-Color Gradients to Mimic CSS Gradients

Posted: 2011-11-14T12:42:56-07:00
by nicknotfound
Hi Fred,

It looks like this is something I'll be able to work with. I'll play around with it a bit and will report back here when I have a workable solution.

To answer your question, the percentages are actually the positions in the image at which the color stops exist. So, the percentages for my example read: red @ 10% of the total image height, yellow @ 20%, and blue @ 80%.

Because the first color stop is at the 10% mark, everything before it should be a solid color (#f00). Likewise, because the last color stop is at the 80% mark, everything after it should be a solid color (#00f). This matches the behavior of gradients in graphics programs like Photoshop or Fireworks.

Here's an attempt to show visually the way these gradients work using the red-yellow-blue example from above, not quite to scale:

Code: Select all

+----+  0% (#f00, because that's the first color stop below)
|    |
| -- | <- 10% - #f00
|    |
| -- | <- 20% - #ff0
|    |
|    |
|    |
|    |
| -- | <- 80% - #00f
|    |
|    |
+----+  100% (#00f, because that's the last color stop above)
So, using your method, I should be able to figure out what solid-color pixels to draw and then stretch to the desired height.

Re: Weighted Multi-Color Gradients to Mimic CSS Gradients

Posted: 2011-11-14T14:30:20-07:00
by fmw42
The only way I can see to do this is to compute sections of two-color gradients at the lengths where you want the solid colors to be located and then append them together. See +layers-colors. Make each section as long in pixels as the percentage you want between solid colors. Then -append to put together. Use constant colors at the ends in your appends.

This seems to do what you want as above.


convert \
\( -size 1x50 xc:"#f00" \) \
\( -size 1x50 gradient:"#f00-#ff0" \) \
\( -size 1x300 gradient:"#ff0-#00f" \) \
\( -size 1x100 xc:"#00f" \) \
-append -scale 100x500! \
rainbow1.png

Re: Weighted Multi-Color Gradients to Mimic CSS Gradients

Posted: 2011-11-14T19:29:15-07:00
by anthony
This is very similar to color stops in SVG images. Unfortunatally while the Draw command can generate circular and vertical gradients (which is what gradient: and radial-gradient: uses internally) color stops have not been implemented.
See my rough notes in Draw, Push/Pop Special Objects
http://www.imagemagick.org/Usage/draw/#push_objects

Also see Florent Monnier's development site for MVG gradients...
http://www.linux-nantes.org/~fmonnier/OCaml/MVG/
This has examples of gradients in both SVG and MVG forms
but the MVG form does not work with the current ImageMagick.

I last attempted to generate more complex gradient in draw during a discussion on drawing shaded cylinders. But ended up falling back to generating simpler gradient: images :-(

Re: Weighted Multi-Color Gradients to Mimic CSS Gradients

Posted: 2011-11-14T21:38:33-07:00
by anthony
Another method may be to create a sparse color image.

Code: Select all

convert -size 1x500 xc:  -sparse-color Shepards \
       '0,50 #f00  0,100 #ff0  0,400 #00f'   -scale 100x500!  rainbow.png
however As I mention in IM examples
http://www.imagemagick.org/Usage/canvas ... ds_leakage
The shepard that are distant become uniformly 'average' using all the given colors. Basically the colors in a shepards gradients 'leak', or jump beyond other colors. As it is a totally global calculation with no understanding of local boundaries.

The solution to that is to generate a 'diffusion' gradient, which works exactly like shepards, but does not 'leak'. IM currently can not generate such a gradient, though I have the technique figured out, just not implemented.