1 package Imager::Transform;
4 use Imager::Expr::Assem;
13 desc=>"Mandelbrot set",
16 # x treated as in range minx..maxx
17 # y treated as in range miny..maxy
19 var diffx:n ; var diffy:n
20 # conx/y are x/y adjusted to min..max ranges
21 var conx:n ; var cony:n
22 diffx = subtract maxx minx
24 conx = mult conx diffx
26 diffy = subtract maxy miny
28 cony = mult cony diffy
35 # calculate (nx,ny)**2 +(x,y)->
36 # (nx*nx-ny*ny+x, 2.nx.ny+y)
37 var wx:n ; var wy:n ; var work:n
46 work = distance nx ny 0 0
50 work = lt count maxcount
52 jumpnz insideangle doinang
61 workp = hsv ang 255 0.5
65 outvalue = mult outsidevaluestep count
66 outvalue = add outvalue outsidevalue
67 outvalue = mod outvalue 1.01
68 jumpnz outsideangle do_outang
69 work = mult count huestep
70 work = add work huebase
72 workp = hsv work 1 outvalue
78 ang = add ang outsidebase
79 workp = hsv ang outsidesat outvalue
84 minx=>{ default=>-2, desc=>'Left of rendered area', },
85 miny=>{ default=>-1.5, desc=>'Top of rendered area', },
86 maxx=>{ default=>1, desc=>'Right of rendered area', },
87 maxy=>{ default=>1.5, desc=>'Bottom of rendered area', },
88 maxcount=>{ default=>100, desc=>'Maximum iterations', },
89 huestep=>{ default=>21.1, desc=>'Hue step for number of iterations', },
90 huebase=>{ default=>0, desc=>'Base hue for number of iterations', },
94 desc=>'Non-zero to use angle of final as hue for inside',
99 desc=>'Base angle for inside colours if insideangle is non-zero',
104 desc=>'Non-zero to use angle of final as hue for outside',
109 desc=>'Base angle if outsideangle is true',
114 desc=>'Brightness for outside pixels',
119 desc=>'Brightness step for each count for outside pixels',
124 desc=>'Saturation for outside pixels',
135 # x treated as in range minx..maxx
136 # y treated as in range miny..maxy
138 var diffx:n ; var diffy:n
139 # conx/y are x/y adjusted to min..max ranges
140 var conx:n ; var cony:n
141 diffx = subtract maxx minx
143 conx = mult conx diffx
145 diffy = subtract maxy miny
147 cony = mult cony diffy
154 # calculate (nx,ny)**2 +(x,y)->
155 # (nx*nx-ny*ny+x, 2.nx.ny+y)
156 var wx:n ; var wy:n ; var work:n
165 work = distance nx ny 0 0
169 work = lt count maxcount
171 jumpnz insideangle doinang
180 workp = hsv ang 255 0.5
184 outvalue = mult outsidevaluestep count
185 outvalue = add outvalue outsidevalue
186 outvalue = mod outvalue 1.01
187 jumpnz outsideangle do_outang
188 work = mult count huestep
189 work = add work huebase
191 workp = hsv work 1 outvalue
197 ang = add ang outsidebase
198 workp = hsv ang outsidesat outvalue
203 zx=>{default=>0.7, desc=>'Real part of initial Z', },
204 zy=>{default=>0.2, desc=>'Imaginary part of initial Z', },
205 minx=>{ default=>-1.5, desc=>'Left of rendered area', },
206 miny=>{ default=>-1.5, desc=>'Top of rendered area', },
207 maxx=>{ default=>1.5, desc=>'Right of rendered area', },
208 maxy=>{ default=>1.5, desc=>'Bottom of rendered area', },
209 maxcount=>{ default=>100, desc=>'Maximum iterations', },
210 huestep=>{ default=>21.1, desc=>'Hue step for number of iterations', },
211 huebase=>{ default=>0, desc=>'Base hue for number of iterations', },
215 desc=>'Non-zero to use angle of final as hue for inside',
220 desc=>'Base angle for inside colours if insideangle is non-zero',
225 desc=>'Non-zero to use angle of final as hue for outside',
230 desc=>'Base angle if outsideangle is true',
235 desc=>'Brightness for outside pixels',
240 desc=>'Brightness step for each count for outside pixels',
245 desc=>'Saturation for outside pixels',
253 desc=>'Adds a circular ripple effect',
255 x y cx cy distance !dist
256 @dist freq / sin !scale
257 @scale depth * @dist + !adj
258 y cy - x cx - atan2 !ang
259 cx @ang cos @adj * + cy @ang sin @adj * + getp1 @scale shadow + shadow 1 + / *
263 freq=> { desc=>'Frequency of ripples', default=>5 },
264 depth=> { desc=>'Depth of ripples', default=>10 },
265 shadow=> { desc=>'Fraction of shadow', default=>20 },
269 { desc=>'Image to ripple' }
275 desc=>'Render a colorful spiral',
277 x y cx cy distance !d y cy - x cx - atan2 !a
278 @d spacing / @a + pi 2 * % !a2
279 @a 180 * pi / 1 @a2 sin 1 + 2 / hsv
283 spacing=>{ desc=>'Spacing between arms', default=>10 },
290 desc=>'Adds diagonal ripples to an image',
292 x y + !dist @dist freq / sin !scale
294 x @adj + y @adj + getp1 @scale shadow + shadow 1 + / *
298 freq=>{ desc=>'Frequency of ripples', default=>5, },
299 depth=>{desc=>'Depth of ripples', default=>3,},
302 desc=>'Fraction of brightness to remove for shadows',
308 { desc=>'Image to add ripples to' }
314 desc=>'Twist an image',
316 x y cx cy distance !dist
317 y cy - x cx - atan2 @dist twist / + !ang
318 cx @ang cos @dist * + cy @ang sin @dist * + getp1
322 twist=>{ desc=>'Amount of twist', default=>2.5, },
326 { desc=>'Image to twist' },
329 # any other functions can wait until Imager::Expr::Infix supports
334 my ($class, $name) = @_;
336 exists $funcs{$name} or return;
338 bless { func=>$funcs{$name}, name=>$name }, $class;
343 return @{$self->{func}{inputs}}
349 return @{$self->{func}{constants}}{@_};
352 return keys %{$self->{func}{constants}};
357 my ($self, $opts, $constants, @in) = @_;
359 my $func = $self->{func};
361 $opts{$func->{type}} = $func->{$func->{type}};
362 my %con = %$constants;
363 for my $name (keys %{$func->{'constants'}}) {
364 unless (exists $con{$name}) {
365 if (exists $func->{'constants'}{$name}{default}) {
366 $con{$name} = $func->{'constants'}{$name}{default};
369 $self->{error} = "No value or default for constant $name";
374 $opts{'constants'} = \%con;
375 unless (@in == @{$func->{'inputs'}}) {
376 $self->{error} = @in." input images given, ".
377 @{$func->{'inputs'}}." supplied";
381 my $out = Imager::transform2(\%opts, @in);
383 $self->{error} = $Imager::ERRSTR;
398 my ($class, $name) = @_;
401 if (ref $class && !$name) {
402 $func = $class->{func};
403 $name = $class->{name}
406 $func = $funcs{$name}
411 Description: $func->{desc}
413 if ($func->{'inputs'} && @{$func->{'inputs'}}) {
414 $desc .= "Input images:\n";
416 for my $in (@{$func->{'inputs'}}) {
417 $desc .= " $i: $in->{desc}\n";
421 $desc .= "There are no input images\n";
423 if ($func->{'constants'} && keys %{$func->{'constants'}}) {
424 $desc .= "Input constants:\n";
425 for my $key (keys %{$func->{'constants'}}) {
426 $desc .= " $key: $func->{'constants'}{$key}{desc}\n";
427 $desc .= " Default: $func->{'constants'}{$key}{default}\n";
431 $desc .= "There are no constants\n";
444 Imager::Transform - a library of register machine image transformations
448 # get a list of transformations
449 my @funcs = Imager::Transform->list;
450 # create a transformation object
451 my $tran = Imager::Transform->new($name);
453 print $tran->describe;
454 # a list of constant names
455 my @constants = $tran->constants;
456 # information about some of the constants
457 my @info = $tran->constants(@constants);
461 This module provides a library of transformations that use the Imager
462 transform2() function.
464 The aim is to provide a place to collect these transformations.
466 At some point there might be an interface to add new functions, but
467 there's not a whole lot of point to that.
469 The interface is a little sparse as yet.
475 =item my @names = Imager::Transform->list
477 Returns a list of the transformations.
479 =item my $desc = Imager::Transform->describe($name);
481 =item my $desc = $tran->describe()
483 Describes a transformation specified either by name (as a class
484 method) or by reference (as an instance method).
486 The class method returns undef if there is no such transformation.
488 =item my $tran = Imager::Transform->new($name)
490 Create a new transformation object. Returns undef if there is no such
493 =item my @inputs = $tran->inputs;
495 =item my $inputs = $tran->inputs;
497 Returns a list of input image descriptions, or the number of them,
498 depending on content.
500 The list contains hash references, which current contain only one
501 member, C<desc>, a description of the use of the input image.
503 =item $tran->constants
505 Returns a list of names of constants that can be set for the
508 =item $tran->constants($name, $name, ...)
510 Returns a hashref for each named constant, which contains the default
511 in key C<default> and a description in key C<desc>.
513 =item my $out = $tran->transform(\%opts, \%constants, @imgs)
515 Perform the image transformation.
517 Returns the new image on success, or undef on failure, in which case
518 you can use $tran->errstr to get an error message.
522 The error message, if any from the last image transformation.
528 Needs more transformations.
532 Imager(3), F<transform.perl>
536 Tony Cook <tonyc@cpan.org>