Checking out the new GradientImage in 6.4.4-2

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Checking out the new GradientImage in 6.4.4-2

Post by fmw42 »

anthony wrote:Hold on Fred. As Cristy said before, it would be hard to figure out an option set that would continue to allow easy use (like gradient: does currently) with all the numerous options that users may like to have available.

I'm not saying that it isn't possible, just a lot more work. If you can come up with some structure for the original 'gradient:' with 'styles', 'color-stops' and 'repeat' methods. that still allows the current 'easy to use' defination, especially if it better corresponds with SVG, then maybe, someone might take time to implement it.

At the moment Cristy is just trying to get SVG and MVG gradients working, which is a more important first step. The radial-gradient: feature was just something he mentioned above and I took a look at. I was suprised it had even been added.

I just felt changing the outer point from a corner to some fixed edge (top would be most logical) would at least allow users to better define the radius, and make the whole gradient visible. And it was better for such a change to be made as early as posible.

And any other 'options' would have entailed a lot more work, and make it different to the other two gradient image generators gradient: and plasma: which is basically a fractal color distortion on top of the normal gradient: base image.

I too like to see a lot more options. But I prefer to get the SVG gradient working for most. However if Cristy wants I'll jump into the code radial-gradient code and change it as I suggested. Or if you can come up with a good 'options' method. I'll gladly try to implement it to. But most importantly it must fall back to easy to use, just as gradient: has been for the last decade.

Think about it and wour out some scheme to implement it using a simple but expandable string.

Remember currently you can specify a gradient as
''
'{one_color}'
'{one_color}-{two_color}'
See IM examples for an indication of how these three styles currently work.

Anthony and Magick,

I am in no hurry and can be patient with all the development.

I do understand and was just surprised when I saw that radial-gradient: was implemented, since I suggested to Magick that he not spend his valuable time implementing a separate option. It was not terribly important, although it could prove valuable in the future for FFT filters.

I just wanted to point out some other options to think about. I will certainly give some more thought to it and offer any suggestions that I come up with. But again it is not that urgent.

As for the current implementation, I would say that stopping at the sides was slightly more preferable to the corner for a square image. However, as a default, as it might be used for a lookup transformation, it would be preferable to have it go from black (0) at the center to white (quantumrange) at the sides. However, this is just a -negate from what you currently show (unless you implement it as radial-gradient:innercolor-outercolor so that it could be radial-gradient:black-white, for example). Seems like your examples show that you already have the one or two color forms in place, so this is likely a non-issue.

The other thing that would be important for use as FFT filter is that the center needs to match the center of the FFT. For FFT images, they need to be even dimensions and the center (DC point) is at M/2,N/2. I do not know how you are computing the center now for the current radial-gradient.

For non-square images, as I said before, one would like to have the option of having the radius correspond to either the smaller or larger side. But this is another parameter. Also the elliptic form would be nice.

All these are indeed a lot of parameters and so perhaps might be better implemented via -draw where you can specify such more easily. However, apart from the center issue. One could have:

radial-gradient-small: for the smaller dimension
radial-gradient-large: for the larger dimension
radial-gradient-corner: for the one that goes to the corners
elliptic-gradient: for the elliptical shaped gradient

Another way to have the equivalent cases would be somewhat similar to -distort (but allowing text parameters within the quotes, not just coordinates):

-radial-gradient circle-or-ellipse "outercolor [innercolor] [small-or-large-or-diag] [xcenter,ycenter]"

The defaults would be one color (outercolor), small indicating radius to smaller dimension, and exact center.

A two color gradient would be:
-radial-gradient circle "outercolor innercolor" with radius to smaller dimension and exact center.

A gradient to the diagonal would be:
-radial-gradient circle "outercolor diag"

A gradient for a non-square image to larger dimension (as the default would be small) would be:
-radial-gradient circle "outercolor large"

An elliptic gradient for a non-square image would be:
-radial-gradient ellipse "outercolor"

An offcenter radial gradient to the closest edge for a 100x100 image would be:
-radial-gradient circle "outercolor 70,70"
this would make a radius=30 gradient so that the "circle" just touched the closest edge

These are just some off the top ideas for consideration. I don't suggest that you put a lot of effort into it at this time and certainly don't know what is feasible, practical or worth the effort.

I just wanted to put some ideas forth for consideration while this is being developed rather than after the fact. And again none of this is high priority.

Thanks

Fred
rmagick
Posts: 245
Joined: 2006-03-16T17:30:48-07:00
Location: Durham, NC, USA

Re: Checking out the new GradientImage in 6.4.4-2

Post by rmagick »

magick wrote:Folks, we're working on the gradient parser in the drawing renderer but it may take some time given the current demands on our time. Stand by...
Nor am I in any hurry. When it's done, though, I'll add radial_ and linear_gradient methods to the Draw class in RMagick, and add LinearGradient and RadialGradient paint server classes to RVG. (This will be the first non-bug-fix change to RVG since its first release.) I believe RVG will simplify the creation of such gradients the same way it simplifies creating patterns.

Combining these changes with a wrapper for SparseColorImage will make a nice upgrade to RMagick!
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Checking out the new GradientImage in 6.4.4-2

Post by anthony »

As a quick aside....
rmagick wrote:
magick wrote:Combining these changes with a wrapper for SparseColorImage will make a nice upgrade to RMagick!
Note the API wrapper for command line -sparse-color includes percent escapes allowing you to do some random images like this...

Code: Select all

convert -size 100x100 xc:blue -sparse-color voronoi '
         %[fx:w*rand()],%[fx:h*rand()] Black
         %[fx:w*rand()],%[fx:h*rand()] White
         %[fx:w*rand()],%[fx:h*rand()] Red
         %[fx:w*rand()],%[fx:h*rand()] Blue
         %[fx:w*rand()],%[fx:h*rand()] Lime
         %[fx:w*rand()],%[fx:h*rand()] Yellow
         %[fx:w*rand()],%[fx:h*rand()] Cyan
         %[fx:w*rand()],%[fx:h*rand()] Magenta
   '  random_areas.gif
Image

I actually used this to good effect in the re-implementation of a very old 'fractured mirror' displacement composition
http://www.imagemagick.org/Usage/compos ... ace_mirror

Such percent escapes in arguments are also now enabled for -distort too.

Of course in an programable API like ruby, perl, python, and PHP, the language itself can do these type of calculations after the image has been read in, so such percent escaping methods is not nearly as vital.

I am wanting to see more use of percent escapes in arguments to various command-line options as a prelude to IM version 7. This will hopefully allow you to set arguments (like -size) that are related to other images that have been read into memory. But we have a way to go for this.

Now back to our regular broadcast....
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Checking out the new GradientImage in 6.4.4-2

Post by anthony »

fmw42 wrote:However, as a default, as it might be used for a lookup transformation, it would be preferable to have it go from black (0) at the center to white (quantumrange) at the sides.
That was just and example, but the way the gradient structure is defined the center color will be given first.

I have submitted my change in the sources, and took your suggestion for the radial to be the edge further away from the center. It was a good call, and I have added examples and demonstrations to IM examples
http://www.imagemagick.org/Usage/canvas ... l-gradient
You may also like to look at the final distorted (using wave) example I also added...
http://www.imagemagick.org/Usage/canvas ... nt_distort

These should appear in a day or so (Fred you can see them on my test site).
The other thing that would be important for use as FFT filter is that the center needs to match the center of the FFT. For FFT images, they need to be even dimensions and the center (DC point) is at M/2,N/2. I do not know how you are computing the center now for the current radial-gradient.
Center given in the gradient structure is set to (W-1)/2,(H-1)/2.
For non-square images, as I said before, one would like to have the option of having the radius correspond to either the smaller or larger side. But this is another parameter. Also the elliptic form would be nice.
Those things can be achieved now with distortions of the basic image. For smaller side, create a square image and add borders. For elliptical, do a non-aspect preserving resize (preferable from larger to smaller.

What I like to see is an expansion of the color arguments to allow
color,color:offset,color:offset,color:offset:color
where offsets are between zero and one, and the first and last colors are 0 and 1 respectivally. This is how SVG defines gradients, and should allow direct fallback to the existing color-color syntax for backward compatibility. This should be directly implementable as it can be parsed into the draw_info->gradient data structure.
radial-gradient-small: for the smaller dimension
achievable by using border
radial-gradient-large: for the larger dimension
how it is now implemented
radial-gradient-corner: for the one that goes to the corners
make image that is 1:1.42 aspect ration and center crop. Example is (will be when uploaded) in IM examples.
elliptic-gradient: for the elliptical shaped gradient
Non-aspect preserving resize of a square image.
Another way to have the equivalent cases would be somewhat similar to -distort (but allowing text parameters within the quotes, not just coordinates)

-radial-gradient circle-or-ellipse "outercolor [innercolor] [small-or-large-or-diag] [xcenter,ycenter]"
This has possibilities, and could also include linear, fractial and non-linear gradient styles too.

It will be future expandable, but will not be backward compatible. It will not however be an image generator, but overwrite some existing image in the same way -sparse-color and +noise random does now.

That may be the best solution in the long run, especially if it includes provision for multiple color gradient definitions, gradient repeating styles, and whatever other options can be provided.

I suggest you try to make sense of what those options are in the SVG documentation, so you can get an idea of what thing you may like to provide.
I just wanted to put some ideas forth for consideration while this is being developed rather than after the fact. And again none of this is high priority.
Agreed. But it is the definition that needs to be worked out against what should be provided.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Checking out the new GradientImage in 6.4.4-2

Post by fmw42 »

Anthony wrote:I have submitted my change in the sources, and took your suggestion for the radial to be the edge further away from the center. It was a good call, and I have added examples and demonstrations to IM examples
Actually I was suggesting using he smaller radius (see the following):
Anthony wrote:
radial-gradient-small: for the smaller dimension
achievable by using border
Actually I don't see this. If the gradient is cut off in the smaller dimension, then adding a border will not help to make it fit the smaller dimension. If you make the gradient to the smaller dimension, then you will always see the whole gradient circle and it won't be cutoff anywhere. It will have excess (pad) in the larger dimension.
Anthony wrote:You may also like to look at the final distorted (using wave) example I also added...
http://www.imagemagick.org/Usage/canvas ... nt_distort
Actually I am not sure which one you are referring to?

However, I never thought of using -distort arc to make the gradient per your example:

convert -size 100x100 gradient: -distort Arc '360 0 50 0' \
gradient_circle.jpg

Is this exactly comparable to the -radial-gradient?

I guess the only way to set the center (for FFT) is to use SRT by half pixel, but this will slightly distort the values due to resampling.
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Checking out the new GradientImage in 6.4.4-2

Post by anthony »

fmw42 wrote:Actually I was suggesting using he smaller radius (see the following):
radial-gradient-small: for the smaller dimension
achievable by using border
Actually I don't see this. If the gradient is cut off in the smaller dimension, then adding a border will not help to make it fit the smaller dimension. If you make the gradient to the smaller dimension, then you will always see the whole gradient circle and it won't be cutoff anywhere. It will have excess (pad) in the larger dimension.
You generate a square image using the smaller dimension (no clip) then pad to the final size using -border.

Anthony wrote:You may also like to look at the final distorted (using wave) example I also added...
http://www.imagemagick.org/Usage/canvas ... nt_distort
Actually I am not sure which one you are referring to?
It will take time to appear on the main site. No it hasn't appear yet. Go look at my test site, which I know I gave you have access to look at.
However, I never thought of using -distort arc to make the gradient per your example:

Code: Select all

convert -size 100x100 gradient: -distort Arc '360 0 50 0' \
          gradient_circle.jpg
Is this exactly comparable to the -radial-gradient?
Should be, though there is a slight image size difference.
However after ensuring both images are 100x100 by shaving and negating the above image, a flicker_cmp shows the images have no visible differences, with aligned centers. Of course using JPEG would guarantee that there are lots of very minor non-visible differences.

radial-gradient of course would be faster and much more direct, than distorting, as it would avoid a lot of calculation and pixel sampling.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Checking out the new GradientImage in 6.4.4-2

Post by fmw42 »

anthony wrote: radial-gradient-small: for the smaller dimension
achievable by using border

You generate a square image using the smaller dimension (no clip) then pad to the final size using -border.
Right! Got it.

Anthony wrote:You may also like to look at the final distorted (using wave) example I also added...
http://www.imagemagick.org/Usage/canvas ... nt_distort
Go look at my test site, which I know I gave you have access to look at.
I did look at your test site, but cannot figure out which example. What does it look like? I don't see the word "wave" anywhere?

A lot of nice examples. Perhaps you can add the elliptical gradient example.
User avatar
rmabry
Posts: 148
Joined: 2004-04-13T11:25:27-07:00

Re: Checking out the new GradientImage in 6.4.4-2

Post by rmabry »

Huzzah! This is great:

http://www.imagemagick.org/Usage/canvas/#gradient

I tested the following (on Version: ImageMagick 6.4.4 2008-10-19 Q16):

convert -size 100x100 xc: -sparse-color Barycentric '30,0 red 0,80 blue 99,99 lime' sparse_bary_triangle0.png


which is just an extraction of the gradient-relevant part of one of Anthony's examples. Works fine. My question now is:

How do I do this in PerlMagick? I have never seen a "color name" (used with xc:) that has this form. The command line handles it fine, but I'm unclear how to set the arg in PerlMagick, á la the usual:

$image->ReadImage("xc: white");


I tried permutations of the following, but I guess I couldn't hit the right combo.

$image->ReadImage("xc: -sparse-color Barycentric \'30,0 red 0,80 blue 99,99 lime\'");


It no likey:

Exception 310: unrecognized color `-sparse-color Barycentric '30,0 red 0,80 blue 99,99 lime''

Or perhaps PerlMagick is not yet prepared for this. Any hints?

Rick
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Checking out the new GradientImage in 6.4.4-2

Post by el_supremo »

-sparse-color is a new command line operator with an underlying function in MagickCore (SparseColorImage), but apparently it's not yet in MagickWand.

So, you would use

Code: Select all

$image->ReadImage("xc:");
and follow it with something like $image->sparse_color() once it's been implemented in PerlMagick.

Pete
User avatar
rmabry
Posts: 148
Joined: 2004-04-13T11:25:27-07:00

Re: Checking out the new GradientImage in 6.4.4-2

Post by rmabry »

el_supremo wrote:you would use

Code: Select all

$image->ReadImage("xc:");
Thanks, Pete, I guess I'll just be patient.

Funny, I never knew "xc:" made any sense without being followed by something further. I still don't know what sense it makes, but it seems to return a white image.

Rick
User avatar
rmabry
Posts: 148
Joined: 2004-04-13T11:25:27-07:00

Re: Checking out the new GradientImage in 6.4.4-2

Post by rmabry »

rmabry wrote: Thanks, Pete, I guess I'll just be patient.
Well, I am not actually so patient, but it might be forced on me.

I just downloaded 6.4.5 and I see that SparseColorImage is in PerlMagick. But I can't figure out how to get the colors into the call. For this,

convert -size 100x100 xc: -sparse-color Barycentric '30,0 red 0,80 blue 99,99 lime' sparse_bary_triangle0.png

I'd have guessed something like this

$image->SparseColor(method=>"barycentric", points=>[30,0 , 0,80, 99,99], channel=> ...)


But where to put the colors?

I am not sure what is expected for channel (if that is even the right place).
The PerlMagick code shows something happening with channel, but the specs do not:

SparseColor points=>array of float values, method=>{Barycentric, Bilinear, Shepards, Voronoi}, virtual-pixel=>{Background Black Constant Dither Edge Gray Mirror Random Tile
Transparent White}

I used channel => 7, figuring that would give me Red |Green | Blue.

Glancing at the code, though, I am suspecting that the colors are somehow numeric and mixed somehow go into the points array. Say it aint so. Or if so, that it is surely temporary and not yet implemented in PerlMagick and that I must indeed wait ...

Ever patiently (for minutes on end),

Rick
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Checking out the new GradientImage in 6.4.4-2

Post by el_supremo »

The SparseColorImage function mixes the coordinates and colours together in a list of floating point doubles where the colours are specified as normalized values (e.g. RGB red would be 1,0,0).
The channels are specified in the same way as any other function which takes a channel argument but I don't know how this is done in Perl.
If the channel is specified (somehow) as RGB , then I assume the list of floating point values for '30,0 red 0,80 blue 99,99 lime' would be
30, 0, 1, 0, 0, 0, 80, 0, 0, 1, 99, 99, 0,1,0

HTH
Pete
el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: Checking out the new GradientImage in 6.4.4-2

Post by el_supremo »

I got an example of SparseColorImage working. It's a mix of MagickCore and MagickWand and almost certainly has a memory leak or two in it, but it does produce the same output as Anthony's example (minus the circles).

Pete

Code: Select all

/*
See the Barycentric section of http://www.imagemagick.org/Usage/canvas/#sparse-color
convert -size 100x100 xc: -sparse-color  Barycentric \
              '30,10 red   10,80 blue   70,60 lime' \
          -fill white -stroke black \
          -draw 'circle 30,10 30,12  circle 10,80 10,82  circle 70,60 70,62' \
          sparse_barycentric.png

*/
#include <windows.h>
#include <magick/MagickCore.h>
#include <wand/magick_wand.h>

void test_wand(LPTSTR lpCmdLine)
{
	MagickWand *mw = NULL,*mwi = NULL;
	Image *im,*imw;
	double l_doubles[] = {30, 10, 1, 0, 0, 10, 80, 0, 0, 1, 70,60, 0,1,0};
	ExceptionInfo *exception;

	MagickWandGenesis();
	exception = AcquireExceptionInfo();
	GetExceptionInfo(exception);
	mw  = NewMagickWand();
	MagickSetSize(mw,100,100);
	MagickReadImage(mw,"xc:");

	imw = GetImageFromMagickWand(mw);
	im = SparseColorImage(imw,RedChannel|GreenChannel|BlueChannel,
			BarycentricColorInterpolate,15,l_doubles,exception);
	mwi = NewMagickWandFromImage(im);
	MagickWriteImage(mwi,"sparse.gif");

	DestroyMagickWand(mw);
	DestroyMagickWand(mwi);
	DestroyExceptionInfo(exception);
    MagickWandTerminus();
}
User avatar
rmabry
Posts: 148
Joined: 2004-04-13T11:25:27-07:00

Re: Checking out the new GradientImage in 6.4.4-2

Post by rmabry »

el_supremo wrote: the list of floating point values for '30,0 red 0,80 blue 99,99 lime' would be

30, 0, 1, 0, 0, 0, 80, 0, 0, 1, 99, 99, 0,1,0

HTH
It does help, it works. Coulda swore I tried that, but I think I didn't have channel set.
User avatar
rmabry
Posts: 148
Joined: 2004-04-13T11:25:27-07:00

Re: Checking out the new GradientImage in 6.4.4-2

Post by rmabry »

el_supremo wrote:I got an example of SparseColorImage working. It's a mix of MagickCore and MagickWand and almost certainly has a memory leak or two in it, but it does produce the same output as Anthony's example (minus the circles).
Hey, thanks for that. This perl snippet also works, just as you said, though I'm not sure of a better way to enter the channel.

use Image::Magick;

my $image = new Image::Magick;
$image->Set(size=>'100x100');
my $ok = $image->ReadImage("xc:");
die "$ok" if "$ok";

$image->SparseColor(method=>"barycentric",
points=>[30, 0, 1, 0, 0, 0, 80, 0, 0, 1, 99, 99, 1,1,0], channel=>7);

$image->WriteImage('gradient-test.png');

undef $image;


Rick
Post Reply