List Info

Thread: make a Gradient from 2 points




make a Gradient from 2 points
user name
2006-01-19 17:42:19
> As far as I know, there is not yet a function in
ImageMagick
> to create a gradient from 2 points

The very next item on our development list is implementing
gradients
as required by the SVG specification.  We would still be
interested in
seeing your code.
_______________________________________________
Magick-developers mailing list
Magick-developersimagemagick.org
http://studio.imagemagick.org/mailman/listinfo/m
agick-developers
make a Gradient from 2 points
user name
2006-01-19 19:28:08
Hi Stentz!

stentzimagemagick.org a écrit :
> > As far as I know, there is not yet a function in
ImageMagick
> > to create a gradient from 2 points
>
> The very next item on our development list is
implementing gradients
> as required by the SVG specification.

I've just had a quick look at the SVG specifications for
gradients.
The function I've written is very close to the SVG
'linearGradient'.
The parameters x1,y1 x2,y2 for linearGradients are the
points A and B.

To make my function fit the SVG specs of linearGradients,
the colors
behind the points A and B should be the same than the colors
at A and B,
and 2 additionnal parameters will have to be added:
the offset at A and the offset at B (along the line AB).

Currently my function is equivalent to if the offset are 0%
and 100%
as in:

<linearGradient id="MyGradient">
   <stop offset="0%"  
stop-color="#F00"/>  <!-- color at A -->
   <stop offset="100%"
stop-color="#00F"/>  <!-- color at B -->
</linearGradient>

It's easy to solve if the offset are not 0% and 100%:
for exemple with 5% and 80%, (which are 0.05 and 0.80)
just multiply the vector (AB) by 0.05 to get the point C,
and multiply the vector (AB) by 0.80 to get the point D.
Then just call my function with C and D (rather than A and
B).


________________


> We would still be interested in seeing your code.


As I said the code is written in OCaml for the moment,
if you are interested to see it though, it is here:

http://www.linux-nantes.org
/~fmonnier/OCaml/ImageMagick/gradient_from_2points.ml.html

OCaml does inline functions, so making a lot of small
sub-functions 
doesn't reduce the efficiency. It is not the same with C, 
making a lot of sub-functions calls would reduce the
efficiency, 
so to convert it to C, all the calculations should be put
together 
in the minimum of functions possible.

In addition some calculations could be
"factorised" (not sure it is 
the good word), for exemple (len ad) is used 3 times in this
OCaml 
piece of code. There is also the product of the 'ab'
coordinates in 
the calculation of the scalar product which never change, so
it should 
be calculated only once at the beginning, rather than at
each pixel 
of the image.

("factorising" this in OCaml would make no sens
since it inlines 
everything, so writing it this way is far more readable and 
understandable.)
________________

Now, just some explanations about how does the code works.

The 'scal' function returns the scalar product of 2 vectors.

The 'len' function returns the length of a vector.
(If you give the coordinate of a point rather than a vector,
it returns the distance from that point to the origine O)

'get_cos_alpha ab ad' returns the cosinus of the angle
between
the 2 vectors (ab) and (ad).
(There's no need to get the angle itself.)

'dist' returns the distance between 2 points.
'sub' substrates 2 vectors.

'get_y_of_A_B a b d' is the main function where all the
tricks happen.
'a', 'b' and 'd' are 3 points. (let's explain with upper
case)
A and B are the 2 points which define the 'linearGradient'.
D is a point of the image for which the function returns the
color, 
so in the function 'gradient_from_2points', we just have to
make 
an iter on every points of the image to set the color of the
pixels.

In the iteration on every x,y of the image _y1D is the
coordinate 
of D in the 1D (1 dimention) AB <switch
lang="fr">repère</switch>.
(I don't know if 'reference mark' is a good traduction for
repère.)
So the ratio of this coordinate by the length of [AB] gives
the 
percentage to mix the 2 colors.
if the percentage is smaller than 0% give a color for behind
A, 
and if the percentage is greater than 100% (=1.0) give a
color 
for behind B.

Perhaps there could be another better implementation,
nevertheless it works this way 


That's all for GradientMagick! 
________________


To implement the radial gradient of SVG, I think it should
be quite 
easy. Given A for the center and B for a point on the
circle.
The radius R is the length of [AB]. Then for every point P
of the 
image just calculate the distance PA between P and A.
Then the percentage to mix the 2 colors is the ratio of R
and PA.


To implement the SVG: spreadMethod = "pad | reflect |
repeat"
we only have to change the cases 'percent > 1.0' and
'percent < 0.0'.
I think pad corresponds to the code i've made, for repeat
we should use a modulo like this:
    percent = percent modulo 1.0;
And for `repeat' perhaps `percent = 1.0 - percent' in the 
odd or even cases will do the job.

________________


So Stentz,
do you wish me to try to work on this for the MagickCore?


-- 
Florent Monnier
Best Regards

_______________________________________________
Magick-developers mailing list
Magick-developersimagemagick.org
http://studio.imagemagick.org/mailman/listinfo/m
agick-developers
[1-2]

about | contact  Other archives ( Real Estate discussion Medical topics )