From: Arnar Mar Hrafnkelsson Date: Wed, 16 Jan 2002 04:39:02 +0000 (+0000) Subject: Added Engines pod, moved masked images to ImageTypes, and moved convert() X-Git-Tag: Imager-0.48^2~443 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/3e1be2c1bffb8accbcfcf6a48779cf227b5306ad?ds=sidebyside Added Engines pod, moved masked images to ImageTypes, and moved convert() and map() to Transformations. --- diff --git a/Changes b/Changes index e125cf21..59668511 100644 --- a/Changes +++ b/Changes @@ -596,6 +596,7 @@ Revision history for Perl extension Imager. - Added lib/Imager/Transformations.pod, some docs of simple transforms. - Added lib/Imager/ImageTypes.pod, draft of ImageType pod. - Added lib/Imager/Filters.pod, draft of Filters pod. + - Added lib/Imager/Engines.pod, draft of Engines pod. ================================================================= diff --git a/Imager.pm b/Imager.pm index 8baa2cb0..fbc6945e 100644 --- a/Imager.pm +++ b/Imager.pm @@ -3156,748 +3156,8 @@ color table. -=head2 Filters - -A special image method is the filter method. An example is: - - $img->filter(type=>'autolevels'); - -This will call the autolevels filter. Here is a list of the filters -that are always avaliable in Imager. This list can be obtained by -running the C script that comes with the module -source. - - Filter Arguments - autolevels lsat(0.1) usat(0.1) skew(0) - bumpmap bump elevation(0) lightx lighty st(2) - bumpmap_complex bump channel(0) tx(0) ty(0) Lx(0.2) Ly(0.4) - Lz(-1) cd(1.0) cs(40.0) n(1.3) Ia(0 0 0) Il(255 255 255) - Is(255 255 255) - contrast intensity - conv coef - fountain xa ya xb yb ftype(linear) repeat(none) combine(none) - super_sample(none) ssample_param(4) segments(see below) - gaussian stddev - gradgen xo yo colors dist - hardinvert - mosaic size(20) - noise amount(3) subtype(0) - postlevels levels(10) - radnoise xo(100) yo(100) ascale(17.0) rscale(0.02) - turbnoise xo(0.0) yo(0.0) scale(10.0) - unsharpmask stddev(2.0) scale(1.0) - watermark wmark pixdiff(10) tx(0) ty(0) - -The default values are in parenthesis. All parameters must have some -value but if a parameter has a default value it may be omitted when -calling the filter function. - -The filters are: -=over - -=item autolevels - -scales the value of each channel so that the values in the image will -cover the whole possible range for the channel. I and I -truncate the range by the specified fraction at the top and bottom of -the range respectivly.. - -=item bumpmap - -uses the channel I image I as a bumpmap on your -image, with the light at (I, I), with a shadow length -of I. - -=item bumpmap_complex - -uses the channel I image I as a bumpmap on your image. -If Lz<0 the three L parameters are considered to be the direction of -the light. If Lz>0 the L parameters are considered to be the light -position. I is the ambient colour, I is the light colour, -I is the color of specular highlights. I is the diffuse -coefficient and I is the specular coefficient. I is the -shininess of the surface. - -=item contrast - -scales each channel by I. Values of I < 1.0 -will reduce the contrast. - -=item conv - -performs 2 1-dimensional convolutions on the image using the values -from I. I should be have an odd length. - -=item fountain - -renders a fountain fill, similar to the gradient tool in most paint -software. The default fill is a linear fill from opaque black to -opaque white. The points A(xa, ya) and B(xb, yb) control the way the -fill is performed, depending on the ftype parameter: - -=over - -=item linear - -the fill ramps from A through to B. - -=item bilinear - -the fill ramps in both directions from A, where AB defines the length -of the gradient. - -=item radial - -A is the center of a circle, and B is a point on it's circumference. -The fill ramps from the center out to the circumference. - -=item radial_square - -A is the center of a square and B is the center of one of it's sides. -This can be used to rotate the square. The fill ramps out to the -edges of the square. - -=item revolution - -A is the centre of a circle and B is a point on it's circumference. B -marks the 0 and 360 point on the circle, with the fill ramping -clockwise. - -=item conical - -A is the center of a circle and B is a point on it's circumference. B -marks the 0 and point on the circle, with the fill ramping in both -directions to meet opposite. - -=back - -The I option controls how the fill is repeated for some -Is after it leaves the AB range: - -=over - -=item none - -no repeats, points outside of each range are treated as if they were -on the extreme end of that range. - -=item sawtooth - -the fill simply repeats in the positive direction - -=item triangle - -the fill repeats in reverse and then forward and so on, in the -positive direction - -=item saw_both - -the fill repeats in both the positive and negative directions (only -meaningful for a linear fill). - -=item tri_both - -as for triangle, but in the negative direction too (only meaningful -for a linear fill). - -=back - -By default the fill simply overwrites the whole image (unless you have -parts of the range 0 through 1 that aren't covered by a segment), if -any segments of your fill have any transparency, you can set the -I option to 'normal' to have the fill combined with the -existing pixels. See the description of I in L. - -If your fill has sharp edges, for example between steps if you use -repeat set to 'triangle', you may see some aliased or ragged edges. -You can enable super-sampling which will take extra samples within the -pixel in an attempt anti-alias the fill. - -The possible values for the super_sample option are: - -=over - -=item none - -no super-sampling is done - -=item grid - -a square grid of points are sampled. The number of points sampled is -the square of ceil(0.5 + sqrt(ssample_param)). - -=item random - -a random set of points within the pixel are sampled. This looks -pretty bad for low ssample_param values. - -=item circle - -the points on the radius of a circle within the pixel are sampled. -This seems to produce the best results, but is fairly slow (for now). - -=back - -You can control the level of sampling by setting the ssample_param -option. This is roughly the number of points sampled, but depends on -the type of sampling. - -The segments option is an arrayref of segments. You really should use -the Imager::Fountain class to build your fountain fill. Each segment -is an array ref containing: - -=over - -=item start - -a floating point number between 0 and 1, the start of the range of fill parameters covered by this segment. - -=item middle - -a floating point number between start and end which can be used to -push the color range towards one end of the segment. - -=item end - -a floating point number between 0 and 1, the end of the range of fill -parameters covered by this segment. This should be greater than -start. - -=item c0 - -=item c1 - -The colors at each end of the segment. These can be either -Imager::Color or Imager::Color::Float objects. - -=item segment type - -The type of segment, this controls the way the fill parameter varies -over the segment. 0 for linear, 1 for curved (unimplemented), 2 for -sine, 3 for sphere increasing, 4 for sphere decreasing. - -=item color type - -The way the color varies within the segment, 0 for simple RGB, 1 for -hue increasing and 2 for hue decreasing. - -=back - -Don't forget to use Imager::Fountain instead of building your own. -Really. It even loads GIMP gradient files. - -=item gaussian - -performs a gaussian blur of the image, using I as the standard -deviation of the curve used to combine pixels, larger values give -bigger blurs. For a definition of Gaussian Blur, see: - - http://www.maths.abdn.ac.uk/~igc/tch/mx4002/notes/node99.html - -=item gradgen - -renders a gradient, with the given I at the corresponding -points (x,y) in I and I. You can specify the way distance is -measured for color blendeing by setting I to 0 for Euclidean, 1 -for Euclidean squared, and 2 for Manhattan distance. - -=item hardinvert - -inverts the image, black to white, white to black. All channels are -inverted, including the alpha channel if any. - -=item mosaic - -produces averaged tiles of the given I. - -=item noise - -adds noise of the given I to the image. If I is -zero, the noise is even to each channel, otherwise noise is added to -each channel independently. - -=item radnoise - -renders radiant Perlin turbulent noise. The centre of the noise is at -(I, I), I controls the angular scale of the noise , -and I the radial scale, higher numbers give more detail. - -=item postlevels - -alters the image to have only I distinct level in each -channel. - -=item turbnoise - -renders Perlin turbulent noise. (I, I) controls the origin of -the noise, and I the scale of the noise, with lower numbers -giving more detail. - -=item unsharpmask - -performs an unsharp mask on the image. This is the result of -subtracting a gaussian blurred version of the image from the original. -I controls the stddev parameter of the gaussian blur. Each -output pixel is: in + I * (in - blurred). - -=item watermark - -applies I as a watermark on the image with strength I, -with an origin at (I, I) - -=back - -A demonstration of most of the filters can be found at: - - http://www.develop-help.com/imager/filters.html - -(This is a slow link.) - -=head2 Color transformations - -You can use the convert method to transform the color space of an -image using a matrix. For ease of use some presets are provided. - -The convert method can be used to: - -=over 4 - -=item * - -convert an RGB or RGBA image to grayscale. - -=item * - -convert a grayscale image to RGB. - -=item * - -extract a single channel from an image. - -=item * - -set a given channel to a particular value (or from another channel) - -=back - -The currently defined presets are: - -=over - -=item gray - -=item grey - -converts an RGBA image into a grayscale image with alpha channel, or -an RGB image into a grayscale image without an alpha channel. - -This weights the RGB channels at 22.2%, 70.7% and 7.1% respectively. - -=item noalpha - -removes the alpha channel from a 2 or 4 channel image. An identity -for other images. - -=item red - -=item channel0 - -extracts the first channel of the image into a single channel image - -=item green - -=item channel1 - -extracts the second channel of the image into a single channel image - -=item blue - -=item channel2 - -extracts the third channel of the image into a single channel image - -=item alpha - -extracts the alpha channel of the image into a single channel image. - -If the image has 1 or 3 channels (assumed to be grayscale of RGB) then -the resulting image will be all white. - -=item rgb - -converts a grayscale image to RGB, preserving the alpha channel if any - -=item addalpha - -adds an alpha channel to a grayscale or RGB image. Preserves an -existing alpha channel for a 2 or 4 channel image. - -=back - -For example, to convert an RGB image into a greyscale image: - - $new = $img->convert(preset=>'grey'); # or gray - -or to convert a grayscale image to an RGB image: - - $new = $img->convert(preset=>'rgb'); - -The presets aren't necessary simple constants in the code, some are -generated based on the number of channels in the input image. - -If you want to perform some other colour transformation, you can use -the 'matrix' parameter. - -For each output pixel the following matrix multiplication is done: - - channel[0] [ [ $c00, $c01, ... ] inchannel[0] - [ ... ] = ... x [ ... ] - channel[n-1] [ $cn0, ..., $cnn ] ] inchannel[max] - 1 - -So if you want to swap the red and green channels on a 3 channel image: - - $new = $img->convert(matrix=>[ [ 0, 1, 0 ], - [ 1, 0, 0 ], - [ 0, 0, 1 ] ]); - -or to convert a 3 channel image to greyscale using equal weightings: - - $new = $img->convert(matrix=>[ [ 0.333, 0.333, 0.334 ] ]) - -=head2 Color Mappings - -You can use the map method to map the values of each channel of an -image independently using a list of lookup tables. It's important to -realize that the modification is made inplace. The function simply -returns the input image again or undef on failure. - -Each channel is mapped independently through a lookup table with 256 -entries. The elements in the table should not be less than 0 and not -greater than 255. If they are out of the 0..255 range they are -clamped to the range. If a table does not contain 256 entries it is -silently ignored. - -Single channels can mapped by specifying their name and the mapping -table. The channel names are C, C, C, C. - - @map = map { int( $_/2 } 0..255; - $img->map( red=>\@map ); - -It is also possible to specify a single map that is applied to all -channels, alpha channel included. For example this applies a gamma -correction with a gamma of 1.4 to the input image. - - $gamma = 1.4; - @map = map { int( 0.5 + 255*($_/255)**$gamma ) } 0..255; - $img->map(all=> \@map); - -The C map is used as a default channel, if no other map is -specified for a channel then the C map is used instead. If we -had not wanted to apply gamma to the alpha channel we would have used: - - $img->map(all=> \@map, alpha=>[]); - -Since C<[]> contains fewer than 256 element the gamma channel is -unaffected. - -It is also possible to simply specify an array of maps that are -applied to the images in the rgba order. For example to apply -maps to the C and C channels one would use: - - $img->map(maps=>[\@redmap, [], \@bluemap]); - - - -=head2 Transformations - -Another special image method is transform. It can be used to generate -warps and rotations and such features. It can be given the operations -in postfix notation or the module Affix::Infix2Postfix can be used. -Look in the test case t/t55trans.t for an example. - -transform() needs expressions (or opcodes) that determine the source -pixel for each target pixel. Source expressions are infix expressions -using any of the +, -, *, / or ** binary operators, the - unary -operator, ( and ) for grouping and the sin() and cos() functions. The -target pixel is input as the variables x and y. - -You specify the x and y expressions as xexpr and yexpr respectively. -You can also specify opcodes directly, but that's magic deep enough -that you can look at the source code. - -You can still use the transform() function, but the transform2() -function is just as fast and is more likely to be enhanced and -maintained. - -Later versions of Imager also support a transform2() class method -which allows you perform a more general set of operations, rather than -just specifying a spatial transformation as with the transform() -method, you can also perform colour transformations, image synthesis -and image combinations. - -transform2() takes an reference to an options hash, and a list of -images to operate one (this list may be empty): - - my %opts; - my @imgs; - ... - my $img = Imager::transform2(\%opts, @imgs) - or die "transform2 failed: $Imager::ERRSTR"; - -The options hash may define a transformation function, and optionally: - -=over 4 - -=item * - -width - the width of the image in pixels. If this isn't supplied the -width of the first input image is used. If there are no input images -an error occurs. - -=item * - -height - the height of the image in pixels. If this isn't supplied -the height of the first input image is used. If there are no input -images an error occurs. - -=item * - -constants - a reference to hash of constants to define for the -expression engine. Some extra constants are defined by Imager - -=back - -The tranformation function is specified using either the expr or -rpnexpr member of the options. - -=over 4 - -=item Infix expressions - -You can supply infix expressions to transform 2 with the expr keyword. - -$opts{expr} = 'return getp1(w-x, h-y)' - -The 'expression' supplied follows this general grammar: - - ( identifier '=' expr ';' )* 'return' expr - -This allows you to simplify your expressions using variables. - -A more complex example might be: - -$opts{expr} = 'pix = getp1(x,y); return if(value(pix)>0.8,pix*0.8,pix)' - -Currently to use infix expressions you must have the Parse::RecDescent -module installed (available from CPAN). There is also what might be a -significant delay the first time you run the infix expression parser -due to the compilation of the expression grammar. - -=item Postfix expressions - -You can supply postfix or reverse-polish notation expressions to -transform2() through the rpnexpr keyword. - -The parser for rpnexpr emulates a stack machine, so operators will -expect to see their parameters on top of the stack. A stack machine -isn't actually used during the image transformation itself. - -You can store the value at the top of the stack in a variable called -foo using !foo and retrieve that value again using @foo. The !foo -notation will pop the value from the stack. - -An example equivalent to the infix expression above: - - $opts{rpnexpr} = 'x y getp1 !pix @pix value 0.8 gt @pix 0.8 * @pix ifp' - -=back - -transform2() has a fairly rich range of operators. - -=over 4 - -=item +, *, -, /, %, ** - -multiplication, addition, subtraction, division, remainder and -exponentiation. Multiplication, addition and subtraction can be used -on colour values too - though you need to be careful - adding 2 white -values together and multiplying by 0.5 will give you grey, not white. - -Division by zero (or a small number) just results in a large number. -Modulo zero (or a small number) results in zero. - -=item sin(N), cos(N), atan2(y,x) - -Some basic trig functions. They work in radians, so you can't just -use the hue values. - -=item distance(x1, y1, x2, y2) - -Find the distance between two points. This is handy (along with -atan2()) for producing circular effects. - -=item sqrt(n) - -Find the square root. I haven't had much use for this since adding -the distance() function. - -=item abs(n) - -Find the absolute value. - -=item getp1(x,y), getp2(x,y), getp3(x, y) - -Get the pixel at position (x,y) from the first, second or third image -respectively. I may add a getpn() function at some point, but this -prevents static checking of the instructions against the number of -images actually passed in. - -=item value(c), hue(c), sat(c), hsv(h,s,v) - -Separates a colour value into it's value (brightness), hue (colour) -and saturation elements. Use hsv() to put them back together (after -suitable manipulation). - -=item red(c), green(c), blue(c), rgb(r,g,b) - -Separates a colour value into it's red, green and blue colours. Use -rgb(r,g,b) to put it back together. - -=item int(n) - -Convert a value to an integer. Uses a C int cast, so it may break on -large values. - -=item if(cond,ntrue,nfalse), if(cond,ctrue,cfalse) - -A simple (and inefficient) if function. - -=item <=,<,==,>=,>,!= - -Relational operators (typically used with if()). Since we're working -with floating point values the equalities are 'near equalities' - an -epsilon value is used. - -=item &&, ||, not(n) - -Basic logical operators. - -=back - -A few examples: - -=over 4 - -=item rpnexpr=>'x 25 % 15 * y 35 % 10 * getp1 !pat x y getp1 !pix @pix sat 0.7 gt @pat @pix ifp' - -tiles a smaller version of the input image over itself where the -colour has a saturation over 0.7. - -=item rpnexpr=>'x 25 % 15 * y 35 % 10 * getp1 !pat y 360 / !rat x y getp1 1 @rat - pmult @pat @rat pmult padd' - -tiles the input image over itself so that at the top of the image the -full-size image is at full strength and at the bottom the tiling is -most visible. - -=item rpnexpr=>'x y getp1 !pix @pix value 0.96 gt @pix sat 0.1 lt and 128 128 255 rgb @pix ifp' - -replace pixels that are white or almost white with a palish blue - -=item rpnexpr=>'x 35 % 10 * y 45 % 8 * getp1 !pat x y getp1 !pix @pix sat 0.2 lt @pix value 0.9 gt and @pix @pat @pix value 2 / 0.5 + pmult ifp' - -Tiles the input image overitself where the image isn't white or almost -white. - -=item rpnexpr=>'x y 160 180 distance !d y 180 - x 160 - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a2 180 * 3.1416 / 1 @a2 sin 1 + 2 / hsv' - -Produces a spiral. - -=item rpnexpr=>'x y 160 180 distance !d y 180 - x 160 - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a 180 * 3.1416 / 1 @a2 sin 1 + 2 / hsv' - -A spiral built on top of a colour wheel. - -=back - -For details on expression parsing see L. For details on -the virtual machine used to transform the images, see -L. - -=head2 Matrix Transformations - -Rather than having to write code in a little language, you can use a -matrix to perform transformations, using the matrix_transform() -method: - - my $im2 = $im->matrix_transform(matrix=>[ -1, 0, $im->getwidth-1, - 0, 1, 0, - 0, 0, 1 ]); - -By default the output image will be the same size as the input image, -but you can supply the xsize and ysize parameters to change the size. - -Rather than building matrices by hand you can use the Imager::Matrix2d -module to build the matrices. This class has methods to allow you to -scale, shear, rotate, translate and reflect, and you can combine these -with an overloaded multiplication operator. - -WARNING: the matrix you provide in the matrix operator transforms the -co-ordinates within the B image to the co-ordinates -within the I image. This can be confusing. - -Since Imager has 3 different fairly general ways of transforming an -image spatially, this method also has a yatf() alias. Yet Another -Transformation Function. - -=head2 Masked Images - -Masked images let you control which pixels are modified in an -underlying image. Where the first channel is completely black in the -mask image, writes to the underlying image are ignored. - -For example, given a base image called $img: - - my $mask = Imager->new(xsize=>$img->getwidth, ysize=>getheight, - channels=>1); - # ... draw something on the mask - my $maskedimg = $img->masked(mask=>$mask); - -You can specifiy the region of the underlying image that is masked -using the left, top, right and bottom options. - -If you just want a subset of the image, without masking, just specify -the region without specifying a mask. - -=head2 Plugins - -It is possible to add filters to the module without recompiling the -module itself. This is done by using DSOs (Dynamic shared object) -avaliable on most systems. This way you can maintain our own filters -and not have to get me to add it, or worse patch every new version of -the Module. Modules can be loaded AND UNLOADED at runtime. This -means that you can have a server/daemon thingy that can do something -like: - - load_plugin("dynfilt/dyntest.so") || die "unable to load plugin\n"; - %hsh=(a=>35,b=>200,type=>lin_stretch); - $img->filter(%hsh); - unload_plugin("dynfilt/dyntest.so") || die "unable to load plugin\n"; - $img->write(type=>'pnm',file=>'testout/t60.jpg') - || die "error in write()\n"; - -Someone decides that the filter is not working as it should - -dyntest.c modified and recompiled. - - load_plugin("dynfilt/dyntest.so") || die "unable to load plugin\n"; - $img->filter(%hsh); - -An example plugin comes with the module - Please send feedback to -addi@umich.edu if you test this. -Note: This seems to test ok on the following systems: -Linux, Solaris, HPUX, OpenBSD, FreeBSD, TRU64/OSF1, AIX. -If you test this on other systems please let me know. =head1 BUGS diff --git a/MANIFEST b/MANIFEST index 2c4e02c9..575d139c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -65,6 +65,7 @@ lib/Imager/Draw.pod lib/Imager/Transformations.pod lib/Imager/ImageTypes.pod lib/Imager/Filters.pod +lib/Imager/Engines.pod lib/Imager/Fill.pm lib/Imager/Font.pm lib/Imager/Font/Type1.pm diff --git a/lib/Imager/Engines.pod b/lib/Imager/Engines.pod new file mode 100644 index 00000000..5a33036a --- /dev/null +++ b/lib/Imager/Engines.pod @@ -0,0 +1,278 @@ +=head1 NAME + +Imager::Engines - Programmable transformation operations + +=head1 SYNOPSIS + + use Imager; + + my %opts; + my @imgs; + my $img; + ... + + my $newimg = $img->transform( + xexpr=>'x', + yexpr=>'y+10*sin((x+y)/10)') + or die $img->errstr; + + my $newimg = Imager::transform2(\%opts, @imgs) + or die "transform2 failed: $Imager::ERRSTR"; + + my $newimg = $img->matrix_transform( + matrix=>[ -1, 0, $img->getwidth-1, + 0, 1, 0, + 0, 0, 1 ]); + + +=head1 DESCRIPTION + +=head2 transform + +The C function can be used to generate spatial warps and +rotations and such effects. It only operates on a single image and +its only function is to displace pixels. + +It can be given the operations in postfix notation or the module +Affix::Infix2Postfix can be used to generate postfix code from infix +code. Look in the test case t/t55trans.t for an example. + +C needs expressions (or opcodes) that determine the +source pixel for each target pixel. Source expressions are infix +expressions using any of the +, -, *, / or ** binary operators, the - +unary operator, ( and ) for grouping and the sin() and cos() +functions. The target pixel is input as the variables x and y. + +You specify the x and y expressions as xexpr and yexpr respectively. +You can also specify opcodes directly, but that's magic deep enough +that you can look at the source code. + +Note: You can still use the transform() function, but the transform2() +function is just as fast and is more likely to be enhanced and +maintained. + + + +=head2 transform2 + +Imager also supports a C class method which allows you +perform a more general set of operations, rather than just specifying +a spatial transformation as with the transform() method, you can also +perform colour transformations, image synthesis and image +combinations from multiple source images. + +C takes an reference to an options hash, and a list of +images to operate one (this list may be empty): + + my %opts; + my @imgs; + ... + my $img = Imager::transform2(\%opts, @imgs) + or die "transform2 failed: $Imager::ERRSTR"; + +The options hash may define a transformation function, and optionally: + +=over + +=item * + +width - the width of the image in pixels. If this isn't supplied the +width of the first input image is used. If there are no input images +an error occurs. + +=item * + +height - the height of the image in pixels. If this isn't supplied +the height of the first input image is used. If there are no input +images an error occurs. + +=item * + +constants - a reference to hash of constants to define for the +expression engine. Some extra constants are defined by Imager + +=back + +The tranformation function is specified using either the expr or +rpnexpr member of the options. + +=over + +=item Infix expressions + +You can supply infix expressions to transform 2 with the expr keyword. + +$opts{expr} = 'return getp1(w-x, h-y)' + +The 'expression' supplied follows this general grammar: + + ( identifier '=' expr ';' )* 'return' expr + +This allows you to simplify your expressions using variables. + +A more complex example might be: + +$opts{expr} = 'pix = getp1(x,y); return if(value(pix)>0.8,pix*0.8,pix)' + +Currently to use infix expressions you must have the Parse::RecDescent +module installed (available from CPAN). There is also what might be a +significant delay the first time you run the infix expression parser +due to the compilation of the expression grammar. + +=item Postfix expressions + +You can supply postfix or reverse-polish notation expressions to +transform2() through the rpnexpr keyword. + +The parser for rpnexpr emulates a stack machine, so operators will +expect to see their parameters on top of the stack. A stack machine +isn't actually used during the image transformation itself. + +You can store the value at the top of the stack in a variable called +foo using !foo and retrieve that value again using @foo. The !foo +notation will pop the value from the stack. + +An example equivalent to the infix expression above: + + $opts{rpnexpr} = 'x y getp1 !pix @pix value 0.8 gt @pix 0.8 * @pix ifp' + +=back + +transform2() has a fairly rich range of operators. + +=over + +=item +, *, -, /, %, ** + +multiplication, addition, subtraction, division, remainder and +exponentiation. Multiplication, addition and subtraction can be used +on colour values too - though you need to be careful - adding 2 white +values together and multiplying by 0.5 will give you grey, not white. + +Division by zero (or a small number) just results in a large number. +Modulo zero (or a small number) results in zero. + +=item sin(N), cos(N), atan2(y,x) + +Some basic trig functions. They work in radians, so you can't just +use the hue values. + +=item distance(x1, y1, x2, y2) + +Find the distance between two points. This is handy (along with +atan2()) for producing circular effects. + +=item sqrt(n) + +Find the square root. I haven't had much use for this since adding +the distance() function. + +=item abs(n) + +Find the absolute value. + +=item getp1(x,y), getp2(x,y), getp3(x, y) + +Get the pixel at position (x,y) from the first, second or third image +respectively. I may add a getpn() function at some point, but this +prevents static checking of the instructions against the number of +images actually passed in. + +=item value(c), hue(c), sat(c), hsv(h,s,v) + +Separates a colour value into it's value (brightness), hue (colour) +and saturation elements. Use hsv() to put them back together (after +suitable manipulation). + +=item red(c), green(c), blue(c), rgb(r,g,b) + +Separates a colour value into it's red, green and blue colours. Use +rgb(r,g,b) to put it back together. + +=item int(n) + +Convert a value to an integer. Uses a C int cast, so it may break on +large values. + +=item if(cond,ntrue,nfalse), if(cond,ctrue,cfalse) + +A simple (and inefficient) if function. + +=item <=,<,==,>=,>,!= + +Relational operators (typically used with if()). Since we're working +with floating point values the equalities are 'near equalities' - an +epsilon value is used. + +=item &&, ||, not(n) + +Basic logical operators. + +=back + +A few examples: + +=over + +=item rpnexpr=>'x 25 % 15 * y 35 % 10 * getp1 !pat x y getp1 !pix @pix sat 0.7 gt @pat @pix ifp' + +tiles a smaller version of the input image over itself where the +colour has a saturation over 0.7. + +=item rpnexpr=>'x 25 % 15 * y 35 % 10 * getp1 !pat y 360 / !rat x y getp1 1 @rat - pmult @pat @rat pmult padd' + +tiles the input image over itself so that at the top of the image the +full-size image is at full strength and at the bottom the tiling is +most visible. + +=item rpnexpr=>'x y getp1 !pix @pix value 0.96 gt @pix sat 0.1 lt and 128 128 255 rgb @pix ifp' + +replace pixels that are white or almost white with a palish blue + +=item rpnexpr=>'x 35 % 10 * y 45 % 8 * getp1 !pat x y getp1 !pix @pix sat 0.2 lt @pix value 0.9 gt and @pix @pat @pix value 2 / 0.5 + pmult ifp' + +Tiles the input image overitself where the image isn't white or almost +white. + +=item rpnexpr=>'x y 160 180 distance !d y 180 - x 160 - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a2 180 * 3.1416 / 1 @a2 sin 1 + 2 / hsv' + +Produces a spiral. + +=item rpnexpr=>'x y 160 180 distance !d y 180 - x 160 - atan2 !a @d 10 / @a + 3.1416 2 * % !a2 @a 180 * 3.1416 / 1 @a2 sin 1 + 2 / hsv' + +A spiral built on top of a colour wheel. + +=back + +For details on expression parsing see L. For details on +the virtual machine used to transform the images, see +L. + + +=head2 Matrix Transformations + +Rather than having to write code in a little language, you can use a +matrix to perform affine transformations, using the matrix_transform() +method: + + my $newimg = $img->matrix_transform(matrix=>[ -1, 0, $img->getwidth-1, + 0, 1, 0, + 0, 0, 1 ]); + +By default the output image will be the same size as the input image, +but you can supply the xsize and ysize parameters to change the size. + +Rather than building matrices by hand you can use the Imager::Matrix2d +module to build the matrices. This class has methods to allow you to +scale, shear, rotate, translate and reflect, and you can combine these +with an overloaded multiplication operator. + +WARNING: the matrix you provide in the matrix operator transforms the +co-ordinates within the B image to the co-ordinates +within the I image. This can be confusing. + +Since Imager has 3 different fairly general ways of transforming an +image spatially, this method also has a yatf() alias. Yet Another +Transformation Function. + +=cut diff --git a/lib/Imager/ImageTypes.pod b/lib/Imager/ImageTypes.pod index 261dd82f..09a68251 100644 --- a/lib/Imager/ImageTypes.pod +++ b/lib/Imager/ImageTypes.pod @@ -320,6 +320,32 @@ RGB image with: $rgbimg = $img->to_rgb8; + +=head2 Masked Images + +Masked images let you control which pixels are modified in an +underlying image. Where the first channel is completely black in the +mask image, writes to the underlying image are ignored. + +For example, given a base image called $img: + + my $mask = Imager->new(xsize=>$img->getwidth, ysize=>getheight, + channels=>1); + # ... draw something on the mask + my $maskedimg = $img->masked(mask=>$mask); + +You can specifiy the region of the underlying image that is masked +using the left, top, right and bottom options. + +If you just want a subset of the image, without masking, just specify +the region without specifying a mask. + + + + + + + =head2 Tags Image tags contain meta-data about the image, ie. information not @@ -399,3 +425,7 @@ If this tag is present then the whole image could not be read. This isn't implemented for all images yet. =back + + + + diff --git a/lib/Imager/Transformations.pod b/lib/Imager/Transformations.pod index ee4431b1..b3f98f5f 100644 --- a/lib/Imager/Transformations.pod +++ b/lib/Imager/Transformations.pod @@ -23,11 +23,29 @@ Imager::Transformations - Simple transformations of one image into another. $img->flip(dir=>"h"); # horizontal flip $img->flip(dir=>"vh"); # vertical and horizontal flip - $nimg = $img->copy->flip(dir=>"v"); # make a copy and flip it vertically + $newimg = $img->copy->flip(dir=>"v"); # make a copy and flip it vertically my $rot20 = $img->rotate(degrees=>20); my $rotpi4 = $img->rotate(radians=>3.14159265/4); + + # Convert image to gray + $new = $img->convert(preset=>'grey'); + + # Swap red/green channel + $new = $img->convert(matrix=>[ [ 0, 1, 0 ], + [ 1, 0, 0 ], + [ 0, 0, 1 ] ]); + + # limit the range of red channel from 0..255 to 0..127 + @map = map { int( $_/2 } 0..255; + $img->map( red=>\@map ); + + # Apply a Gamma of 1.4 + my $gamma = 1.4; + my @map = map { int( 0.5 + 255*($_/255)**$gamma ) } 0..255; + $img->map(all=>\@map); # inplace conversion + =head1 DESCRIPTION The methods described in Imager::Transformations fall into two categories. @@ -172,7 +190,161 @@ parameter which can take the values C, C, C and C. +=head2 Color transformations + +You can use the convert method to transform the color space of an +image using a matrix. For ease of use some presets are provided. + +The convert method can be used to: + +=over + +=item * + +convert an RGB or RGBA image to grayscale. + +=item * + +convert a grayscale image to RGB. + +=item * + +extract a single channel from an image. + +=item * + +set a given channel to a particular value (or from another channel) + +=back + +The currently defined presets are: + +=over + +=item gray + +=item grey + +converts an RGBA image into a grayscale image with alpha channel, or +an RGB image into a grayscale image without an alpha channel. + +This weights the RGB channels at 22.2%, 70.7% and 7.1% respectively. + +=item noalpha + +removes the alpha channel from a 2 or 4 channel image. An identity +for other images. + +=item red + +=item channel0 + +extracts the first channel of the image into a single channel image + +=item green + +=item channel1 + +extracts the second channel of the image into a single channel image + +=item blue + +=item channel2 + +extracts the third channel of the image into a single channel image + +=item alpha + +extracts the alpha channel of the image into a single channel image. + +If the image has 1 or 3 channels (assumed to be grayscale of RGB) then +the resulting image will be all white. + +=item rgb + +converts a grayscale image to RGB, preserving the alpha channel if any + +=item addalpha + +adds an alpha channel to a grayscale or RGB image. Preserves an +existing alpha channel for a 2 or 4 channel image. + +=back + +For example, to convert an RGB image into a greyscale image: + + $new = $img->convert(preset=>'grey'); # or gray + +or to convert a grayscale image to an RGB image: + + $new = $img->convert(preset=>'rgb'); + +The presets aren't necessary simple constants in the code, some are +generated based on the number of channels in the input image. + +If you want to perform some other colour transformation, you can use +the 'matrix' parameter. + +For each output pixel the following matrix multiplication is done: + + | channel[0] | | $c00, ..., $c0k | | inchannel[0] | + | ... | = | ... | x | ... | + | channel[k] | | $ck0, ..., $ckk | | inchannel[k] | + 1 +Where C. + +So if you want to swap the red and green channels on a 3 channel image: + + $new = $img->convert(matrix=>[ [ 0, 1, 0 ], + [ 1, 0, 0 ], + [ 0, 0, 1 ] ]); + +or to convert a 3 channel image to greyscale using equal weightings: + + $new = $img->convert(matrix=>[ [ 0.333, 0.333, 0.334 ] ]) + + +=head2 Color Mappings + +You can use the map method to map the values of each channel of an +image independently using a list of lookup tables. It's important to +realize that the modification is made inplace. The function simply +returns the input image again or undef on failure. + +Each channel is mapped independently through a lookup table with 256 +entries. The elements in the table should not be less than 0 and not +greater than 255. If they are out of the 0..255 range they are +clamped to the range. If a table does not contain 256 entries it is +silently ignored. + +Single channels can mapped by specifying their name and the mapping +table. The channel names are C, C, C, C. + + @map = map { int( $_/2 } 0..255; + $img->map( red=>\@map ); + +It is also possible to specify a single map that is applied to all +channels, alpha channel included. For example this applies a gamma +correction with a gamma of 1.4 to the input image. + + $gamma = 1.4; + @map = map { int( 0.5 + 255*($_/255)**$gamma ) } 0..255; + $img->map(all=> \@map); + +The C map is used as a default channel, if no other map is +specified for a channel then the C map is used instead. If we +had not wanted to apply gamma to the alpha channel we would have used: + + $img->map(all=> \@map, alpha=>[]); + +Since C<[]> contains fewer than 256 element the gamma channel is +unaffected. + +It is also possible to simply specify an array of maps that are +applied to the images in the rgba order. For example to apply +maps to the C and C channels one would use: + $img->map(maps=>[\@redmap, [], \@bluemap]);