1Imager::Cookbook(3) User Contributed Perl Documentation Imager::Cookbook(3)
2
3
4
6 Imager::Cookbook - recipes working with Imager
7
9 Various simple and not so simple ways to do things with Imager.
10
12 This is described in detail in Imager::Files.
13
14 Reading an image from a file
15 my $image = Imager->new;
16
17 $image->read(file=>$filename) or die $image->errstr;
18
19 Or:
20
21 my $image = Imager->new(file => $filename)
22 or die Imager->errstr;
23
24 See Imager::Files.
25
26 Writing an image to a file
27 $image->write(file=>$filename) or die $image->errstr;
28
29 Write an animated GIF
30 # build an array of images to use in the gif
31 my @images;
32 # synthesize the images or read them from files, it doesn't matter
33 ...
34
35 # write the gif
36 Imager->write_multi({ file=>$filename, type=>'gif' }, @images)
37 or die Imager->errstr;
38
39 See "Writing an animated GIF" in Imager::Files for a more detailed
40 example.
41
42 Reading multiple images from one file
43 Some formats, like GIF and TIFF support multiple images per file. Use
44 the read_multi() method to read them:
45
46 my @images = Imager->read_multi(file=>$filename)
47 or die Imager->errstr;
48
49 Converting from one file format to another
50 This is as simple as reading the original file and writing the new
51 file, for single images:
52
53 my $image = Imager->new;
54 # Imager auto-detects the input file type
55 $image->read(file => $input_filename)
56 or die $image->errstr;
57 # Imager derives the output file format from the filename
58 $image->write(file => $output_filename)
59 or die $image->errstr;
60
61 # or you can supply a type parameter:
62 $image->write(file => $output_filename, type => 'gif')
63 or die $image->errstr;
64
65 The main issue that can occur with this is if the input file has
66 transparency and the output file format doesn't support that. This can
67 be a problem when converting from GIF files to JPEG files for example.
68
69 By default, if the output format doesn't support transparency, Imager
70 will compose the image onto a black background. You can override that
71 by supplying an "i_background" option to write() or write_multi():
72
73 $image->write(file => "foo.jpg", i_background => "#808080")
74 or die $image->errstr;
75
76 Some formats support multiple files, so if you want to convert from say
77 TIFF to JPEG, you'll need multiple output files:
78
79 my @images = Imager->read_multi(file => 'input.tif')
80 or die Imager->errstr;
81 my $index = 1;
82 for my $image (@images) {
83 $image->write(file => sprintf('output%02d.jpg', $index++))
84 or die $image->errstr;
85 }
86
87 Transparent PNG
88 To save to a transparent PNG (or GIF or TIFF) you need to start with an
89 image with transparency.
90
91 To make a transparent image, create an image object with 2 or 4
92 channels:
93
94 # RGB with alpha channel
95 my $rgba = Imager->new(xsize => $width, ysize => $height, channels => 4);
96
97 # Gray with alpha channel
98 my $graya = Imager->new(xsize => $width, ysize => $height, channels => 2);
99
100 By default, the created image will be transparent.
101
102 Otherwise, if you have an existing image file with transparency, simply
103 read it, and the transparency will be preserved.
104
106 Creating an image
107 To create a simple RGB image, supply the image width and height to the
108 new() method:
109
110 my $rgb = Imager->new(xsize=>$width, ysize=>$height);
111
112 If you also want an alpha channel:
113
114 my $rgb_alpha = Imager->new(xsize=>$width, ysize=>$height, channels=>4);
115
116 To make a gray-scale image:
117
118 my $gray = Imager->new(xsize=>$width, ysize=>$height, channels=>1);
119
120 and a gray-scale image with an alpha channel:
121
122 my $gray_alpha = Imager->new(xsize=>$width, ysize=>$height, channels=>2);
123
124 When a new image is created this way all samples are set to zero -
125 black for 1 or 3 channel images, transparent black for 2 or 4 channel
126 images.
127
128 You can also create paletted images and images with more than 8-bits
129 per channel, see Imager::ImageTypes for more details.
130
131 Setting the background of a new image
132 To set the background of a new image to a solid color, use the box()
133 method with no limits, and "filled=>1":
134
135 $image->box(filled=>1, color=>$color);
136
137 As always, a color can be specified as an Imager::Color object:
138
139 my $white = Imager::Color->new(255, 255, 255);
140 $image->box(filled=>1, color=>$white);
141
142 or you supply any single scalar that Imager::Color's new() method
143 accepts as a color description:
144
145 $image->box(filled=>1, color=>'white');
146 $image->box(filled=>1, color=>'#FF0000');
147 $image->box(filled=>1, color=>[ 255, 255, 255 ]);
148
149 You can also fill the image with a fill object:
150
151 use Imager::Fill;
152 # create the fill object
153 my $fill = Imager::Fill->new(hatch=>'check1x1')
154 $image->box(fill=>$fill);
155
156 # let Imager create one automatically
157 $image->box(fill=>{ hatch=>'check1x1' });
158
159 See Imager::Fill for information on Imager's fill objects.
160
161 Create an image from raw RGB data
162 If your data matches the layout supported by Imager's "RAW" in
163 Imager::Files file support closely enough, you can simply read the data
164 as if it was a raw file:
165
166 my $img = Imager->new(
167 (
168 filetype => "raw",
169 xsize => $width,
170 ysize => $height,
171 # stored as RGBXRGBX where X is dropped
172 raw_interleave => 0,
173 raw_datachannels => 4,
174 raw_storechannels => 3,
175 );
176
177 If the channel order doesn't match you can further use the "combine()"
178 in Imager::Transformations method to extract the channels in the
179 correct order, eg. if the source data above was in "BGRX" format
180 instead of "RGBX":
181
182 my $img2 = $im->combine(src => [ $img, $img, $img ],
183 channels => [ 2, 1, 0 ]);
184
185 Adapted from perl monks <https://perlmonks.org/?node_id=11139983>.
186
187 For more control you can use the setsamples() method to set pixels
188 directly to the image:
189
190 # for AGBR data in $data
191 my $img = Imager->new(xsize => $width, ysize => $height, channels => 4);
192 my $rowbytes = $width * 4;
193 my @chans = [ 3, 1, 2, 0 ];
194 for my $row (0 .. $height) {
195 $img->setsamples
196 (
197 y => $row,
198 data => $data,
199 offset => $rowbytes * $row,
200 channels => \@chans,
201 type => '8bit',
202 );
203 }
204
206 As with any CGI script it's up to you to validate data and set limits
207 on any parameters supplied to Imager.
208
209 For example, if you allow the caller to set the size of an output image
210 you should limit the size to prevent the client from specifying an
211 image size that will consume all available memory.
212
213 This is beside any other controls you need over access to data.
214
215 See CGI for a module useful for processing CGI submitted data.
216
217 Returning an image from a CGI script
218 This is similar to writing to a file, but you also need to supply the
219 information needed by the web browser to identify the file format:
220
221 my $img = ....; # create the image and generate the contents
222 ++$|; # make sure the content type isn't buffered
223 print "Content-Type: image/png\n\n";
224 binmode STDOUT;
225 $img->write(fd=>fileno(STDOUT), type=>'png')
226 or die $img->errstr;
227
228 You need to set the Content-Type header depending on the file format
229 you send to the web browser.
230
231 If you want to supply a content-length header, write the image to a
232 scalar as a buffer:
233
234 my $img = ....; # create the image and generate the contents
235 my $data;
236 $img->write(type=>'png', data=>\$data)
237 or die $img->errstr;
238 print "Content-Type: image/png\n";
239 print "Content-Length: ",length($data),"\n\n";
240 binmode STDOUT;
241 print $data;
242
243 See "samples/samp-scale.cgi" and "samples/samp-image.cgi" for a couple
244 of simple examples of producing an image from CGI.
245
246 Inserting a CGI image in a page
247 There's occasionally confusion on how to display an image generated by
248 Imager in a page generated by a CGI.
249
250 Your web browser handles this process as two requests, one for the HTML
251 page, and another for the image itself.
252
253 Each request needs to perform validation since an attacker can control
254 the values supplied to both requests.
255
256 How you make the data available to the image generation code depends on
257 your application.
258
259 See "samples/samp-form.cgi" and "samples/samp-image.cgi" in the Imager
260 distribution for one approach. The POD in "samp-form.cgi" also
261 discusses some of the issues involved.
262
263 Parsing an image posted via CGI
264 "WARNING": file format attacks have become a common attack vector, make
265 sure you have up to date image file format libraries, otherwise trying
266 to parse uploaded files, whether with Imager or some other tool, may
267 result in a remote attacker being able to run their own code on your
268 system.
269
270 If your HTML form uses the correct magic, it can upload files to your
271 CGI script, in particular, you need to use " method="post" " and
272 "enctype="multipart/form-data"" in the "form" tag, and use
273 "type="file"" in the "input", for example:
274
275 <form action="/cgi-bin/yourprogram" method="post"
276 enctype="multipart/form-data">
277 <input type="file" name="myimage" />
278 <input type="submit value="Upload Image" />
279 </form>
280
281 To process the form:
282
283 1. first check that the user supplied a file
284
285 2. get the file handle
286
287 3. have Imager read the image
288
289 # returns the client's name for the file, don't open this locally
290 my $cgi = CGI->new;
291 # 1. check the user supplied a file
292 my $filename = $cgi->param('myimage');
293 if ($filename) {
294 # 2. get the file handle
295 my $fh = $cgi->upload('myimage');
296 if ($fh) {
297 binmode $fh;
298
299 # 3. have Imager read the image
300 my $img = Imager->new;
301 if ($img->read(fh=>$fh)) {
302 # we can now process the image
303 }
304 }
305 # else, you probably have an incorrect form or input tag
306 }
307 # else, the user didn't select a file
308
309 See "samples/samp-scale.cgi" and "samples/samp-tags.cgi" in the Imager
310 distribution for example code.
311
312 You may also want to set limits on the size of the image read, using
313 Imager's "set_file_limits" method, documented in "set_file_limits()" in
314 Imager::Files. For example:
315
316 # limit to 10 million bytes of memory usage
317 Imager->set_file_limits(bytes => 10_000_000);
318
319 # limit to 1024 x 1024
320 Imager->set_file_limits(width => 1024, height => 1024);
321
323 Adding a border to an image
324 First make a new image with space for the border:
325
326 my $border_width = ...;
327 my $border_height = ...;
328 my $out = Imager->new(xsize => $source->getwidth() + 2 * $border_width,
329 ysize => $source->getheight() + 2 * $border_height,
330 bits => $source->bits,
331 channels => $source->getchannels);
332
333 Then paste the source image into the new image:
334
335 $out->paste(left => $border_width,
336 top => $border_height,
337 img => $source);
338
339 Whether you draw the border before or after pasting the original image
340 depends on whether you want the border to overlap the image, for
341 example a semi-transparent border drawn after pasting the source image
342 could overlap the edge without hiding it.
343
344 If you want a solid border you could just fill the image before pasting
345 the source for simplicity:
346
347 $out->box(filled=>1, color=>'red');
348 $out->paste(left => $border_width,
349 top => $border_height,
350 img => $source);
351
353 Drawing text
354 Aligning text
355 Measuring text
356 Word wrapping text
357 Shearing (slanting) or Rotating text
358 This requires that you have Imager installed with FreeType 2.x support
359 installed, and that the font be created using the FreeType 2.x driver,
360 for example:
361
362 my $font = Imager::Font->new(file=>$fontfile, type=>'ft2');
363
364 First you need a transformation matrix, for shearing that could be:
365
366 my $angle_in_radians = ...;
367 my $tan_angle = sin($angle_rads) / cos($angle_rads);
368 # shear horizontally, supply this as y instead to do it vertically
369 my $matrix = Imager::Matrix2d->shear(x=>$tan_angle);
370
371 For rotation that would be:
372
373 my $matrix = Imager::Matrix2d->rotate(radians => $angle_in_radians);
374
375 or:
376
377 my $matrix = Imager::Matrix2d->rotate(degrees => $angle_in_degrees);
378
379 Feed that to the font object:
380
381 $font->transform(matrix => $matrix);
382
383 and draw the text as normal:
384
385 $image->string(string => $text,
386 x => $where_x,
387 y => $where_y,
388 color => $color,
389 font => $font);
390
391 See samples/slant_text.pl for a comprehensive example, including
392 calculating the transformed bounding box to create an image to fit the
393 transformed text into.
394
396 Shearing an image
397 Convert to gray-scale
398 To convert an RGB image to a gray-scale image, use the convert method:
399
400 my $grey = $image->convert(preset => 'gray');
401
402 convert() returns a new image.
403
404 See: "Color transformations" in Imager::Transformations
405
407 Image format
408 When Imager reads a file it does a magic number check to determine the
409 file type, so "foo.png" could actually be a GIF image, and Imager will
410 read it anyway.
411
412 You can check the actual format of the image by looking at the
413 "i_format" tag.
414
415 my $format = $image->tags(name=>'i_format');
416
417 Image spatial resolution
418 Most image file formats store information about the physical size of
419 the pixels, though in some cases that information isn't useful.
420
421 Imager stores this information in the tags "i_xres" and "i_yres", and
422 this is always stored in dots per inch.
423
424 Some formats, including TIFF and JPEG allow you to change the units
425 spatial resolution information is stored in, if you set the tag that
426 changes this the Imager will convert "i_xres" and "i_yres" to those
427 units when it writes the file.
428
429 For example to set the resolution to 300 dpi:
430
431 $image->settag(name => 'i_xres', value => 300);
432 $image->settag(name => 'i_yres', value => 300);
433
434 If you want the file format to store the resolution in some other unit,
435 for example you can write a TIFF file that stores the resolution in
436 pixels per centimeter, you would do:
437
438 # 150 pixels/cm
439 $image->settag(name => 'i_xres', value => 150 * 2.54);
440 $image->settag(name => 'i_yres', value => 150 * 2.54);
441 $image->settag(name => 'tiff_resolutionunit', value => 3);
442
443 Keywords: DPI
444
446 Replacing a color with transparency
447 To replace a color with transparency you can use the "difference()" in
448 Imager::Filters method.
449
450 # make a work image the same size as our input
451 my $work = Imager->new(xsize => $in->getwidth, ysize => $in->getheight,
452 channels => $in->getchannels);
453 # and fill it with the color we want transparent
454 $work->box(filled => 1, color => $color);
455
456 # get an image with that color replaced with transparent black
457 my $out = $work->difference(other => $in);
458
460 Drop Shadows
461 This can be used for a glow effect as well.
462
463 First create a new image, either with an alpha channel (if you want
464 transparency behind the shadow) or without, if you want a background
465 color:
466
467 my $out = Imager->new
468 (
469 xsize => $shadow_size * 2 + $src->getwidth,
470 ysize => $shadow_size * 2 + $src->getheight,
471 channels => 4,
472 );
473 # fill it with your background color, if you want one
474 # $out->box(filled => 1, color => $back_color);
475
476 Make a work image to render the shadow on:
477
478 my $shadow_work = Imager->new
479 (
480 xsize => $back->getwidth,
481 ysize => $back->getheight,
482 channels => 1,
483 );
484
485 Extract the alpha channel from the source image, first the alpha
486 version:
487
488 my $alpha = $src->convert(preset => "alpha");
489
490 and draw that on the work shadow:
491
492 $shadow_work->paste
493 (
494 src => $slpha,
495 left => $shadow_size,
496 top => $shadow_size,
497 );
498
499 otherwise just draw a box for the non-alpha source:
500
501 $shadow_work->box
502 (
503 filled => 1,
504 color => [ 255 ],
505 xmin => $shadow_size,
506 ymin => $shadow_size,
507 xmax => $shadow_size + $src->getwidth() - 1,
508 ymax => $shadow_size + $src->getheight() - 1,
509 );
510
511 Blur the work shadow:
512
513 $shadow_work->filter(type => "gaussian", stddev => $shadow_size);
514
515 Convert it to an RGB image with alpha:
516
517 $shadow_work = $shadow_work->convert
518 (
519 matrix => [ [ 0, $red / 255 ],
520 [ 0, $green / 255 ],
521 [ 0, $blue / 255 ],
522 [ 1 ] ]
523 );
524
525 Draw that on the output image:
526
527 $out->rubthrough(src => $shadow_work);
528
529 Draw our original image on the output image, perhaps with an offset:
530
531 $out->rubthrough
532 (
533 src => $src,
534 tx => $shadow_size + $x_offset,
535 ty => $shadow_size + $y_offset,
536 );
537
538 See samples/drop_shadow.pl for an example of this recipe.
539
541 Tony Cook <tony@develop-help.com>
542
544 Imager, Imager::Files, Imager::Draw.
545
546
547
548perl v5.36.0 2023-01-20 Imager::Cookbook(3)