]> git.imager.perl.org - imager.git/blobdiff - lib/Imager/Cookbook.pod
skip t/x30podlinkcheck.t if Pod::Parser 1.50 not available
[imager.git] / lib / Imager / Cookbook.pod
index 6ec76ab980c8151160d0b76852278f7bf69d409a..ad7af17e46bfaa4ee218c2c4e06f06dc2e8cfce2 100644 (file)
@@ -22,7 +22,7 @@ See L<Imager::Files>.
 
   $image->write(file=>$filename) or die $image->errstr;
 
-=head2 Write an animated gif.
+=head2 Write an animated GIF
 
   # build an array of images to use in the gif
   my  @images;
@@ -44,6 +44,66 @@ the L<read_multi()|Imager::Files> method to read them:
   my @images = Imager->read_multi(file=>$filename)
     or die Imager->errstr;
 
+=head2 Converting from one file format to another
+
+This is as simple as reading the original file and writing the new
+file, for single images:
+
+  my $image = Imager->new;
+  # Imager auto-detects the input file type
+  $image->read(file => $input_filename)
+    or die $image->errstr;
+  # Imager derives the output file format from the filename
+  $image->write(file => $output_filename)
+    or die $image->errstr;
+
+  # or you can supply a type parameter:
+  $image->write(file => $output_filename, type => 'gif')
+    or die $image->errstr;
+
+The main issue that can occur with this is if the input file has
+transparency and the output file format doesn't support that.  This
+can be a problem when converting from GIF files to JPEG files for
+example.
+
+By default, if the output format doesn't support transparency, Imager
+will compose the image onto a black background.  You can override that
+by supplying an C<i_background> option to C<write()> or
+C<write_multi()>:
+
+  $image->write(file => "foo.jpg", i_background => "#808080")
+    or die $image->errstr;
+
+Some formats support multiple files, so if you want to convert from
+say TIFF to JPEG, you'll need multiple output files:
+
+  my @images = Imager->read_multi(file => 'input.tif')
+    or die Imager->errstr;
+  my $index = 1;
+  for my $image (@images) {
+    $image->write(file => sprintf('output%02d.jpg', $index++))
+      or die $image->errstr;
+  }
+
+=head2 Transparent PNG
+
+To save to a transparent PNG (or GIF or TIFF) you need to start with
+an image with transparency.
+
+To make a transparent image, create an image object with 2 or 4
+channels:
+
+  # RGB with alpha channel
+  my $rgba = Imager->new(xsize => $width, ysize => $height, channels => 4);
+
+  # Gray with alpha channel
+  my $graya = Imager->new(xsize => $width, ysize => $height, channels => 2);
+
+By default, the created image will be transparent.
+
+Otherwise, if you have an existing image file with transparency,
+simply read it, and the transparency will be preserved.
+
 =head1 IMAGE SYNTHESIS
 
 =head2 Creating an image
@@ -57,11 +117,11 @@ If you also want an alpha channel:
 
   my $rgb_alpha = Imager->new(xsize=>$width, ysize=>$height, channels=>4);
 
-To make a grayscale image:
+To make a gray-scale image:
 
   my $gray = Imager->new(xsize=>$width, ysize=>$height, channels=>1);
 
-and a grayscale image with an alpha channel:
+and a gray-scale image with an alpha channel:
 
   my $gray_alpha = Imager->new(xsize=>$width, ysize=>$height, channels=>2);
 
@@ -122,6 +182,7 @@ This is similar to writing to a file, but you also need to supply the
 information needed by the web browser to identify the file format:
 
   my $img = ....; # create the image and generate the contents
+  ++$|; # make sure the content type isn't buffered
   print "Content-Type: image/png\n\n";
   binmode STDOUT;
   $img->write(fd=>fileno(STDOUT), type=>'png')
@@ -169,10 +230,7 @@ C<WARNING>: file format attacks have become a common attack vector,
 make sure you have up to date image file format libraries, otherwise
 trying to parse uploaded files, whether with Imager or some other
 tool, may result in a remote attacker being able to run their own code
-on your system.  Currently Imager makes no attempt to place size
-limits on a read image file.  This may result in consumption of large
-amounts of memory.  Future versions of Imager may provide mechanisms
-to limit the sizes of images read from files.
+on your system.
 
 If your HTML form uses the correct magic, it can upload files to your
 CGI script, in particular, you need to use C< method="post" > and
@@ -226,8 +284,49 @@ have Imager read the image
 See C<samples/samp-scale.cgi> and C<samples/samp-tags.cgi> in the
 Imager distribution for example code.
 
+You may also want to set limits on the size of the image read, using
+Imager's C<set_file_limits> method, documented in
+L<Imager::Files/set_file_limits()>.  For example:
+
+  # limit to 10 million bytes of memory usage
+  Imager->set_file_limits(bytes => 10_000_000);
+
+  # limit to 1024 x 1024
+  Imager->set_file_limits(width => 1024, height => 1024);
+
 =head1 DRAWING
 
+=head2 Adding a border to an image
+
+First make a new image with space for the border:
+
+  my $border_width = ...;
+  my $border_height = ...;
+  my $out = Imager->new(xsize => $source->getwidth() + 2 * $border_width,
+                        ysize => $source->getheight() + 2 * $border_height,
+                        bits => $source->bits,
+                        channels => $source->getchannels);
+
+Then paste the source image into the new image:
+
+  $out->paste(left => $border_width,
+              top => $border_height,
+              img => $source);
+
+Whether you draw the border before or after pasting the original image
+depends on whether you want the border to overlap the image, for
+example a semi-transparent border drawn after pasting the source image
+could overlap the edge without hiding it.
+
+If you want a solid border you could just fill the image before
+pasting the source for simplicity:
+
+  $out->box(filled=>1, color=>'red');
+  $out->paste(left => $border_width,
+              top => $border_height,
+              img => $source);
+
+
 =head1 TEXT
 
 =head2 Drawing text
@@ -238,12 +337,118 @@ Imager distribution for example code.
 
 =head2 Word wrapping text
 
+=head2 Shearing (slanting) or Rotating text
+
+This requires that you have Imager installed with FreeType 2.x support
+installed, and that the font be created using the FreeType 2.x driver,
+for example:
+
+  my $font = Imager::Font->new(file=>$fontfile, type=>'ft2');
+
+First you need a transformation matrix, for shearing that could be:
+
+  my $angle_in_radians = ...;
+  my $tan_angle = sin($angle_rads) / cos($angle_rads);
+  # shear horizontally, supply this as y instead to do it vertically
+  my $matrix = Imager::Matrix2d->shear(x=>$tan_angle);
+
+For rotation that would be:
+
+  my $matrix = Imager::Matrix2d->rotate(radians => $angle_in_radians);
+
+or:
+
+  my $matrix = Imager::Matrix2d->rotate(degrees => $angle_in_degrees);
+
+Feed that to the font object:
+
+  $font->transform(matrix => $matrix);
+
+and draw the text as normal:
+
+  $image->string(string => $text,
+                 x => $where_x,
+                 y => $where_y,
+                 color => $color,
+                 font => $font);
+
+See samples/slant_text.pl for a comprehensive example, including
+calculating the transformed bounding box to create an image to fit the
+transformed text into.
+
+=head1 IMAGE TRANSFORMATION
+
+=head2 Shearing an image
+
+=head2 Convert to gray-scale
+
+To convert an RGB image to a gray-scale image, use the convert method:
+
+  my $grey = $image->convert(preset => 'gray');
+
+convert() returns a new image.
+
+See: L<Imager::Transformations/"Color transformations">
+
 =head1 METADATA
 
-=head2 Image spatial resolution.
+=head2 Image format
+
+When Imager reads a file it does a magic number check to determine the
+file type, so C<foo.png> could actually be a GIF image, and Imager
+will read it anyway.
+
+You can check the actual format of the image by looking at the
+C<i_format> tag.
+
+  my $format = $image->tags(name=>'i_format');
+
+=head2 Image spatial resolution
+
+Most image file formats store information about the physical size of
+the pixels, though in some cases that information isn't useful.
+
+Imager stores this information in the tags C<i_xres> and C<i_yres>,
+and this is always stored in dots per inch.
+
+Some formats, including TIFF and JPEG allow you to change the units
+spatial resolution information is stored in, if you set the tag that
+changes this the Imager will convert C<i_xres> and C<i_yres> to those
+units when it writes the file.
+
+For example to set the resolution to 300 dpi:
+
+  $image->settag(name => 'i_xres', value => 300);
+  $image->settag(name => 'i_yres', value => 300);
+
+If you want the file format to store the resolution in some other
+unit, for example you can write a TIFF file that stores the resolution
+in pixels per centimeter, you would do:
+
+  # 150 pixels/cm
+  $image->settag(name => 'i_xres', value => 150 * 2.54);
+  $image->settag(name => 'i_yres', value => 150 * 2.54);
+  $image->settag(name => 'tiff_resolutionunit', value => 3);
 
 Keywords: DPI
 
+=head1 IMAGE MANIPULATION
+
+=head2 Replacing a color with transparency
+X<replacing colors>
+
+To replace a color with transparency you can use the
+L<Imager::Filters/difference()> method.
+
+  # make a work image the same size as our input
+  my $work = Imager->new(xsize => $in->getwidth, ysize => $in->getheight,
+                         channels => $in->getchannels);
+  # and fill it with the colour we want transparent
+  $work->box(filled => 1, color => $color);
+
+  # get an image with that colour replaced with transparent black
+  my $out = $work->difference(other => $in);
+
 =head1 AUTHOR
 
 Tony Cook <tony@develop-help.com>