1 package Imager::Transform;
4 use Imager::Expr::Assem;
10 desc=>"Mandelbrot set",
13 # x treated as in range minx..maxx
14 # y treated as in range miny..maxy
16 var diffx:n ; var diffy:n
17 # conx/y are x/y adjusted to min..max ranges
18 var conx:n ; var cony:n
19 diffx = subtract maxx minx
21 conx = mult conx diffx
23 diffy = subtract maxy miny
25 cony = mult cony diffy
32 # calculate (nx,ny)**2 +(x,y)->
33 # (nx*nx-ny*ny+x, 2.nx.ny+y)
34 var wx:n ; var wy:n ; var work:n
43 work = distance nx ny 0 0
47 work = lt count maxcount
49 jumpnz insideangle doinang
58 workp = hsv ang 255 0.5
62 outvalue = mult outsidevaluestep count
63 outvalue = add outvalue outsidevalue
64 outvalue = mod outvalue 1.01
65 jumpnz outsideangle do_outang
66 work = mult count huestep
67 work = add work huebase
69 workp = hsv work 1 outvalue
75 ang = add ang outsidebase
76 workp = hsv ang outsidesat outvalue
81 minx=>{ default=>-2, desc=>'Left of rendered area', },
82 miny=>{ default=>-1.5, desc=>'Top of rendered area', },
83 maxx=>{ default=>1, desc=>'Right of rendered area', },
84 maxy=>{ default=>1.5, desc=>'Bottom of rendered area', },
85 maxcount=>{ default=>100, desc=>'Maximum iterations', },
86 huestep=>{ default=>21.1, desc=>'Hue step for number of iterations', },
87 huebase=>{ default=>0, desc=>'Base hue for number of iterations', },
91 desc=>'Non-zero to use angle of final as hue for inside',
96 desc=>'Base angle for inside colours if insideangle is non-zero',
101 desc=>'Non-zero to use angle of final as hue for outside',
106 desc=>'Base angle if outsideangle is true',
111 desc=>'Brightness for outside pixels',
116 desc=>'Brightness step for each count for outside pixels',
121 desc=>'Saturation for outside pixels',
132 # x treated as in range minx..maxx
133 # y treated as in range miny..maxy
135 var diffx:n ; var diffy:n
136 # conx/y are x/y adjusted to min..max ranges
137 var conx:n ; var cony:n
138 diffx = subtract maxx minx
140 conx = mult conx diffx
142 diffy = subtract maxy miny
144 cony = mult cony diffy
151 # calculate (nx,ny)**2 +(x,y)->
152 # (nx*nx-ny*ny+x, 2.nx.ny+y)
153 var wx:n ; var wy:n ; var work:n
162 work = distance nx ny 0 0
166 work = lt count maxcount
168 jumpnz insideangle doinang
177 workp = hsv ang 255 0.5
181 outvalue = mult outsidevaluestep count
182 outvalue = add outvalue outsidevalue
183 outvalue = mod outvalue 1.01
184 jumpnz outsideangle do_outang
185 work = mult count huestep
186 work = add work huebase
188 workp = hsv work 1 outvalue
194 ang = add ang outsidebase
195 workp = hsv ang outsidesat outvalue
200 zx=>{default=>0.7, desc=>'Real part of initial Z', },
201 zy=>{default=>0.2, desc=>'Imaginary part of initial Z', },
202 minx=>{ default=>-1.5, desc=>'Left of rendered area', },
203 miny=>{ default=>-1.5, desc=>'Top of rendered area', },
204 maxx=>{ default=>1.5, desc=>'Right of rendered area', },
205 maxy=>{ default=>1.5, desc=>'Bottom of rendered area', },
206 maxcount=>{ default=>100, desc=>'Maximum iterations', },
207 huestep=>{ default=>21.1, desc=>'Hue step for number of iterations', },
208 huebase=>{ default=>0, desc=>'Base hue for number of iterations', },
212 desc=>'Non-zero to use angle of final as hue for inside',
217 desc=>'Base angle for inside colours if insideangle is non-zero',
222 desc=>'Non-zero to use angle of final as hue for outside',
227 desc=>'Base angle if outsideangle is true',
232 desc=>'Brightness for outside pixels',
237 desc=>'Brightness step for each count for outside pixels',
242 desc=>'Saturation for outside pixels',
251 x y cx cy distance !dist
252 @dist freq / sin !scale
253 @scale depth * @dist + !adj
254 y cy - x cx - atan2 !ang
255 cx @ang cos @adj * + cy @ang sin @adj * + getp1 @scale shadow + shadow 1 + / *
259 freq=> { desc=>'Frequency of ripples', default=>5 },
260 depth=> { desc=>'Depth of ripples', default=>10 },
261 shadow=> { desc=>'Fraction of shadow', default=>20 },
265 { desc=>'Image to ripple' }
272 x y cx cy distance !d y cy - x cx - atan2 !a
273 @d spacing / @a + pi 2 * % !a2
274 @a 180 * pi / 1 @a2 sin 1 + 2 / hsv
278 spacing=>{ desc=>'Spacing between arms', default=>10 },
285 desc=>'Adds diagonal ripples to an image',
287 x y + !dist @dist freq / sin !scale
289 x @adj + y @adj + getp1 @scale shadow + shadow 1 + / *
293 freq=>{ desc=>'Frequency of ripples', default=>5, },
294 depth=>{desc=>'Depth of ripples', default=>3,},
297 desc=>'Fraction of brightness to remove for shadows',
303 { desc=>'Image to add ripples to' }
309 desc=>'Twist an image',
311 x y cx cy distance !dist
312 y cy - x cx - atan2 @dist twist / + !ang
313 cx @ang cos @dist * + cy @ang sin @dist * + getp1
317 twist=>{ desc=>'Amount of twist', default=>2.5, },
321 { desc=>'Image to twist' },
324 # any other functions can wait until Imager::Expr::Infix supports
329 my ($class, $name) = @_;
331 exists $funcs{$name} or return;
333 bless { func=>$funcs{$name}, name=>$name }, $class;
338 return @{$self->{func}{inputs}}
344 return @{$self->{func}{constants}}{@_};
347 return keys %{$self->{func}{constants}};
352 my ($self, $opts, $constants, @in) = @_;
354 my $func = $self->{func};
356 $opts{$func->{type}} = $func->{$func->{type}};
357 my %con = %$constants;
358 for my $name (keys %{$func->{constants}}) {
359 unless (exists $con{$name}) {
360 if (exists $func->{constants}{$name}{default}) {
361 $con{$name} = $func->{constants}{$name}{default};
364 $self->{error} = "No value or default for constant $name";
369 $opts{constants} = \%con;
370 unless (@in == @{$func->{inputs}}) {
371 $self->{error} = @in." input images given, ".
372 @{$func->{inputs}}." supplied";
376 my $out = Imager::transform2(\%opts, @in);
378 $self->{error} = $Imager::ERRSTR;
393 my ($class, $name) = @_;
396 if (ref $class && !$name) {
397 $func = $class->{func};
398 $name = $class->{name}
401 $func = $funcs{$name}
406 Description: $func->{desc}
408 if ($func->{inputs} && @{$func->{inputs}}) {
409 $desc .= "Input images:\n";
411 for my $in (@{$func->{inputs}}) {
412 $desc .= " $i: $in->{desc}\n";
416 $desc .= "There are no input images\n";
418 if ($func->{constants} && keys %{$func->{constants}}) {
419 $desc .= "Input constants:\n";
420 for my $key (keys %{$func->{constants}}) {
421 $desc .= " $key: $func->{constants}{$key}{desc}\n";
422 $desc .= " Default: $func->{constants}{$key}{default}\n";
426 $desc .= "There are no constants\n";
439 Imager::Transform - a library of register machine image transformations
443 # get a list of transformations
444 my @funcs = Imager::Transform->list;
445 # create a transformation object
446 my $tran = Imager::Transform->new($name);
448 print $tran->describe;
449 # a list of constant names
450 my @constants = $tran->constants;
451 # information about some of the constants
452 my @info = $tran->constants(@constants);
456 This module provides a library of transformations that use the Imager
457 transform2() function.
459 The aim is to provide a place to collect these transformations.
461 At some point there might be an interface to add new functions, but
462 there's not a whole lot of point to that.
464 The interface is a little sparse as yet.
470 =item my @names = Imager::Transform->list
472 Returns a list of the transformations.
474 =item my $desc = Imager::Transform->describe($name);
476 =item my $desc = $tran->describe()
478 Describes a transformation specified either by name (as a class
479 method) or by reference (as an instance method).
481 The class method returns undef if there is no such transformation.
483 =item my $tran = Imager::Transform->new($name)
485 Create a new transformation object. Returns undef if there is no such
488 =item my @inputs = $tran->inputs;
490 =item my $inputs = $tran->inputs;
492 Returns a list of input image descriptions, or the number of them,
493 depending on content.
495 The list contains hashrefs, which current contain only one member,
496 desc, a description of the use of the image.
498 =item my $out = $tran->transform(\%opts, \%constants, @imgs)
500 Perform the image transformation.
502 Returns the new image on success, or undef on failure, in which case
503 you can use $tran->errstr to get an error message.
507 The error message, if any from the last image transformation.
513 Needs more transformations.
517 Imager(3), transform.perl