Codebase list libimager-perl / 23e7e76
[svn-upgrade] Integrating new upstream version, libimager-perl (0.56) Gregor Herrmann 17 years ago
111 changed file(s) with 3705 addition(s) and 5206 deletion(s). Raw diff Collapse all Expand all
+215
-1321
Changes less more
0 ------------------------------------------------------------------------
1 r1098 | tony | 2006-09-14 17:43:24 +1000 (Thu, 14 Sep 2006) | 29 lines
2 Changed paths:
3 M /trunk/Imager/Imager.pm
4 M /trunk/Imager/META.yml
5 A /trunk/Imager/announce/0.54.txt
0 Imager release history. Older releases can be found in Changes.old
1
2 Imager 0.56 -
3 ===========
4
5 - added support for reading 16-bit/sample PGM/PPM images
6
7 - added support for writing 16-bit/sample PGM/PPM images
8
9 - improved performance of reading PBM/PGM/PPM images
10
11 - added support for writing PBM images if the image is paletted and
12 contains only black and white
13
14 - added a new make_colors value - "mono"
15
16 - switched from the svn log Changes to a manual Changes to reduce
17 noise
18
19 - new sample code - samples/flasher.pl
20
21 Bug fixes:
22
23 - CRITICAL: the "Imager" typemap entry (not used by Imager itself)
24 was returning an image object with an extra reference, this
25 resulted in a memory leak.
26 http://rt.cpan.org/Ticket/Display.html?id=24992
27
28 - fix rendering on alpha channel images for the FreeType 2.x driver
29 http://rt.cpan.org/Ticket/Display.html?id=11972
30
31 - reading bmp files now consitently handles short reads. You can now
32 supply a parameter to treat a short read as successful and set
33 i_incomplete
34 http://rt.cpan.org/Ticket/Display.html?id=8426
35
36 - previously, reading ASCII PBM files required spaces between samples,
37 even though the format doesn't require that
38
39 - improved documentation of the unsharpmask filter (I hope)
40 http://rt.cpan.org/Ticket/Display.html?id=25531
41
42 - force flushing of the output from i_tt_dump_names() and test output
43 in t/t35ttfont.t to prevent output from being mixed up.
44 https://rt.cpan.org/Ticket/Display.html?id=24859
45
46 - rewrite a conditional expression as an if() to hopefully work around
47 a bug in the pre-4.0 GCC Apple shipped with OS X 10.4.
48 https://rt.cpan.org/Ticket/Display.html?id=25561
49
50 - avoid Data::Dumper in regops.perl to support older releases of perl
51 https://rt.cpan.org/Ticket/Display.html?id=24391
52
53 Imager 0.55 - 16 Dec 2006
54 ===========
55
56 This is primarily a bug fix release.
57
58 Note: Test::More is now a pre-requisite for Imager and is no longer bundled.
59
60 There is one new feature:
61
62 - the Win32 font driver now supports UTF8 (RT 22166)
63 http://www.cpanforum.com/threads/3276
64 http://rt.cpan.org/Ticket/Display.html?id=22166
65
66 Several bugs were fixed:
67
68 - the string() method would not output the string "0"
69 http://rt.cpan.org/Public/Bug/Display.html?id=21770
70
71 - fills.c was failing to compile on Solaris 10 (compiler unknown)
72 http://rt.cpan.org/Public/Bug/Display.html?id=21944
73
74 - the gif_disposal and gif_user_input tags weren't being read from
75 the file correctly
76 http://rt.cpan.org/Public/Bug/Display.html?id=22192
77
78 - gif.c was failing to build under MSVC
79 http://rt.cpan.org/Ticket/Display.html?id=23922
80
81 - in some cases strings passed to the string() method were treated as
82 terminated by NUL (chr 0)
83 http://rt.cpan.org/Public/Bug/Display.html?id=21770
84
85 - on "MSWin32" perl builds we now link to -lzlib instead of -lz since
86 that's the default build name for zlib on Win32.
87 http://rt.cpan.org/Ticket/Display.html?id=23064
88
89 - search $Config{incpath} for headers too, which we should have been
90 doing all along.
91
92 Win32 font driver fixes:
93
94 - the global descent value from bounding box was the wrong sign
95 http://www.cpanforum.com/threads/3276
96
97 - if the first or last glyph overflowed the left or right side of the
98 advance width they would be clipped
99
100
101 Imager 0.54 - 14 Sep 2006
102 ===========
6103
7104 This is primarily a feature release:
8105
9 - a new qtype value 'mixing' has been added to the scale() method.
10 This is faster than 'normal', slower than 'preview'. This is based on
11 the method used by pnmscale, and seems to produce less blurry results
12 than normal.
13
14 - the rubthrough() method can now render onto images with an alpha
15 channel.
16
17 - the read_multi() method now falls back to calling doing a single
18 image read via the read() method and write_multi() will now fall
19 back to calling write() if a single image is supplied. This means
20 you can simply call the read_multi() or write_multi() functions
21 without having to check if the type is formatted by that method.
22
23 - the GIF loop extension can now be written. If you don't have
24 libungif/giflib 4.1.4 (or some distribution's bugfixed equivalent)
25 you should upgrade.
26
27 - getscanline() and setscanline() can now read/write palette index
28 based data from/to the image for paletted images, by setting type to
29 'index'.
30
31 - we no longer hassle you to disable GIF support
32
33 - minor documentation fixes
34
35
36 ------------------------------------------------------------------------
37 r1092 | tony | 2006-09-12 14:19:09 +1000 (Tue, 12 Sep 2006) | 2 lines
38 Changed paths:
39 M /trunk/Imager/Makefile.PL
40
41 add generated .c files to make clean
42
43 ------------------------------------------------------------------------
44 r1091 | tony | 2006-09-06 23:50:43 +1000 (Wed, 06 Sep 2006) | 3 lines
45 Changed paths:
46 M /trunk/Imager/doco.perl
47 M /trunk/Imager/errep.perl
48 M /trunk/Imager/filterlist.perl
49 M /trunk/Imager/t/t94kwalitee.t
50
51 add .perl files to the t94kwalitee struct tests and fix the non strict
52 .perl code
53
54 ------------------------------------------------------------------------
55 r1090 | tony | 2006-09-06 21:35:38 +1000 (Wed, 06 Sep 2006) | 3 lines
56 Changed paths:
57 M /trunk/Imager/Imager.pm
58 M /trunk/Imager/t/t102png.t
59
60 read_multi() now falls back to calling read() and write_multi() now
61 falls back to calling write() for a single image.
62
63 ------------------------------------------------------------------------
64 r1089 | tony | 2006-09-01 17:17:36 +1000 (Fri, 01 Sep 2006) | 1 line
65 Changed paths:
66 M /trunk/Imager/t/t105gif.t
67
68 skip the right number of tests when gif not available
69 ------------------------------------------------------------------------
70 r1088 | tony | 2006-08-31 23:35:33 +1000 (Thu, 31 Aug 2006) | 2 lines
71 Changed paths:
72 M /trunk/Imager/TODO
73
74 rubthrough done
75
76 ------------------------------------------------------------------------
77 r1087 | tony | 2006-08-31 23:27:19 +1000 (Thu, 31 Aug 2006) | 2 lines
78 Changed paths:
79 M /trunk/Imager/t/t105gif.t
80
81 skip the loop tests with older (un)giflibs
82
83 ------------------------------------------------------------------------
84 r1086 | tony | 2006-08-31 23:16:45 +1000 (Thu, 31 Aug 2006) | 18 lines
85 Changed paths:
86 M /trunk/Imager/Makefile.PL
87 M /trunk/Imager/gif.c
88 M /trunk/Imager/t/t105gif.t
89
90 Changes to GIF support:
91
92 - the Nescape loop extension block is written if gif_loop is set.
93 This requires libungif/libgif 4.1.3 or later.
94
95 Resolves: http://rt.cpan.org/Ticket/Display.html?id=21185
96
97 - we now set the GIF header depending on the features enabled in the
98 GIF. Since we don't do configure type probes for bugs we have to
99 enable this based on the gif_lib.h version number, it's enabled for
100 4.1.0 and later, but requires 4.1.3 and later (maybe 4.1.3) to run
101 without crashing.
102
103 You can avoid this crash by passing --nogifsetversion to Makefile.PL,
104 or by installing a non-buggy libungif/libgif, if there is such a
105 thing.
106
107
108 ------------------------------------------------------------------------
109 r1085 | tony | 2006-08-30 17:25:55 +1000 (Wed, 30 Aug 2006) | 2 lines
110 Changed paths:
111 M /trunk/Imager/lib/Imager/Transformations.pod
112
113 note on relative speeds of the scaling mechanisms
114
115 ------------------------------------------------------------------------
116 r1084 | tony | 2006-08-30 16:47:48 +1000 (Wed, 30 Aug 2006) | 12 lines
117 Changed paths:
118 M /trunk/Imager/MANIFEST
119 M /trunk/Imager/bench/scale.perl
120 M /trunk/Imager/imtoc.perl
121 M /trunk/Imager/lib/Imager/Transformations.pod
122 D /trunk/Imager/scale.c
123 A /trunk/Imager/scale.im (from /trunk/Imager/scale.c:1083)
124 M /trunk/Imager/t/t40scale.t
125
126 convert scale.c to scale.im so we have 8 bit/sample and double/sample
127 implementations of mixing scaling.
128
129 modified imtoc.perl to allow non-conditional #code sections to allow
130 creation ofr 8 and double/sample versions of support functions.
131
132 fixed a bug in an optimization that avoids vertically scaling when the
133 vertical size stays the same.
134
135 The change from double/sample only to both saved about 20% on
136 scalebench time (which also loads/saves the images)
137
138 ------------------------------------------------------------------------
139 r1083 | tony | 2006-08-29 17:20:42 +1000 (Tue, 29 Aug 2006) | 3 lines
140 Changed paths:
141 M /trunk/Imager/CountColor/Makefile.PL
142 M /trunk/Imager/DynTest/Makefile.PL
143 M /trunk/Imager/Flines/Makefile.PL
144 M /trunk/Imager/ICO/Makefile.PL
145 M /trunk/Imager/Makefile.PL
146 M /trunk/Imager/Mandelbrot/Makefile.PL
147
148 comparisons against $ExtUtils::MakeMaker::VERSION were warning when
149 that had an _ in it. We now eval it to prevent the warning.
150
151 ------------------------------------------------------------------------
152 r1082 | tony | 2006-08-29 10:42:46 +1000 (Tue, 29 Aug 2006) | 10 lines
153 Changed paths:
154 M /trunk/Imager
155 M /trunk/Imager/MANIFEST
156 M /trunk/Imager/MANIFEST.SKIP
157 M /trunk/Imager/Makefile.PL
158 M /trunk/Imager/apidocs.perl
159 M /trunk/Imager/image.c
160 A /trunk/Imager/imtoc.perl
161 M /trunk/Imager/lib/Imager/APIRef.pod
162 M /trunk/Imager/lib/Imager/ImageTypes.pod
163 A /trunk/Imager/rubthru.im
164 M /trunk/Imager/t/t69rubthru.t
165
166 the rubthrough() method now supports destination images with an alpha
167 channel.
168
169 Also added a statement on the relationship between the alpha channel
170 and color data in Imager.
171
172 The new rubthrough() code uses a new pre-processor that reduces source
173 code duplication between 8-bit/sample and double/sample processing.
174
175
176 ------------------------------------------------------------------------
177 r1081 | tony | 2006-08-29 10:23:01 +1000 (Tue, 29 Aug 2006) | 2 lines
178 Changed paths:
179 M /trunk/Imager/MANIFEST
180
181 remove t/t60dyntest.t from the MANIFEST, since we moved it
182
183 ------------------------------------------------------------------------
184 r1080 | tony | 2006-08-19 17:24:35 +1000 (Sat, 19 Aug 2006) | 2 lines
185 Changed paths:
186 M /trunk/Imager/Imager.pm
187
188 to_rgb8 doesn't crop but the void content warning said it did
189
190 ------------------------------------------------------------------------
191 r1079 | tony | 2006-08-18 17:08:37 +1000 (Fri, 18 Aug 2006) | 3 lines
192 Changed paths:
193 M /trunk/Imager/MANIFEST
194 M /trunk/Imager/TODO
195 D /trunk/Imager/dynfilt/t/t00dummy.t
196 A /trunk/Imager/dynfilt/t/t60dyntest.t (from /trunk/Imager/t/t60dyntest.t:1077)
197 D /trunk/Imager/t/t60dyntest.t
198
199 move the existing dynfilt test into dynfilt/t, update it to use
200 Test::More and remove the dummy test script
201
202 ------------------------------------------------------------------------
203 r1078 | tony | 2006-08-18 14:35:27 +1000 (Fri, 18 Aug 2006) | 10 lines
204 Changed paths:
205 M /trunk/Imager/Imager.pm
206 M /trunk/Imager/Imager.xs
207 M /trunk/Imager/MANIFEST
208 M /trunk/Imager/Makefile.PL
209 M /trunk/Imager/TODO
210 M /trunk/Imager/imager.h
211 M /trunk/Imager/lib/Imager/Transformations.pod
212 A /trunk/Imager/scale.c (from /branches/Imager/scale/scale.c:1077)
213 M /trunk/Imager/t/t40scale.t
214
215 Merged in the scale branch:
216
217 - adds a new scaling mechanism 'mixing' based on the method
218 implemented by pnmscale. Produces better detail when scaling down and
219 is faster than the 'normal' method.
220
221 - the scale() method can now scale non-proportionally if the caller
222 specifically asks for it with xscalefactor/yscalefactor or by setting
223 type to 'nonprop'.
224
225 ------------------------------------------------------------------------
226 r1074 | tony | 2006-08-15 18:12:30 +1000 (Tue, 15 Aug 2006) | 5 lines
227 Changed paths:
228 M /trunk/Imager/Imager.pm
229 M /trunk/Imager/Imager.xs
230 M /trunk/Imager/TODO
231 M /trunk/Imager/lib/Imager/Draw.pod
232 M /trunk/Imager/t/t023palette.t
233 M /trunk/Imager/t/t67convert.t
234
235 added pixel type 'index' to getscanline() and setscanline() for
236 getting/setting palette indexes from paletted images.
237
238 https://rt.cpan.org/Ticket/Display.html?id=20338
239
240 ------------------------------------------------------------------------
241 r1073 | tony | 2006-08-10 11:53:19 +1000 (Thu, 10 Aug 2006) | 5 lines
242 Changed paths:
243 M /trunk/Imager/samples/slant_text.pl
244 M /trunk/Imager/t/t91pod.t
245
246 finally found which file contained the POD errors that
247 http://cpants.perl.org/kwalitee/Imager was complaining about
248
249 modified t/t91pod.t to check every pl/pod/pm/PL file
250
251 ------------------------------------------------------------------------
252 r1071 | tony | 2006-08-08 00:20:21 +1000 (Tue, 08 Aug 2006) | 5 lines
253 Changed paths:
254 M /trunk/Imager/lib/Imager/API.pod
255
256 you need to load Imager to use the API, Imager::API now tells the user
257 that
258
259 http://rt.cpan.org/Ticket/Display.html?id=20823
260
261 ------------------------------------------------------------------------
262 r1070 | tony | 2006-08-07 17:02:43 +1000 (Mon, 07 Aug 2006) | 7 lines
263 Changed paths:
264 M /trunk/Imager/Makefile.PL
265 M /trunk/Imager/README
266
267 Removed the query asking if GIF support should be disabled, since
268 recent lib(un)gif are sane.
269
270 https://rt.cpan.org/Ticket/Display.html?id=20687
271
272 Some README cleanup.
273
274 ------------------------------------------------------------------------
275 r1069 | tony | 2006-07-29 15:21:49 +1000 (Sat, 29 Jul 2006) | 2 lines
276 Changed paths:
277 M /trunk/Imager/TODO
278
279 basic todo for 0.54
280
281 ------------------------------------------------------------------------
282 r1067 | tony | 2006-07-27 10:38:49 +1000 (Thu, 27 Jul 2006) | 6 lines
283 Changed paths:
284 M /trunk/Imager/Imager.pm
285 M /trunk/Imager/META.yml
286
287 bump to 0.53
288
289 This is to fix a crash bug introduced in 0.52.
290
291 http://rt.cpan.org/Ticket/Display.html?id=20705
292
293 ------------------------------------------------------------------------
294 r1066 | tony | 2006-07-27 10:31:44 +1000 (Thu, 27 Jul 2006) | 8 lines
295 Changed paths:
296 M /trunk/Imager/Imager.xs
297 M /trunk/Imager/t/t07iolayer.t
298
299 there was a C< *(char *)0 = 0 > left in a code path uncovered by the
300 test suite.
301
302 - added a test to cover that code path
303 - removed the debug code
304
305 Fixes: http://rt.cpan.org/Ticket/Display.html?id=20705
306
307 ------------------------------------------------------------------------
308 r1064 | tony | 2006-07-25 14:43:38 +1000 (Tue, 25 Jul 2006) | 42 lines
309 Changed paths:
310 M /trunk/Imager/Imager.pm
311 M /trunk/Imager/META.yml
312 A /trunk/Imager/announce/0.52.txt
313
314 bump to 0.52
106 - a new qtype value 'mixing' has been added to the scale()
107 method. This is faster than 'normal', slower than 'preview'. This
108 is based on the method used by pnmscale, and seems to produce less
109 blurry results than normal.
110 http://rt.cpan.org/Public/Bug/Display.html?id=20677
111
112 - the rubthrough() method can now render onto images with an alpha
113 channel.
114 http://rt.cpan.org/Ticket/Display.html?id=20678
115
116 - the read_multi() method now falls back to calling doing a single
117 image read via the read() method and write_multi() will now fall
118 back to calling write() if a single image is supplied. This means
119 you can simply call the read_multi() or write_multi() functions
120 without having to check if the type is formatted by that method.
121 http://rt.cpan.org/Ticket/Display.html?id=19457
122 http://rt.cpan.org/Ticket/Display.html?id=19458
123
124 - the GIF loop extension can now be written. If you don't have
125 libungif/giflib 4.1.4 (or some distribution's bugfixed equivalent) you
126 should upgrade.
127 http://rt.cpan.org/Ticket/Display.html?id=21185
128
129 - getscanline() and setscanline() can now read/write palette index
130 based data from/to the image for paletted images, by setting type to
131 'index'.
132 http://rt.cpan.org/Ticket/Display.html?id=20338
133
134 - we no longer hassle you to disable GIF support
135 http://rt.cpan.org/Ticket/Display.html?id=20687
136
137 - minor documentation fixes
138
139
140 Imager 0.53 - 26 Jul 2006
141 ===========
142
143 This is a bugfix release.
144
145 Some test code was left in a code path not covered by the test
146 suite. A test was added to cover this code path and the test code was
147 removed.
148 http://rt.cpan.org/Public/Bug/Display.html?id=20705
149
150
151 Imager 0.52 - 25 Jul 2006
152 ===========
315153
316154 This is primarily a feature release, but contains a fair few bug
317155 fixes, new features:
318156
319 - ability to read and write MS Windows ICO and CUR files
320
321 - you can now add file format plugins to support new file formats
322
323 - add POD coverage tests
324
325 - setcolors() and addcolors() now accept color names and so on instead
326 of requiring Imager::Color objects.
327
328 - flood_fill() can now fill to a specified border color instead of
329 just to the area the same color as the seed.
157 - ability to read and write MS Windows ICO and CUR files
158
159 - you can now add file format plugins to support new file formats
160
161 - add POD coverage tests
162
163 - setcolors() and addcolors() now accept color names and so on
164 instead of requiring Imager::Color objects.
165 http://rt.cpan.org/Ticket/Display.html?id=20056
166
167 - flood_fill() can now fill to a specified border color instead of
168 just to the area the same color as the seed.
169 http://rt.cpan.org/Ticket/Display.html?id=19618
170
330171
331172 Bug fixes:
332173
333 - bounding_box for the T1 driver wasn't converting UTF8 to ascii when
334 calculating the advance width.
335
336 - bounding_box for the T1 driver wasn't including leading and trailing
337 spaces in the bounding box as the other drivers did, it also produced
338 strange results for empty strings or strings containing only spaces
339
340 - when reading CMYK jpeg images they were being transferred to the
341 image object as is, producing a four channel image. It only looked
342 ok due to an old still unfixed Photoshop bug. We now convert from
343 the inverted CMYK that photoshop (and Corel for example) produce
344 into RGB.
345
346 - reading a CYMK TIFF would result in a 4 channel image, reading any
347 image with more than 4 channels (eg. RGB with 2 alpha channels)
348 would result in an error.
349
350 - added /usr/local/include to the default include search path, since
351 we were already searching /usr/local/lib for libraries.
174 - bounding_box for the T1 driver wasn't converting UTF8 to ascii when
175 calculating the advance width.
176 http://rt.cpan.org/Public/Bug/Display.html?id=20554
177
178 - bounding_box for the T1 driver wasn't including leading and
179 trailing spaces in the bounding box as the other drivers did, it also
180 produced strange results for empty strings or strings containing only
181 spaces
182
183 - when reading CMYK jpeg images they were being transferred to the
184 image object as is, producing a four channel image. It only looked ok
185 due to an old still unfixed Photoshop bug. We now convert from the
186 inverted CMYK that photoshop (and Corel for example) produce into RGB.
187 http://rt.cpan.org/Ticket/Display.html?id=20416
188
189 - reading a CYMK TIFF would result in a 4 channel image, reading any
190 image with more than 4 channels (eg. RGB with 2 alpha channels) would
191 result in an error.
192 http://rt.cpan.org/Ticket/Display.html?id=20415
193
194 - added /usr/local/include to the default include search path, since
195 we were already searching /usr/local/lib for libraries.
352196
353197 And various minor fixes and documentation updates.
354198
355199
356 ------------------------------------------------------------------------
357 r1063 | tony | 2006-07-24 22:28:31 +1000 (Mon, 24 Jul 2006) | 4 lines
358 Changed paths:
359 M /trunk/Imager/lib/Imager/Cookbook.pod
360
361 added a cookbook entry for converting files from one format to another
362
363 part of http://rt.cpan.org/Ticket/Display.html?id=5608
364
365 ------------------------------------------------------------------------
366 r1062 | tony | 2006-07-24 22:09:22 +1000 (Mon, 24 Jul 2006) | 4 lines
367 Changed paths:
368 M /trunk/Imager/lib/Imager/Draw.pod
369
370 document the direction of Imager's co-ordinate system
371
372 http://rt.cpan.org/Ticket/Display.html?id=11429
373
374 ------------------------------------------------------------------------
375 r1061 | tony | 2006-07-24 21:27:24 +1000 (Mon, 24 Jul 2006) | 2 lines
376 Changed paths:
377 M /trunk/Imager/lib/Imager/Files.pod
378
379 add an example of reading exif tags
380
381 ------------------------------------------------------------------------
382 r1060 | tony | 2006-07-24 21:16:06 +1000 (Mon, 24 Jul 2006) | 2 lines
383 Changed paths:
384 M /trunk/Imager/lib/Imager/Files.pod
385
386 add some basic examples of using data, fd, fh, callback parameters
387
388 ------------------------------------------------------------------------
389 r1059 | tony | 2006-07-24 20:17:00 +1000 (Mon, 24 Jul 2006) | 3 lines
390 Changed paths:
391 M /trunk/Imager/lib/Imager/Files.pod
392
393 added examples for fh, fd, file, data and callback mechanisms for
394 reading/writing files.
395
396 ------------------------------------------------------------------------
397 r1058 | tony | 2006-07-24 17:15:49 +1000 (Mon, 24 Jul 2006) | 2 lines
398 Changed paths:
399 M /trunk/Imager/image.c
400 M /trunk/Imager/t/t1000files.t
401
402 add detection of BZIP2 and gzip data
403
404 ------------------------------------------------------------------------
405 r1057 | tony | 2006-07-24 14:46:00 +1000 (Mon, 24 Jul 2006) | 2 lines
406 Changed paths:
407 M /trunk/Imager/MANIFEST
408 A /trunk/Imager/dynfilt/t
409 A /trunk/Imager/dynfilt/t/t00dummy.t
410
411 add dummy test to dynfilt to since it was confusing smoke testers
412
413 ------------------------------------------------------------------------
414 r1056 | tony | 2006-07-24 14:44:28 +1000 (Mon, 24 Jul 2006) | 2 lines
415 Changed paths:
416 M /trunk/Imager/fontfiles/SpaceTest.sfd
417
418 commit changes to SpaceTest font source caused by exports
419
420 ------------------------------------------------------------------------
421 r1055 | tony | 2006-07-21 10:01:57 +1000 (Fri, 21 Jul 2006) | 2 lines
422 Changed paths:
423 M /trunk/Imager/image.c
424 M /trunk/Imager/t/t1000files.t
425
426 add a magic entry to detect XWD files
427
428 ------------------------------------------------------------------------
429 r1054 | tony | 2006-07-21 00:35:22 +1000 (Fri, 21 Jul 2006) | 5 lines
430 Changed paths:
431 M /trunk/Imager/font.c
432 M /trunk/Imager/t/t30t1font.t
433
434 bounding_box() for the t1 driver wasn't converting from UTF8 to ascii
435 when calculating the advance width.
436
437 fixes http://rt.cpan.org/Ticket/Display.html?id=20554
438
439 ------------------------------------------------------------------------
440 r1053 | tony | 2006-07-20 23:42:04 +1000 (Thu, 20 Jul 2006) | 11 lines
441 Changed paths:
442 M /trunk/Imager/MANIFEST
443 M /trunk/Imager/font.c
444 M /trunk/Imager/fontfiles/ExistenceTest.afm
445 M /trunk/Imager/fontfiles/ExistenceTest.pfb
446 M /trunk/Imager/fontfiles/ExistenceTest.sfd
447 A /trunk/Imager/fontfiles/SpaceTest.afm
448 A /trunk/Imager/fontfiles/SpaceTest.pfb
449 A /trunk/Imager/fontfiles/SpaceTest.sfd
450 M /trunk/Imager/t/t30t1font.t
451
452 bounding_box() for t1 driver fonts was treating spaces as empty space
453 when calculating the bounds, which they are, but this is inconsistent
454 with other drivers. This was especially a problem for strings
455 containing only spaces where the left bound would end up far to the
456 right of the right bound, and similarly for the ascent and descent.
457
458 calculating the bounding box for an empty string invoked special
459 behaviour in t1lib, making it unreliable.
460
461 Fixes: http://rt.cpan.org/Ticket/Display.html?id=20555
462
463 ------------------------------------------------------------------------
464 r1052 | tony | 2006-07-19 10:39:58 +1000 (Wed, 19 Jul 2006) | 2 lines
465 Changed paths:
466 M /trunk/Imager/Imager.pm
467 M /trunk/Imager/META.yml
468
469 bump to 0.51_03
470
471 ------------------------------------------------------------------------
472 r1051 | tony | 2006-07-19 00:34:52 +1000 (Wed, 19 Jul 2006) | 3 lines
473 Changed paths:
474 M /trunk/Imager/jpeg.c
475
476 make the selection of a transfer function check that it's getting the
477 right number of channels
478
479 ------------------------------------------------------------------------
480 r1050 | tony | 2006-07-18 23:34:56 +1000 (Tue, 18 Jul 2006) | 2 lines
481 Changed paths:
482 M /trunk/Imager/lib/Imager/APIRef.pod
483
484 set eol-style so that generation doesn't make svn burp
485
486 ------------------------------------------------------------------------
487 r1049 | tony | 2006-07-18 23:21:21 +1000 (Tue, 18 Jul 2006) | 3 lines
488 Changed paths:
489 M /trunk/Imager/image.c
490 M /trunk/Imager/jpeg.c
491
492 cast 2 signed/unsigned char pointer conversions to prevent warnings
493 (errors on some compilers)
494
495 ------------------------------------------------------------------------
496 r1048 | tony | 2006-07-18 22:49:31 +1000 (Tue, 18 Jul 2006) | 2 lines
497 Changed paths:
498 M /trunk/Imager/t/t106tiff.t
499
500 report the error if we can't read the alpha test images
501
502 ------------------------------------------------------------------------
503 r1047 | tony | 2006-07-18 22:43:02 +1000 (Tue, 18 Jul 2006) | 3 lines
504 Changed paths:
505 M /trunk/Imager/testimg/scmyka.tif
506 M /trunk/Imager/testimg/scmykaa.tif
507 M /trunk/Imager/testimg/srgba.tif
508 M /trunk/Imager/testimg/srgbaa.tif
509
510 newer versions of libtiff were choking on the bad values corel was
511 putting into EXTRASAMPLES, corrected via hex editing
512
513 ------------------------------------------------------------------------
514 r1046 | tony | 2006-07-15 00:57:44 +1000 (Sat, 15 Jul 2006) | 21 lines
515 Changed paths:
516 M /trunk/Imager/MANIFEST
517 M /trunk/Imager/jpeg.c
518 M /trunk/Imager/t/t101jpeg.t
519 A /trunk/Imager/testimg/scmyk.jpg
520
521 CMYK jpeg images were being read as 4 channel images, even though they
522 have no alpha channel.
523
524 The colors were being transferred directly from the JPEG image data,
525 this only looked correct because of an old bug in photoshop, kept for
526 compatibility in later versions. Photoshop inverts the ink values in
527 the file, so max cyan coverage is stored at 0, and min as 255, and so
528 on.
529
530 CMYK jpegs are now read as 3 channel images. The colors are now
531 converted adjusting for the photoshop bug, cmyk images from the only
532 other source I have, corel draw 9, are inverted in the same way,
533 presumably for compatibility with photoshop.
534
535 If anyone has an application that produces technically correct CMYK
536 jpegs, please provide a sample in jpeg and tiff form so I can attempt
537 to deal with it.
538
539 Fixes: http://rt.cpan.org/Ticket/Display.html?id=20416
540
541
542 ------------------------------------------------------------------------
543 r1045 | tony | 2006-07-13 21:04:53 +1000 (Thu, 13 Jul 2006) | 10 lines
544 Changed paths:
545 M /trunk/Imager/MANIFEST
546 M /trunk/Imager/lib/Imager/Files.pod
547 M /trunk/Imager/t/t106tiff.t
548 A /trunk/Imager/testimg/scmyk.tif
549 A /trunk/Imager/testimg/scmyka.tif
550 A /trunk/Imager/testimg/scmykaa.tif
551 A /trunk/Imager/testimg/slab.tif
552 A /trunk/Imager/testimg/srgb.tif
553 A /trunk/Imager/testimg/srgba.tif
554 A /trunk/Imager/testimg/srgbaa.tif
555 M /trunk/Imager/tiff.c
556
557 http://rt.cpan.org/Ticket/Display.html?id=20415
558
559 Reading a CMYK TIFF with no alpha would result in a 4-channel image.
560
561 Also, reading a CMYK TIFF with an alpha channel would fail to read.
562
563 Reading a CMYK TIFF with 2 alpha channels would fail to read.
564
565 Reading a RGB TIFF with 2 alpha channels would also fail to read.
566
567 ------------------------------------------------------------------------
568 r1044 | tony | 2006-07-13 15:20:09 +1000 (Thu, 13 Jul 2006) | 8 lines
569 Changed paths:
570 M /trunk/Imager/freetyp2.c
571 M /trunk/Imager/t/t38ft2font.t
572
573 attempting to render a space non-antialiased from freetype 2 could
574 crash or fail, depending on the version of freetype.
575
576 Fixed by checking if the glyph has anything to render before calling
577 FT_Render_Glyph().
578
579 https://rt.cpan.org/Ticket/Display.html?id=20403
580
581 ------------------------------------------------------------------------
582 r1043 | tony | 2006-07-11 23:21:31 +1000 (Tue, 11 Jul 2006) | 2 lines
583 Changed paths:
584 M /trunk/Imager/Imager.pm
585 M /trunk/Imager/lib/Imager/Cookbook.pod
586 M /trunk/Imager/lib/Imager/ImageTypes.pod
587
588 add some examples using the i_xres and i_yres tags
589
590 ------------------------------------------------------------------------
591 r1042 | tony | 2006-07-10 18:07:18 +1000 (Mon, 10 Jul 2006) | 3 lines
592 Changed paths:
593 M /trunk/Imager/lib/Imager/Cookbook.pod
594
595 the cookbook said we couldn't limit image sizes, but we can now. Fix
596 that and add some simple examples.
597
598 ------------------------------------------------------------------------
599 r1035 | tony | 2006-07-07 20:59:07 +1000 (Fri, 07 Jul 2006) | 2 lines
600 Changed paths:
601 M /trunk/Imager/Makefile.PL
602
603 it's libgif not libguf
604
605 ------------------------------------------------------------------------
606 r1034 | tony | 2006-07-07 20:57:26 +1000 (Fri, 07 Jul 2006) | 3 lines
607 Changed paths:
608 M /trunk/Imager/Makefile.PL
609
610 move linker flags from freetype-config/pkg-config up to the front to
611 match the placement of C flags.
612
613 ------------------------------------------------------------------------
614 r1033 | tony | 2006-07-06 00:21:07 +1000 (Thu, 06 Jul 2006) | 6 lines
615 Changed paths:
616 M /trunk/Imager/Makefile.PL
617
618 we search /usr/local/include by default but we weren't searching
619 /usr/local/lib, fixed that
620
621 don't rebuild META.yml if we're not setting AUTHOR, this was producing
622 a bad META.yml on older EU::MMs
623
624 ------------------------------------------------------------------------
625 r1032 | tony | 2006-07-05 21:54:33 +1000 (Wed, 05 Jul 2006) | 3 lines
626 Changed paths:
627 M /trunk/Imager/ICO/t/t60writefail.t
628
629 implement limited writes as a closure instead of as an overloaded
630 class to support 5.005_03
631
632 ------------------------------------------------------------------------
633 r1031 | tony | 2006-07-05 21:41:04 +1000 (Wed, 05 Jul 2006) | 2 lines
634 Changed paths:
635 M /trunk/Imager/ICO/ICO.xs
636 M /trunk/Imager/ICO/t/t10icon.t
637 M /trunk/Imager/ICO/t/t20readone.t
638 M /trunk/Imager/ICO/t/t21readmult.t
639 M /trunk/Imager/ICO/t/t30cursor.t
640 M /trunk/Imager/ICO/t/t40readcurone.t
641 M /trunk/Imager/ICO/t/t41curmultread.t
642 M /trunk/Imager/ICO/t/t50readfail.t
643 M /trunk/Imager/ICO/t/t60writefail.t
644 M /trunk/Imager/ICO/t/t70icosing.t
645 M /trunk/Imager/ICO/t/t71icomult.t
646 M /trunk/Imager/ICO/t/t72cursing.t
647 M /trunk/Imager/ICO/t/t73curmult.t
648 M /trunk/Imager/t/t07iolayer.t
649 M /trunk/Imager/t/t69rubthru.t
650 M /trunk/Imager/t/tr18561.t
651 M /trunk/Imager/t/tr18561b.t
652
653 minor changes for compatibility with 5.005_03
654
655 ------------------------------------------------------------------------
656 r1028 | tony | 2006-07-04 23:54:13 +1000 (Tue, 04 Jul 2006) | 2 lines
657 Changed paths:
658 M /trunk/Imager/Imager.pm
659 M /trunk/Imager/META.yml
660
661 bump to 0.51_02
662
663 ------------------------------------------------------------------------
664 r1027 | tony | 2006-07-04 22:52:08 +1000 (Tue, 04 Jul 2006) | 3 lines
665 Changed paths:
666 M /trunk/Imager/Imager.pm
667 M /trunk/Imager/t/t93podcover.t
668
669 make sure the method index includes all documented Imager methods and
670 is properly sorted.
671
672 ------------------------------------------------------------------------
673 r1026 | tony | 2006-07-04 22:06:22 +1000 (Tue, 04 Jul 2006) | 3 lines
674 Changed paths:
675 M /trunk/Imager/Imager.xs
676 M /trunk/Imager/ppport.h
677
678 update to a newer ppport.h and modify Imager.xs a bit based on its
679 recommendations
680
681 ------------------------------------------------------------------------
682 r1025 | tony | 2006-07-04 21:39:37 +1000 (Tue, 04 Jul 2006) | 2 lines
683 Changed paths:
684 M /trunk/Imager/filters.c
685
686 addition memory allocation checks
687
688 ------------------------------------------------------------------------
689 r1024 | tony | 2006-07-04 21:28:34 +1000 (Tue, 04 Jul 2006) | 2 lines
690 Changed paths:
691 M /trunk/Imager/lib/Imager/Matrix2d.pm
692 M /trunk/Imager/lib/Imager/Transform.pm
693 M /trunk/Imager/t/t93podcover.t
694
695 add more pod coverage tests (and the coverage needed)
696
697 ------------------------------------------------------------------------
698 r1023 | tony | 2006-07-04 21:17:12 +1000 (Tue, 04 Jul 2006) | 6 lines
699 Changed paths:
700 M /trunk/Imager
701 M /trunk/Imager/CountColor
702 M /trunk/Imager/DynTest
703 M /trunk/Imager/Flines
704 M /trunk/Imager/ICO
705 M /trunk/Imager/Imager.pm
706 M /trunk/Imager/MANIFEST
707 M /trunk/Imager/Mandelbrot
708 M /trunk/Imager/lib/Imager/Color/Float.pm
709 M /trunk/Imager/lib/Imager/Color/Table.pm
710 M /trunk/Imager/lib/Imager/Color.pm
711 M /trunk/Imager/lib/Imager/Expr.pm
712 M /trunk/Imager/lib/Imager/Files.pod
713 M /trunk/Imager/lib/Imager/Fill.pm
714 M /trunk/Imager/lib/Imager/Font/BBox.pm
715 M /trunk/Imager/lib/Imager/Font/Wrap.pm
716 M /trunk/Imager/lib/Imager/Font.pm
717 A /trunk/Imager/lib/Imager/Handy.pod
718 M /trunk/Imager/lib/Imager/ImageTypes.pod
719 M /trunk/Imager/t/t93podcover.t
720
721 svn:ignore some more profiler files and other junk
722
723 we now pass the pod coverage test on the Imager class, remove the TODO
724
725 add pod coverage tests for several other classes, and pass them
726
727 ------------------------------------------------------------------------
728 r1021 | tony | 2006-07-01 15:38:11 +1000 (Sat, 01 Jul 2006) | 4 lines
729 Changed paths:
730 M /trunk/Imager/apidocs.perl
731 M /trunk/Imager/lib/Imager/APIRef.pod
732
733 don't include the line number in the From comment so since unrelated edits
734 were causing changes to APIRef.pm. This is still possible but they should
735 be a lot less frequence.
736
737 ------------------------------------------------------------------------
738 r1020 | tony | 2006-07-01 15:31:35 +1000 (Sat, 01 Jul 2006) | 3 lines
739 Changed paths:
740 M /trunk/Imager/t/t023palette.t
741
742 added error handling tests for bad colors supplied to addcolors()
743 and setcolors()
744
745 ------------------------------------------------------------------------
746 r1019 | tony | 2006-06-30 23:51:45 +1000 (Fri, 30 Jun 2006) | 6 lines
747 Changed paths:
748 M /trunk/Imager/Imager.xs
749 M /trunk/Imager/iolayer.c
750 A /trunk/Imager/lib/Imager/IO.pod
751 M /trunk/Imager/t/t07iolayer.t
752
753 add more iolayer tests
754 callback handler fixes to return errors correctly
755 Imager::IO XS changes to make errors return empty lists
756 iolayer error handling fixes
757 documented Imager::IO methods
758
759 ------------------------------------------------------------------------
760 r1018 | tony | 2006-06-29 21:39:10 +1000 (Thu, 29 Jun 2006) | 3 lines
761 Changed paths:
762 M /trunk/Imager/Imager.pm
763 M /trunk/Imager/t/t023palette.t
764
765 setcolors() and addcolors() can now accept non-object colors like most
766 other methods
767
768 ------------------------------------------------------------------------
769 r1017 | tony | 2006-06-29 21:06:16 +1000 (Thu, 29 Jun 2006) | 2 lines
770 Changed paths:
771 M /trunk/Imager/t/t101jpeg.t
772
773 extra jpeg tests to improve code coverage of jpeg.c
774
775 ------------------------------------------------------------------------
776 r1016 | tony | 2006-06-29 20:56:09 +1000 (Thu, 29 Jun 2006) | 3 lines
777 Changed paths:
778 M /trunk/Imager/bmp.c
779 M /trunk/Imager/datatypes.c
780 M /trunk/Imager/error.c
781 M /trunk/Imager/filters.c
782 M /trunk/Imager/font.c
783 M /trunk/Imager/gif.c
784 M /trunk/Imager/hlines.c
785 M /trunk/Imager/image.c
786 M /trunk/Imager/imexif.c
787 M /trunk/Imager/iolayer.c
788 M /trunk/Imager/log.c
789
790 long delayed renaming of m_fatal() to i_fatal() to match Imager's
791 functions in general
792
793 ------------------------------------------------------------------------
794 r1015 | tony | 2006-06-29 20:53:07 +1000 (Thu, 29 Jun 2006) | 2 lines
795 Changed paths:
796 M /trunk/Imager/META.yml
797
798 META.yml changed due to release
799
800 ------------------------------------------------------------------------
801 r1014 | tony | 2006-06-29 20:51:12 +1000 (Thu, 29 Jun 2006) | 2 lines
802 Changed paths:
803 M /trunk/Imager/jpeg.c
804
805 add missing parameter required by format in wiol_empty_output_buffer
806
807 ------------------------------------------------------------------------
808 r1012 | tony | 2006-06-28 23:22:25 +1000 (Wed, 28 Jun 2006) | 2 lines
809 Changed paths:
810 M /trunk/Imager/Imager.pm
811
812 bump to 0.51_01 for release
813
814 ------------------------------------------------------------------------
815 r1011 | tony | 2006-06-28 00:38:10 +1000 (Wed, 28 Jun 2006) | 1 line
816 Changed paths:
817 M /trunk/Imager/Makefile.PL
818
819 handle a missing Changes file when checking if we need to generate one.
820 ------------------------------------------------------------------------
821 r1010 | tony | 2006-06-28 00:25:03 +1000 (Wed, 28 Jun 2006) | 2 lines
822 Changed paths:
823 M /trunk/Imager/lib/Imager/APIRef.pod
824 M /trunk/Imager/limits.c
825
826 document the image file limit functions for the API
827
828 ------------------------------------------------------------------------
829 r1009 | tony | 2006-06-27 22:50:28 +1000 (Tue, 27 Jun 2006) | 1 line
830 Changed paths:
831 M /trunk/Imager/iolayert.h
832
833 include stddef.h for size_t
834 ------------------------------------------------------------------------
835 r1008 | tony | 2006-06-27 22:20:47 +1000 (Tue, 27 Jun 2006) | 10 lines
836 Changed paths:
837 M /trunk/Imager/Imager.pm
838 M /trunk/Imager/Imager.xs
839 M /trunk/Imager/draw.c
840 M /trunk/Imager/fills.c
841 M /trunk/Imager/imager.h
842 M /trunk/Imager/imext.c
843 M /trunk/Imager/imext.h
844 M /trunk/Imager/imexttypes.h
845 M /trunk/Imager/lib/Imager/APIRef.pod
846 M /trunk/Imager/lib/Imager/Draw.pod
847 M /trunk/Imager/t/t20fill.t
848 M /trunk/Imager/t/t82inline.t
849
850 implement a flood_fill that stops at a given color rather than filling
851 a region of the color at the start poiint.
852
853 from perl you can call flood_fill() with a border parameter to specify
854 a fill to border.
855
856 from the API call the i_flood_fill_border() or i_flood_cfill_border()
857 function.
858
859
860 ------------------------------------------------------------------------
861 r1007 | tony | 2006-06-27 22:12:12 +1000 (Tue, 27 Jun 2006) | 3 lines
862 Changed paths:
863 M /trunk/Imager/Makefile.PL
864
865 Makefile was generating lib/Imager/APIRef.pod, not
866 lib/Imager/APIRef.pm
867
868 ------------------------------------------------------------------------
869 r1006 | tony | 2006-06-26 23:14:54 +1000 (Mon, 26 Jun 2006) | 3 lines
870 Changed paths:
871 M /trunk/Imager/Makefile.PL
872
873 use the ExtUtils::MakeMaker prompt() function to ask about including
874 gif support instead of <STDIN>
875
876 ------------------------------------------------------------------------
877 r1005 | tony | 2006-06-26 22:57:00 +1000 (Mon, 26 Jun 2006) | 3 lines
878 Changed paths:
879 M /trunk/Imager/Imager.pm
880 M /trunk/Imager/lib/Imager/Files.pod
881
882 document parseiptc()
883 https://rt.cpan.org/Ticket/Display.html?id=17894
884
885 ------------------------------------------------------------------------
886 r1004 | tony | 2006-06-26 22:34:40 +1000 (Mon, 26 Jun 2006) | 3 lines
887 Changed paths:
888 M /trunk/Imager/lib/Imager/Files.pod
889
890 clarify that FORMATGUESS is only used when writing to a file.
891 http://rt.cpan.org/Ticket/Display.html?id=18773
892
893 ------------------------------------------------------------------------
894 r1003 | tony | 2006-06-26 22:20:27 +1000 (Mon, 26 Jun 2006) | 10 lines
895 Changed paths:
896 M /trunk/Imager
897 M /trunk/Imager/CountColor
898 M /trunk/Imager/DynTest
899 M /trunk/Imager/Flines
900 M /trunk/Imager/ICO
901 M /trunk/Imager/ICO/ICO.pm
902 M /trunk/Imager/ICO/ICO.xs
903 M /trunk/Imager/ICO/Makefile.PL
904 M /trunk/Imager/ICO/imicon.c
905 M /trunk/Imager/ICO/imicon.h
906 A /trunk/Imager/ICO/lib (from /branches/Imager/ico/ICO/lib:1002)
907 M /trunk/Imager/ICO/msicon.c
908 M /trunk/Imager/ICO/msicon.h
909 M /trunk/Imager/ICO/t/t10icon.t
910 A /trunk/Imager/ICO/t/t30cursor.t (from /branches/Imager/ico/ICO/t/t30cursor.t:1002)
911 A /trunk/Imager/ICO/t/t40readcurone.t (from /branches/Imager/ico/ICO/t/t40readcurone.t:1002)
912 A /trunk/Imager/ICO/t/t41curmultread.t (from /branches/Imager/ico/ICO/t/t41curmultread.t:1002)
913 A /trunk/Imager/ICO/t/t50readfail.t (from /branches/Imager/ico/ICO/t/t50readfail.t:1002)
914 A /trunk/Imager/ICO/t/t60writefail.t (from /branches/Imager/ico/ICO/t/t60writefail.t:1002)
915 A /trunk/Imager/ICO/t/t70icosing.t (from /branches/Imager/ico/ICO/t/t70icosing.t:1002)
916 A /trunk/Imager/ICO/t/t71icomult.t (from /branches/Imager/ico/ICO/t/t71icomult.t:1002)
917 A /trunk/Imager/ICO/t/t72cursing.t (from /branches/Imager/ico/ICO/t/t72cursing.t:1002)
918 A /trunk/Imager/ICO/t/t73curmult.t (from /branches/Imager/ico/ICO/t/t73curmult.t:1002)
919 A /trunk/Imager/ICO/testimg/pal43232.cur (from /branches/Imager/ico/ICO/testimg/pal43232.cur:1002)
920 M /trunk/Imager/Imager.pm
921 M /trunk/Imager/Imager.xs
922 M /trunk/Imager/MANIFEST
923 M /trunk/Imager/MANIFEST.SKIP
924 M /trunk/Imager/Makefile.PL
925 M /trunk/Imager/Mandelbrot
926 M /trunk/Imager/dynfilt
927 M /trunk/Imager/image.c
928 M /trunk/Imager/imager.h
929 M /trunk/Imager/imageri.h
930 M /trunk/Imager/imext.c
931 M /trunk/Imager/imext.h
932 M /trunk/Imager/imexttypes.h
933 M /trunk/Imager/iolayer.c
934 M /trunk/Imager/iolayert.h
935 M /trunk/Imager/lib/Imager/Files.pod
936 M /trunk/Imager/t/t106tiff.t
937
938 add support for file write plugins
939
940 fix write_multi() writing to scalars
941 https://rt.cpan.org/Ticket/Display.html?id=19982
942
943 add support for writing to ICO/CUR image files
944
945 added file limit check functions to the API
946
947
948 ------------------------------------------------------------------------
949 r996 | tony | 2006-05-22 13:46:15 +1000 (Mon, 22 May 2006) | 2 lines
950 Changed paths:
951 M /trunk/Imager/MANIFEST
952 M /trunk/Imager/samples/README
953 A /trunk/Imager/samples/inline_capture2image.pl
954
955 add inline_capture2image.pl sample
956
957 ------------------------------------------------------------------------
958 r995 | tony | 2006-05-22 13:29:51 +1000 (Mon, 22 May 2006) | 2 lines
959 Changed paths:
960 M /trunk/Imager/MANIFEST
961 M /trunk/Imager/Makefile.PL
962 D /trunk/Imager/lib/Imager/API.pm
963 A /trunk/Imager/lib/Imager/API.pod (from /trunk/Imager/lib/Imager/API.pm:959)
964 D /trunk/Imager/lib/Imager/APIRef.pm
965 A /trunk/Imager/lib/Imager/APIRef.pod (from /trunk/Imager/lib/Imager/APIRef.pm:959)
966
967 rename APIRef.pm, API.pm to *.pod since they contain no code
968
969 ------------------------------------------------------------------------
970 r994 | tony | 2006-05-22 13:24:49 +1000 (Mon, 22 May 2006) | 2 lines
971 Changed paths:
972 M /trunk/Imager/tags.c
973
974 fix documentation nit
975
976 ------------------------------------------------------------------------
977 r993 | tony | 2006-05-22 13:24:20 +1000 (Mon, 22 May 2006) | 2 lines
978 Changed paths:
979 M /trunk/Imager/MANIFEST
980
981 added kwalitee test script to the MANIFEST
982
983 ------------------------------------------------------------------------
984 r992 | tony | 2006-05-22 13:23:50 +1000 (Mon, 22 May 2006) | 2 lines
985 Changed paths:
986 M /trunk/Imager/lib/Imager/ExtUtils.pm
987
988 give lib/Imager/ExtUtils.pm a version number
989
990 ------------------------------------------------------------------------
991 r991 | tony | 2006-05-22 13:23:11 +1000 (Mon, 22 May 2006) | 4 lines
992 Changed paths:
993 M /trunk/Imager/CountColor/Makefile.PL
994 M /trunk/Imager/DynTest/Makefile.PL
995 M /trunk/Imager/Flines/Makefile.PL
996 M /trunk/Imager/Mandelbrot/Makefile.PL
997 M /trunk/Imager/dynfilt/Makefile.PL
998 M /trunk/Imager/t/Pod/Coverage/Imager.pm
999 A /trunk/Imager/t/t94kwalitee.t
1000 M /trunk/Imager/t/testtools.pl
1001
1002 added "kwalitee" test script:
1003 - currently tests all pl/pm/PL files have use strict
1004 - added use strict to all pl/pm/PL files with code in them
1005
1006 ------------------------------------------------------------------------
1007 r990 | tony | 2006-05-22 13:18:27 +1000 (Mon, 22 May 2006) | 5 lines
1008 Changed paths:
1009 M /trunk/Imager/image.c
1010 M /trunk/Imager/t/t1000files.t
1011
1012 i_test_format_probe:
1013 - added Utah RLE,
1014 - separated ICO and CUR file formats,
1015 - fix duplicate PCX entry
1016
1017 ------------------------------------------------------------------------
1018 r989 | tony | 2006-04-30 00:53:11 +1000 (Sun, 30 Apr 2006) | 4 lines
1019 Changed paths:
1020 M /trunk/Imager/lib/Imager/interface.pod
1021
1022 minor updates, make it clear in the title this documents the C level.
1023 tags is now used.
1024 there's been a double image type for a while now.
1025
1026 ------------------------------------------------------------------------
1027 r988 | tony | 2006-04-30 00:44:27 +1000 (Sun, 30 Apr 2006) | 4 lines
1028 Changed paths:
1029 M /trunk/Imager/lib/Imager/ImageTypes.pod
1030
1031 changed the title to better reflect what it documents - model, not
1032 internals.
1033 Split out the initial paragraphs into more concise statements.
1034
1035 ------------------------------------------------------------------------
1036 r983 | tony | 2006-04-19 22:19:56 +1000 (Wed, 19 Apr 2006) | 9 lines
1037 Changed paths:
1038 M /trunk/Imager/Imager.pm
1039 M /trunk/Imager/MANIFEST
1040 A /trunk/Imager/t/tr18561.t
1041 A /trunk/Imager/t/tr18561b.t
1042
1043 - Calling setpixel() with color set to [ 0, 0, 0 ] would crash with
1044 Can't locate object method "new" via package "Imager::Color::Float" ...
1045
1046 - having the color parameter code create floating point colors could
1047 cause other problems too, since most of the underlying functions can't
1048 handle them, so removed the attempt to create float colors.
1049
1050 Fixes #18561
1051
1052 ------------------------------------------------------------------------
1053 r980 | tony | 2006-04-19 14:05:45 +1000 (Wed, 19 Apr 2006) | 4 lines
1054 Changed paths:
1055 M /trunk/Imager/Imager.pm
1056 M /trunk/Imager/t/t66paste.t
1057
1058 Specifying the bottom edge of the source image to paste was broken in
1059 a couple of different ways.
1060 Fixes #18712
1061
1062 ------------------------------------------------------------------------
1063 r978 | tony | 2006-04-04 09:53:26 +1000 (Tue, 04 Apr 2006) | 2 lines
1064 Changed paths:
1065 M /trunk/Imager/lib/Imager/Filters.pod
1066
1067 add AUTHOR, SEE ALSO, REVISION sections
1068
1069 ------------------------------------------------------------------------
1070 r977 | tony | 2006-04-02 16:57:56 +1000 (Sun, 02 Apr 2006) | 4 lines
1071 Changed paths:
1072 M /trunk/Imager/MANIFEST
1073 M /trunk/Imager/imexif.c
1074 M /trunk/Imager/t/t101jpeg.t
1075 A /trunk/Imager/testimg/zerotype.jpg
1076
1077 fix range checking on IFD entry data types. This could cause various
1078 crashes.
1079 Fixes #18496
1080
1081 ------------------------------------------------------------------------
1082 r976 | tony | 2006-03-30 18:14:17 +1100 (Thu, 30 Mar 2006) | 2 lines
1083 Changed paths:
1084 M /trunk/Imager/jpeg.c
1085 M /trunk/Imager/t/t101jpeg.t
1086 M /trunk/Imager/t/t108tga.t
1087 M /trunk/Imager/tga.c
1088
1089 backport fix for RT issue 18397
1090
1091 ------------------------------------------------------------------------
1092 r975 | tony | 2006-03-30 15:41:41 +1100 (Thu, 30 Mar 2006) | 5 lines
1093 Changed paths:
1094 M /trunk/Imager/image.c
1095 M /trunk/Imager/t/t1000files.t
1096
1097 add format probes for SGI RGB, ILBM, XPM, PCX, FITS, Photoshop, EPS
1098
1099 if you have an entry for some other format you want to implement let
1100 me know.
1101
1102 ------------------------------------------------------------------------
1103 r964 | tony | 2006-03-24 20:49:57 +1100 (Fri, 24 Mar 2006) | 6 lines
1104 Changed paths:
1105 A /trunk/Imager/ICO
1106 A /trunk/Imager/ICO/ICO.pm
1107 A /trunk/Imager/ICO/ICO.xs
1108 A /trunk/Imager/ICO/Makefile.PL
1109 A /trunk/Imager/ICO/imicon.c
1110 A /trunk/Imager/ICO/imicon.h
1111 A /trunk/Imager/ICO/msicon.c
1112 A /trunk/Imager/ICO/msicon.h
1113 A /trunk/Imager/ICO/t
1114 A /trunk/Imager/ICO/t/t10icon.t
1115 A /trunk/Imager/ICO/t/t20readone.t
1116 A /trunk/Imager/ICO/t/t21readmult.t
1117 A /trunk/Imager/ICO/testimg
1118 A /trunk/Imager/ICO/testimg/combo.ico
1119 A /trunk/Imager/ICO/testimg/pal13232.ico
1120 A /trunk/Imager/ICO/testimg/pal43232.ico
1121 A /trunk/Imager/ICO/testimg/pal43232.ppm
1122 A /trunk/Imager/ICO/testimg/pal83232.ico
1123 A /trunk/Imager/ICO/testimg/pal83232.ppm
1124 A /trunk/Imager/ICO/testimg/rgba3232.ico
1125 A /trunk/Imager/ICO/testimg/rgba3232.ppm
1126 M /trunk/Imager/MANIFEST
1127 M /trunk/Imager/MANIFEST.SKIP
1128
1129 - implement reading MS Windows icon files
1130
1131 - add t/Pod/Coverage/Imager.pm to MANIFEST
1132
1133 - skip some more trash in MANIFEST.SKIP
1134
1135 ------------------------------------------------------------------------
1136 r963 | tony | 2006-03-24 15:26:24 +1100 (Fri, 24 Mar 2006) | 2 lines
1137 Changed paths:
1138 M /trunk/Imager/tga.c
1139
1140 make the targa probe even stricter
1141
1142 ------------------------------------------------------------------------
1143 r962 | tony | 2006-03-24 01:09:57 +1100 (Fri, 24 Mar 2006) | 10 lines
1144 Changed paths:
1145 M /trunk/Imager/Imager.pm
1146 M /trunk/Imager/Imager.xs
1147 M /trunk/Imager/lib/Imager/Files.pod
1148 M /trunk/Imager/t/t70newgif.t
1149
1150 - added support for registering file readers
1151
1152 - if you supply and unknown type value (or Imager probes and finds
1153 one) then Imager will attempt to load "Imager::File::\Utypecode" (this
1154 can register a file reader.)
1155
1156 - note: these changes may mean slightly different errors if you call
1157 read_multi() with no file or type parameters, since read_multi() now
1158 attempts to do the same file format probe that read() does.
1159
1160 ------------------------------------------------------------------------
1161 r961 | tony | 2006-03-24 00:41:56 +1100 (Fri, 24 Mar 2006) | 5 lines
1162 Changed paths:
1163 M /trunk/Imager/image.c
1164 M /trunk/Imager/imager.h
1165 M /trunk/Imager/t/t1000files.t
1166 M /trunk/Imager/tga.c
1167
1168 - i_test_format_probe() now attempts to detect MS Windows Icon/cursor files
1169
1170 - made the TGA probe a bit more specific since it was giving false
1171 positives on icon files.
1172
1173 ------------------------------------------------------------------------
1174 r960 | tony | 2006-03-22 12:01:15 +1100 (Wed, 22 Mar 2006) | 8 lines
1175 Changed paths:
1176 M /trunk/Imager/Imager.xs
1177 M /trunk/Imager/MANIFEST
1178 M /trunk/Imager/imdatatypes.h
1179 M /trunk/Imager/imperl.h
1180 M /trunk/Imager/iolayer.c
1181 M /trunk/Imager/iolayer.h
1182 A /trunk/Imager/iolayert.h
1183
1184 More iolayers work:
1185
1186 - rename the callback types
1187 - move types and the call macros into iolayer.t
1188 - move typedef for Imager__IO to imperl.h
1189
1190 so now io glue objects can be used from XS/Inline
1191
1192 ------------------------------------------------------------------------
1193 r957 | tony | 2006-03-16 16:41:10 +1100 (Thu, 16 Mar 2006) | 6 lines
1194 Changed paths:
1195 M /trunk/Imager/Imager.xs
1196 M /trunk/Imager/iolayer.c
1197 M /trunk/Imager/iolayer.h
1198 M /trunk/Imager/t/t07iolayer.t
1199
1200 more iolayer goodness:
1201
1202 - make write/read/seek/close on an IO object visible as methods from perl
1203
1204 - allow SEEK_CUR on bufchains
1205
1206 ------------------------------------------------------------------------
1207 r956 | tony | 2006-03-15 23:49:49 +1100 (Wed, 15 Mar 2006) | 3 lines
1208 Changed paths:
1209 M /trunk/Imager/Imager.xs
1210 M /trunk/Imager/iolayer.c
1211 M /trunk/Imager/iolayer.h
1212
1213 io_glue_destroy() now uses an extra callback to handle type specific
1214 destruction, instead of switching on "class"
1215
1216 ------------------------------------------------------------------------
1217 r955 | tony | 2006-03-15 23:08:47 +1100 (Wed, 15 Mar 2006) | 7 lines
1218 Changed paths:
1219 M /trunk/Imager/iolayer.c
1220 M /trunk/Imager/iolayer.h
1221
1222 iolayer modifications:
1223
1224 - move private types and functions into iolayers.c
1225
1226 - make each layer "new" function do the initialization that
1227 io_commit_types() was doing.
1228
1229 ------------------------------------------------------------------------
1230 r954 | tony | 2006-03-15 22:32:59 +1100 (Wed, 15 Mar 2006) | 2 lines
1231 Changed paths:
1232 M /trunk/Imager/MANIFEST
1233
1234 fixed incorrect filename for t/t93podcover.t in MANIFEST
1235
1236 ------------------------------------------------------------------------
1237 r953 | tony | 2006-03-14 11:50:09 +1100 (Tue, 14 Mar 2006) | 6 lines
1238 Changed paths:
1239 M /trunk/Imager/Imager.pm
1240
1241 remove the reference to IRC from SUPPORT, I'm not paying enough
1242 attention there for it to be useful. Yes, there is a channel, but the
1243 mailing list/perlmonks/direct email/cpanratings are more likely to get
1244 you some help.
1245
1246
1247 ------------------------------------------------------------------------
1248 r952 | tony | 2006-03-13 13:46:48 +1100 (Mon, 13 Mar 2006) | 3 lines
1249 Changed paths:
1250 M /trunk/Imager/Imager.pm
1251 M /trunk/Imager/t/t101jpeg.t
1252
1253 prevent the parseiptc method from warning when there's no IPTC data to
1254 process
1255
1256 ------------------------------------------------------------------------
1257 r951 | tony | 2006-03-13 12:58:44 +1100 (Mon, 13 Mar 2006) | 2 lines
1258 Changed paths:
1259 M /trunk/Imager
1260 M /trunk/Imager/MANIFEST
1261 A /trunk/Imager/t/Pod
1262 A /trunk/Imager/t/Pod/Coverage
1263 A /trunk/Imager/t/Pod/Coverage/Imager.pm
1264 M /trunk/Imager/t/t101jpeg.t
1265 A /trunk/Imager/t/t93podcover.t
1266
1267 POD coverage tests, as a TODO for now
1268
1269 ------------------------------------------------------------------------
1270 r950 | tony | 2006-03-12 00:16:47 +1100 (Sun, 12 Mar 2006) | 2 lines
1271 Changed paths:
1272 M /trunk/Imager/Imager.pm
1273 M /trunk/Imager/Imager.xs
1274 M /trunk/Imager/log.c
1275 M /trunk/Imager/log.h
1276 M /trunk/Imager/t/t50basicoo.t
1277
1278 rename some private functions to private names
1279
1280 ------------------------------------------------------------------------
1281 r949 | tony | 2006-03-09 11:56:19 +1100 (Thu, 09 Mar 2006) | 3 lines
1282 Changed paths:
1283 M /trunk/Imager/io.c
1284
1285 malloc_state() no longer writes to stdout when Imager is built without
1286 memory debugging
1287
1288 ------------------------------------------------------------------------
1289 r948 | tony | 2006-03-08 23:11:41 +1100 (Wed, 08 Mar 2006) | 2 lines
1290 Changed paths:
1291 M /trunk/Imager/TODO
1292
1293 initial targets for 0.50
1294
1295 ------------------------------------------------------------------------
1296 r947 | tony | 2006-03-08 22:56:41 +1100 (Wed, 08 Mar 2006) | 7 lines
1297 Changed paths:
1298 M /trunk/Imager/t/t82inline.t
1299
1300 Skip Inline tests when we're in a directory containing spaces in the
1301 path, since Inline itself errors out when used in such a directory.
1302 See #4150.
1303
1304 Fixes: 18049.
1305
1306
1307 ------------------------------------------------------------------------
1308 r946 | tony | 2006-03-07 23:06:50 +1100 (Tue, 07 Mar 2006) | 2 lines
1309 Changed paths:
1310 M /trunk/Imager/png.c
1311
1312 removed unreachable code (mymalloc() succeeds or exit()s)
1313
1314 ------------------------------------------------------------------------
1315 r945 | tony | 2006-03-07 23:01:38 +1100 (Tue, 07 Mar 2006) | 2 lines
1316 Changed paths:
1317 M /trunk/Imager/Makefile.PL
1318
1319 Actually get the changes in the right order.
1320
1321 ------------------------------------------------------------------------
1322 r944 | tony | 2006-03-07 22:54:01 +1100 (Tue, 07 Mar 2006) | 5 lines
1323 Changed paths:
1324 D /trunk/Imager/Changes
1325 A /trunk/Imager/Changes.old (from /trunk/Imager/Changes:943)
1326 M /trunk/Imager/MANIFEST
1327 M /trunk/Imager/Makefile.PL
1328
1329 New changes will be listed most recent first, and is generated from
1330 svn log.
1331
1332 Changes for older revisions of Imager can be found in Changes.old.
1333
1334 ------------------------------------------------------------------------
200 Imager 0.51 - 23 Apr 2006
201 ===========
202
203 - fix a validation bug when processing JPEG EXIF data that can cause
204 a crash
205 http://rt.cpan.org/Public/Bug/Display.html?id=18496
206
207 - fix mis-processing of the src_maxx and src_maxy parameters of the
208 paste() method
209 http://rt.cpan.org/Public/Bug/Display.html?id=18712
210
211 - fix a problem in Imager's "smart" handling of the color parameter
212 to various methods.
213 http://rt.cpan.org/Public/Bug/Display.html?id=18561
214
215
216 Imager 0.50 - 29 Mar 2006
217 ===========
218
219 - CRITICAL: fixes a segmentation fault from attempting to write a 2
220 or 4 channel image to jpeg or a 2 channel image to tga where the
221 output is an in-memeory buffer.
222 http://rt.cpan.org/Public/Bug/Display.html?id=18397
223
224 - fixes an incorrect pointer parameter in the PNG code
225 http://rt.cpan.org/Public/Bug/Display.html?id=18051
226
227 - skip Inline::C tests when building in a directory with spaces
228 http://rt.cpan.org/Public/Bug/Display.html?id=18049
00 #!perl -w
11 use strict;
22 use blib;
3 use lib '../t';
43 use Imager;
54 use Test::More tests => 9;
65
00 #!perl -w
11 use strict;
22 use blib;
3 use lib '../t';
43 use Imager;
54 use Test::More tests => 4;
65
00 #!perl -w
11 use strict;
22 use blib;
3 use lib '../t';
43 use Imager;
54 use Test::More tests => 3;
65
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 94;
43
54 BEGIN { use_ok('Imager::File::ICO'); }
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 1;
43 use Imager;
54
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 1;
43 use Imager;
54
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 25;
43
54 BEGIN { use_ok('Imager::File::CUR'); }
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 1;
43 use Imager;
54
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 1;
43 use Imager;
54
00 #!perl -w
11 use strict;
22 use Imager;
3 use lib '../t';
43 use Test::More tests => 40;
54
65 sub get_data;
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 69;
43 use Imager ':handy';
54
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 1;
43 use Imager;
54 require '../t/testtools.pl';
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 1;
43 use Imager;
54 require '../t/testtools.pl';
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 1;
43 use Imager;
54 require '../t/testtools.pl';
00 #!perl -w
11 use strict;
2 use lib '../t';
32 use Test::More tests => 1;
43 use Imager;
54 require '../t/testtools.pl';
154154 BEGIN {
155155 require Exporter;
156156 @ISA = qw(Exporter);
157 $VERSION = '0.54';
157 $VERSION = '0.56';
158158 eval {
159159 require XSLoader;
160160 XSLoader::load(Imager => $VERSION);
12681268 return $self;
12691269 }
12701270
1271 my $allow_incomplete = $input{allow_incomplete};
1272 defined $allow_incomplete or $allow_incomplete = 0;
1273
12711274 if ( $input{'type'} eq 'tiff' ) {
12721275 my $page = $input{'page'};
12731276 defined $page or $page = 0;
1274 # Fixme, check if that length parameter is ever needed
1275 $self->{IMG}=i_readtiff_wiol( $IO, -1, $page );
1277 $self->{IMG}=i_readtiff_wiol( $IO, $allow_incomplete, $page );
12761278 if ( !defined($self->{IMG}) ) {
12771279 $self->{ERRSTR}=$self->_error_as_msg(); return undef;
12781280 }
12811283 }
12821284
12831285 if ( $input{'type'} eq 'pnm' ) {
1284 $self->{IMG}=i_readpnm_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
1286 $self->{IMG}=i_readpnm_wiol( $IO, $allow_incomplete );
12851287 if ( !defined($self->{IMG}) ) {
12861288 $self->{ERRSTR}='unable to read pnm image: '._error_as_msg();
12871289 return undef;
13001302 }
13011303
13021304 if ( $input{'type'} eq 'bmp' ) {
1303 $self->{IMG}=i_readbmp_wiol( $IO );
1305 $self->{IMG}=i_readbmp_wiol( $IO, $allow_incomplete );
13041306 if ( !defined($self->{IMG}) ) {
13051307 $self->{ERRSTR}=$self->_error_as_msg();
13061308 return undef;
16741676 $self->_set_opts(\%input, "bmp_", $self)
16751677 or return undef;
16761678 if ( !i_writebmp_wiol($self->{IMG}, $IO) ) {
1677 $self->{ERRSTR}='unable to write bmp image';
1679 $self->{ERRSTR} = $self->_error_as_msg;
16781680 return undef;
16791681 }
16801682 $self->{DEBUG} && print "writing a bmp file\n";
32533255 unless ($self->{IMG}) { $self->{ERRSTR}='empty input image'; return undef; }
32543256
32553257 my %input=('x'=>0, 'y'=>0, @_);
3256 $input{string}||=$input{text};
3258 defined($input{string}) or $input{string} = $input{text};
32573259
32583260 unless(defined $input{string}) {
32593261 $self->{ERRSTR}="missing required parameter 'string'";
436436 size -= cbd->used - cbd->where;
437437 out += cbd->used - cbd->where;
438438 if (size < sizeof(cbd->buffer)) {
439 int did_read;
439 int did_read = 0;
440440 int copy_size;
441441 while (size
442442 && (did_read = call_reader(cbd, cbd->buffer, size,
534534 { "webmap", mc_web_map, },
535535 { "addi", mc_addi, },
536536 { "mediancut", mc_median_cut, },
537 { "mono", mc_mono, },
538 { "monochrome", mc_mono, },
537539 };
538540
539541 static struct value_name translate_names[] =
22492251 #ifdef HAVE_LIBTIFF
22502252
22512253 Imager::ImgRaw
2252 i_readtiff_wiol(ig, length, page=0)
2254 i_readtiff_wiol(ig, allow_incomplete, page=0)
22532255 Imager::IO ig
2254 int length
2256 int allow_incomplete
22552257 int page
22562258
22572259 void
28802882
28812883
28822884 Imager::ImgRaw
2883 i_readpnm_wiol(ig, length)
2885 i_readpnm_wiol(ig, allow_incomplete)
28842886 Imager::IO ig
2885 int length
2887 int allow_incomplete
28862888
28872889
28882890 undef_int
29112913 Imager::IO ig
29122914
29132915 Imager::ImgRaw
2914 i_readbmp_wiol(ig)
2916 i_readbmp_wiol(ig, allow_incomplete=0)
29152917 Imager::IO ig
2918 int allow_incomplete
29162919
29172920
29182921 undef_int
35643567 PREINIT:
35653568 i_palidx *work;
35663569 int i;
3567 STRLEN len;
3568 int count;
35693570 CODE:
35703571 if (items > 3) {
35713572 work = mymalloc(sizeof(i_palidx) * (items-3));
35903591 SV *data
35913592 PREINIT:
35923593 i_palidx const *work;
3593 int i;
35943594 STRLEN len;
3595 int count;
35963595 CODE:
35973596 work = (i_palidx const *)SvPV(data, len);
35983597 len /= sizeof(i_palidx);
41914190 #ifdef HAVE_WIN32
41924191
41934192 void
4194 i_wf_bbox(face, size, text)
4193 i_wf_bbox(face, size, text_sv, utf8=0)
41954194 char *face
41964195 int size
4197 char *text
4196 SV *text_sv
4197 int utf8
41984198 PREINIT:
41994199 int cords[BOUNDING_BOX_COUNT];
42004200 int rc, i;
4201 char const *text;
4202 STRLEN text_len;
42014203 PPCODE:
4202 if (rc = i_wf_bbox(face, size, text, strlen(text), cords)) {
4204 text = SvPV(text_sv, text_len);
4205 #ifdef SvUTF8
4206 if (SvUTF8(text_sv))
4207 utf8 = 1;
4208 #endif
4209 if (rc = i_wf_bbox(face, size, text, text_len, cords, utf8)) {
42034210 EXTEND(SP, rc);
42044211 for (i = 0; i < rc; ++i)
42054212 PUSHs(sv_2mortal(newSViv(cords[i])));
42064213 }
42074214
42084215 undef_int
4209 i_wf_text(face, im, tx, ty, cl, size, text, align, aa)
4216 i_wf_text(face, im, tx, ty, cl, size, text_sv, align, aa, utf8 = 0)
42104217 char *face
42114218 Imager::ImgRaw im
42124219 int tx
42134220 int ty
42144221 Imager::Color cl
42154222 int size
4216 char *text
4223 SV *text_sv
42174224 int align
42184225 int aa
4226 int utf8
4227 PREINIT:
4228 char const *text;
4229 STRLEN text_len;
42194230 CODE:
4220 RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text),
4221 align, aa);
4231 text = SvPV(text_sv, text_len);
4232 #ifdef SvUTF8
4233 if (SvUTF8(text_sv))
4234 utf8 = 1;
4235 #endif
4236 RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, text_len,
4237 align, aa, utf8);
42224238 OUTPUT:
42234239 RETVAL
42244240
42254241 undef_int
4226 i_wf_cp(face, im, tx, ty, channel, size, text, align, aa)
4242 i_wf_cp(face, im, tx, ty, channel, size, text_sv, align, aa, utf8 = 0)
42274243 char *face
42284244 Imager::ImgRaw im
42294245 int tx
42304246 int ty
42314247 int channel
42324248 int size
4233 char *text
4249 SV *text_sv
42344250 int align
42354251 int aa
4252 int utf8
4253 PREINIT:
4254 char const *text;
4255 STRLEN text_len;
42364256 CODE:
4237 RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text),
4238 align, aa);
4257 text = SvPV(text_sv, text_len);
4258 #ifdef SvUTF8
4259 if (SvUTF8(text_sv))
4260 utf8 = 1;
4261 #endif
4262 RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, text_len,
4263 align, aa, utf8);
42394264 OUTPUT:
42404265 RETVAL
42414266
43894414 RETVAL
43904415
43914416 undef_int
4392 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8)
4417 i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text_sv, align, aa, vlayout, utf8)
43934418 Imager::Font::FT2 font
43944419 Imager::ImgRaw im
43954420 int tx
43974422 int channel
43984423 double cheight
43994424 double cwidth
4400 char *text
4425 SV *text_sv
44014426 int align
44024427 int aa
44034428 int vlayout
44044429 int utf8
4430 PREINIT:
4431 char const *text;
4432 STRLEN len;
44054433 CODE:
44064434 #ifdef SvUTF8
44074435 if (SvUTF8(ST(7)))
44084436 utf8 = 1;
44094437 #endif
4438 text = SvPV(text_sv, len);
44104439 RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
4411 strlen(text), align, aa, vlayout, 1);
4440 len, align, aa, vlayout, 1);
44124441 OUTPUT:
44134442 RETVAL
44144443
116116 imgdouble.c Implements double/sample images
117117 imio.h
118118 imperl.h
119 imrender.h Buffer rending engine function declarations
119120 imtoc.perl Sample size adapter pre-processor
120121 io.c
121122 iolayer.c
150151 lib/Imager/Inline.pod Using Imager with Inline::C
151152 lib/Imager/Matrix2d.pm
152153 lib/Imager/Regops.pm
154 lib/Imager/Test.pm
153155 lib/Imager/Transform.pm
154156 lib/Imager/Transformations.pod
155157 lib/Imager/Tutorial.pod
171173 regmach.c
172174 regmach.h
173175 regops.perl
176 render.im
177 rendert.h Buffer rendering engine types
174178 rgb.c Reading and writing SGI rgb files
175179 rotate.c
176180 rubthru.im
178182 samples/align-string.pl Demonstrate align_string method.
179183 samples/anaglyph.pl
180184 samples/border.pl Demonstrate adding a border
185 samples/flasher.pl Animate an source image fading to a color and back
181186 samples/inline_capture2image.pl convert captured BGR data to an image
182187 samples/inline_replace_color.pl replace colors using Inline::C
183188 samples/interleave.pl
195200 stackmach.c
196201 stackmach.h
197202 t/Pod/Coverage/Imager.pm
198 t/Test/Builder.pm
199 t/Test/More.pm
200203 t/t00basic.t
201204 t/t01introvert.t
202205 t/t020masked.t
271274 testimg/badused1.bmp 1-bit/pixel, out of range colors used value
272275 testimg/badused4a.bmp 4-bit/pixel, badly out of range used value (SEGV test)
273276 testimg/badused4b.bmp 4-bit/pixel, just out of range used value (SEGV test)
277 testimg/bad_asc.pbm ASCII PBM with invalid image data
278 testimg/bad_asc.pgm ASCII PGM with invalid image data
279 testimg/bad_asc.ppm ASCII PPM with invalid image data
274280 testimg/bandw.gif
275281 testimg/base.jpg Base JPEG test image
276282 testimg/comp4.bmp Compressed 4-bit/pixel BMP
295301 testimg/palette.png
296302 testimg/palette_out.png
297303 testimg/penguin-base.ppm
304 testimg/pgm.pgm Simple pgm for testing the right sample is in the right place
298305 testimg/scale.gif
299306 testimg/scale.ppm
300307 testimg/scalei.gif
310317 testimg/short4rle.bmp truncated 4bit/pixel compressed BMP
311318 testimg/short8.bmp 8-bit/pixel, data missing from EOF
312319 testimg/short8rle.bmp 8-bit/pixel compressed, data missing from EOF
320 testimg/short_asc.pbm ASCII PBM with short image section
321 testimg/short_asc.pgm ASCII PGM with short image section
322 testimg/short_asc.ppm ASCII PPM with short image section
323 testimg/short_bin.pbm Bin PBM with short image section
324 testimg/short_bin.pgm Bin PGM with short image section
325 testimg/short_bin.ppm Bin PPM with short image section
326 testimg/short_bin16.pgm 16-bit Bin PGM with short image section
327 testimg/short_bin16.ppm 16-bit Bin PPM with short image section
313328 testimg/simple.pbm
314329 testimg/slab.tif Lab color image
315330 testimg/srgb.tif Simple RGB image
00 --- #YAML:1.0
11 name: Imager
2 version: 0.54
2 version: 0.56
33 version_from: Imager.pm
44 author: Tony Cook <tony@imager.perl.org>, Arnar M. Hrafnkelsson
55 abstract: Perl extension for Generating 24 bit Images
66 installdirs: site
77 recommends:
88 Parse::RecDescent: 0
9 requires:
10 Test::More: 0.47
911 license: perl
1012 dynamic_config: 1
1113 distribution_type: module
12 generated_by: Imager version 0.54
14 meta-spec:
15 version: 1.3
16 url: http://module-build.sourceforge.net/META-spec-v1.3.html
17 generated_by: Imager version 0.56
3838 my $noprobe; # non-zero to disable newer probes
3939 my $noexif; # non-zero to disable EXIF parsing of JPEGs
4040 my $no_gif_set_version; # disable calling EGifSetGifVersion
41 my $coverage; # build for coverage testing
4142 GetOptions("help" => \$help,
4243 "enable=s" => \@enable,
4344 "disable=s" => \@disable,
4748 "verbose|v" => \$VERBOSE,
4849 "nolog" => \$NOLOG,
4950 "noexif" => \$noexif,
50 "nogifsetversion" => \$no_gif_set_version);
51 "nogifsetversion" => \$no_gif_set_version,
52 'coverage' => \$coverage);
5153
5254 if ($VERBOSE) {
5355 print "Verbose mode\n";
8385
8486 init(); # initialize global data
8587 pathcheck(); # Check if directories exist
86 distcheck(); # for building dists
8788
8889 if (exists $ENV{IM_ENABLE}) {
8990 my %en = map { $_, 1 } split ' ', $ENV{IM_ENABLE};
156157 regmach.o trans2.o quant.o error.o convert.o
157158 map.o tags.o palimg.o maskimg.o img16.o rotate.o
158159 bmp.o tga.o rgb.o color.o fills.o imgdouble.o limits.o hlines.o
159 imext.o scale.o rubthru.o);
160 imext.o scale.o rubthru.o render.o);
160161
161162 $Recommends{Imager} =
162163 { 'Parse::RecDescent' => 0 };
170171 'OBJECT' => join(' ', @objs, $F_OBJECT),
171172 clean => { FILES=>'testout meta.tmp rubthru.c scale.c' },
172173 PM => gen_PM(),
174 PREREQ_PM => { 'Test::More' => 0.47 },
173175 );
176
177 if ($coverage) {
178 if ($Config{gccversion}) {
179 push @ARGV, 'OPTIMIZE=-ftest-coverage -fprofile-arcs';
180 #$opts{dynamic_lib} = { OTHERLDFLAGS => '-ftest-coverage -fprofile-arcs' };
181 }
182 else {
183 die "Don't know the coverage C flags for your compiler\n";
184 }
185 }
174186
175187 # eval to prevent warnings about versions with _ in them
176188 my $MM_ver = eval $ExtUtils::MakeMaker::VERSION;
397409 if ($^O =~ /win32/i && $Config{cc} =~ /\bcl\b/i) {
398410 push(@incs, split /;/, $ENV{INCLUDE}) if exists $ENV{INCLUDE};
399411 }
412 if ($Config{incpath}) {
413 push @incs, grep -d, split /\Q$Config{path_sep}/, $Config{incpath};
414 }
400415 push @incs, grep -d,
401416 qw(/sw/include
402417 /usr/include/freetype2
466481 def=>'HAVE_LIBPNG',
467482 inccheck=>sub { -e catfile($_[0], 'png.h') },
468483 libcheck=>sub { $_[0] eq "libpng$aext" or $_[0] eq "libpng.$lext" },
469 libfiles=>'-lpng -lz',
484 libfiles=>$^O eq 'MSWin32' ? '-lpng -lzlib' : '-lpng -lz',
470485 objfiles=>'png.o',
471486 docs=>q{
472487 Png stands for Portable Network Graphics and is intended as
851866 $meta .= " $module: $version\n";
852867 }
853868 }
869 if ($opts->{PREREQ_PM}) {
870 $meta .= "requires:\n";
871 while (my ($module, $version) = each %{$opts->{PREREQ_PM}}) {
872 $meta .= " $module: $version\n";
873 }
874 }
854875 $meta .= <<YAML;
855876 license: perl
856877 dynamic_config: 1
857878 distribution_type: module
879 meta-spec:
880 version: 1.3
881 url: http://module-build.sourceforge.net/META-spec-v1.3.html
858882 generated_by: $opts->{NAME} version $version
859883 YAML
860884 my $save_meta;
875899 }
876900 }
877901
878 # this is intended to only be running on the development
879 # machines
880 sub distcheck {
881 if (-e '.svn') {
882 # update Changes if needed
883 my $write_changes;
884 # get the last revision from Changes
885 if (open CHANGES, "< Changes") {
886 <CHANGES>;
887 my ($changes_rev) = <CHANGES> =~ /^r(\d+)/
888 or ++$write_changes;
889
890 my ($revision) = grep s/^Revision: //, `svn info`
891 or die "Could not get Revision from svn";
892 chomp $revision;
893
894 $write_changes ||= $changes_rev != $revision;
895 close CHANGES;
896 }
897 else {
898 ++$write_changes;
899 }
900 if ($write_changes) {
901 print "Updating Changes file\n";
902 system 'svn log -v -r HEAD:943 >Changes';
903 }
904 }
905 }
+142
-58
bmp.c less more
4444 static int write_24bit_data(io_glue *ig, i_img *im);
4545 static int read_bmp_pal(io_glue *ig, i_img *im, int count);
4646 static i_img *read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
47 int compression, long offbits);
47 int compression, long offbits, int allow_incomplete);
4848 static i_img *read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
49 int compression, long offbits);
49 int compression, long offbits, int allow_incomplete);
5050 static i_img *read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
51 int compression, long offbits);
51 int compression, long offbits, int allow_incomplete);
5252 static i_img *read_direct_bmp(io_glue *ig, int xsize, int ysize,
5353 int bit_count, int clr_used, int compression,
54 long offbits);
54 long offbits, int allow_incomplete);
5555
5656 /*
5757 =item i_writebmp_wiol(im, io_glue)
101101 */
102102
103103 i_img *
104 i_readbmp_wiol(io_glue *ig) {
104 i_readbmp_wiol(io_glue *ig, int allow_incomplete) {
105105 int b_magic, m_magic, filesize, res1, res2, infohead_size;
106106 int xsize, ysize, planes, bit_count, compression, size_image, xres, yres;
107107 int clr_used, clr_important, offbits;
117117 &xsize, &ysize, &planes,
118118 &bit_count, &compression, &size_image, &xres, &yres,
119119 &clr_used, &clr_important)) {
120 i_push_error(0, "file too short");
120 i_push_error(0, "file too short to be a BMP file");
121121 return 0;
122122 }
123123 if (b_magic != 'B' || m_magic != 'M' || infohead_size != INFOHEAD_SIZE
132132 bit_count, compression, size_image, xres, yres, clr_used,
133133 clr_important));
134134
135 if (!i_int_check_image_file_limits(xsize, ysize, 3, sizeof(i_sample_t))) {
135 if (!i_int_check_image_file_limits(xsize, abs(ysize), 3, sizeof(i_sample_t))) {
136136 mm_log((1, "i_readbmp_wiol: image size exceeds limits\n"));
137137 return NULL;
138138 }
139139
140140 switch (bit_count) {
141141 case 1:
142 im = read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
142 im = read_1bit_bmp(ig, xsize, ysize, clr_used, compression, offbits,
143 allow_incomplete);
143144 break;
144145
145146 case 4:
146 im = read_4bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
147 im = read_4bit_bmp(ig, xsize, ysize, clr_used, compression, offbits,
148 allow_incomplete);
147149 break;
148150
149151 case 8:
150 im = read_8bit_bmp(ig, xsize, ysize, clr_used, compression, offbits);
152 im = read_8bit_bmp(ig, xsize, ysize, clr_used, compression, offbits,
153 allow_incomplete);
151154 break;
152155
153156 case 32:
154157 case 24:
155158 case 16:
156159 im = read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression,
157 offbits);
160 offbits, allow_incomplete);
158161 break;
159162
160163 default:
662665 */
663666 static i_img *
664667 read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
665 int compression, long offbits) {
668 int compression, long offbits, int allow_incomplete) {
666669 i_img *im;
667 int x, y, lasty, yinc;
670 int x, y, lasty, yinc, start_y;
668671 i_palidx *line, *p;
669672 unsigned char *packed;
670673 int line_size = (xsize + 7)/8;
689692 line_size = (line_size+3) / 4 * 4;
690693
691694 if (ysize > 0) {
692 y = ysize-1;
695 start_y = ysize-1;
693696 lasty = -1;
694697 yinc = -1;
695698 }
696699 else {
697700 /* when ysize is -ve it's a top-down image */
698701 ysize = -ysize;
699 y = 0;
702 start_y = 0;
700703 lasty = ysize;
701704 yinc = 1;
702705 }
706 y = start_y;
703707 if (!clr_used)
704708 clr_used = 2;
705709 if (clr_used < 0 || clr_used > 2) {
743747 if (ig->readcb(ig, packed, line_size) != line_size) {
744748 myfree(packed);
745749 myfree(line);
746 i_push_error(0, "failed reading 1-bit bmp data");
747 i_img_destroy(im);
748 return NULL;
750 if (allow_incomplete) {
751 i_tags_setn(&im->tags, "i_incomplete", 1);
752 i_tags_setn(&im->tags, "i_lines_read", abs(start_y - y));
753 return im;
754 }
755 else {
756 i_push_error(0, "failed reading 1-bit bmp data");
757 i_img_destroy(im);
758 return NULL;
759 }
749760 }
750761 in = packed;
751762 bit = 0x80;
781792 */
782793 static i_img *
783794 read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
784 int compression, long offbits) {
795 int compression, long offbits, int allow_incomplete) {
785796 i_img *im;
786797 int x, y, lasty, yinc;
787798 i_palidx *line, *p;
790801 unsigned char *in;
791802 int size, i;
792803 long base_offset;
804 int starty;
793805
794806 /* line_size is going to be smaller than xsize in most cases (and
795807 when it's not, xsize is itself small), and hence not overflow */
796808 line_size = (line_size+3) / 4 * 4;
797809
798810 if (ysize > 0) {
799 y = ysize-1;
811 starty = ysize-1;
800812 lasty = -1;
801813 yinc = -1;
802814 }
803815 else {
804816 /* when ysize is -ve it's a top-down image */
805817 ysize = -ysize;
806 y = 0;
818 starty = 0;
807819 lasty = ysize;
808820 yinc = 1;
809821 }
822 y = starty;
810823 if (!clr_used)
811824 clr_used = 16;
812825
855868 if (ig->readcb(ig, packed, line_size) != line_size) {
856869 myfree(packed);
857870 myfree(line);
858 i_push_error(0, "failed reading 4-bit bmp data");
859 i_img_destroy(im);
860 return NULL;
871 if (allow_incomplete) {
872 i_tags_setn(&im->tags, "i_incomplete", 1);
873 i_tags_setn(&im->tags, "i_lines_read", abs(y - starty));
874 return im;
875 }
876 else {
877 i_push_error(0, "failed reading 4-bit bmp data");
878 i_img_destroy(im);
879 return NULL;
880 }
861881 }
862882 in = packed;
863883 p = line;
883903 if (ig->readcb(ig, packed, 2) != 2) {
884904 myfree(packed);
885905 myfree(line);
886 i_push_error(0, "missing data during decompression");
887 i_img_destroy(im);
888 return NULL;
906 if (allow_incomplete) {
907 i_tags_setn(&im->tags, "i_incomplete", 1);
908 i_tags_setn(&im->tags, "i_lines_read", abs(y - starty));
909 return im;
910 }
911 else {
912 i_push_error(0, "missing data during decompression");
913 i_img_destroy(im);
914 return NULL;
915 }
889916 }
890917 else if (packed[0]) {
891918 line[0] = packed[1] >> 4;
913940 if (ig->readcb(ig, packed, 2) != 2) {
914941 myfree(packed);
915942 myfree(line);
916 i_push_error(0, "missing data during decompression");
917 i_img_destroy(im);
918 return NULL;
943 if (allow_incomplete) {
944 i_tags_setn(&im->tags, "i_incomplete", 1);
945 i_tags_setn(&im->tags, "i_lines_read", abs(y - starty));
946 return im;
947 }
948 else {
949 i_push_error(0, "missing data during decompression");
950 i_img_destroy(im);
951 return NULL;
952 }
919953 }
920954 x += packed[0];
921955 y += yinc * packed[1];
928962 if (ig->readcb(ig, packed, read_size) != read_size) {
929963 myfree(packed);
930964 myfree(line);
931 i_push_error(0, "missing data during decompression");
932 /*i_img_destroy(im);*/
933 return im;
965 if (allow_incomplete) {
966 i_tags_setn(&im->tags, "i_incomplete", 1);
967 i_tags_setn(&im->tags, "i_lines_read", abs(y - starty));
968 return im;
969 }
970 else {
971 i_push_error(0, "missing data during decompression");
972 i_img_destroy(im);
973 return NULL;
974 }
934975 }
935976 for (i = 0; i < size; ++i) {
936977 line[0] = packed[i] >> 4;
955996 }
956997
957998 /*
958 =item read_8bit_bmp(ig, xsize, ysize, clr_used, compression)
999 =item read_8bit_bmp(ig, xsize, ysize, clr_used, compression, allow_incomplete)
9591000
9601001 Reads in the palette and image data for a 8-bit/pixel image.
9611002
9651006 */
9661007 static i_img *
9671008 read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used,
968 int compression, long offbits) {
1009 int compression, long offbits, int allow_incomplete) {
9691010 i_img *im;
970 int x, y, lasty, yinc;
1011 int x, y, lasty, yinc, start_y;
9711012 i_palidx *line;
9721013 int line_size = xsize;
9731014 long base_offset;
9791020 }
9801021
9811022 if (ysize > 0) {
982 y = ysize-1;
1023 start_y = ysize-1;
9831024 lasty = -1;
9841025 yinc = -1;
9851026 }
9861027 else {
9871028 /* when ysize is -ve it's a top-down image */
9881029 ysize = -ysize;
989 y = 0;
1030 start_y = 0;
9901031 lasty = ysize;
9911032 yinc = 1;
9921033 }
1034 y = start_y;
9931035 if (!clr_used)
9941036 clr_used = 256;
9951037 if (clr_used > 256 || clr_used < 0) {
10311073 while (y != lasty) {
10321074 if (ig->readcb(ig, line, line_size) != line_size) {
10331075 myfree(line);
1034 i_push_error(0, "failed reading 8-bit bmp data");
1035 i_img_destroy(im);
1036 return NULL;
1076 if (allow_incomplete) {
1077 i_tags_setn(&im->tags, "i_incomplete", 1);
1078 i_tags_setn(&im->tags, "i_lines_read", abs(start_y - y));
1079 return im;
1080 }
1081 else {
1082 i_push_error(0, "failed reading 8-bit bmp data");
1083 i_img_destroy(im);
1084 return NULL;
1085 }
10371086 }
10381087 i_ppal(im, 0, xsize, y, line);
10391088 y += yinc;
10511100 /* there's always at least 2 bytes in a sequence */
10521101 if (ig->readcb(ig, packed, 2) != 2) {
10531102 myfree(line);
1054 i_push_error(0, "missing data during decompression");
1055 i_img_destroy(im);
1056 return NULL;
1103 if (allow_incomplete) {
1104 i_tags_setn(&im->tags, "i_incomplete", 1);
1105 i_tags_setn(&im->tags, "i_lines_read", abs(start_y-y));
1106 return im;
1107 }
1108 else {
1109 i_push_error(0, "missing data during decompression");
1110 i_img_destroy(im);
1111 return NULL;
1112 }
10571113 }
10581114 if (packed[0]) {
10591115 memset(line, packed[1], packed[0]);
10731129 case BMPRLE_DELTA:
10741130 if (ig->readcb(ig, packed, 2) != 2) {
10751131 myfree(line);
1076 i_push_error(0, "missing data during decompression");
1077 i_img_destroy(im);
1078 return NULL;
1132 if (allow_incomplete) {
1133 i_tags_setn(&im->tags, "i_incomplete", 1);
1134 i_tags_setn(&im->tags, "i_lines_read", abs(start_y-y));
1135 return im;
1136 }
1137 else {
1138 i_push_error(0, "missing data during decompression");
1139 i_img_destroy(im);
1140 return NULL;
1141 }
10791142 }
10801143 x += packed[0];
10811144 y += yinc * packed[1];
10861149 read_size = (count+1) / 2 * 2;
10871150 if (ig->readcb(ig, line, read_size) != read_size) {
10881151 myfree(line);
1089 i_push_error(0, "missing data during decompression");
1090 i_img_destroy(im);
1091 return NULL;
1152 if (allow_incomplete) {
1153 i_tags_setn(&im->tags, "i_incomplete", 1);
1154 i_tags_setn(&im->tags, "i_lines_read", abs(start_y-y));
1155 return im;
1156 }
1157 else {
1158 i_push_error(0, "missing data during decompression");
1159 i_img_destroy(im);
1160 return NULL;
1161 }
10921162 }
10931163 i_ppal(im, x, x+count, y, line);
10941164 x += count;
11281198 };
11291199
11301200 /*
1131 =item read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression)
1201 =item read_direct_bmp(ig, xsize, ysize, bit_count, clr_used, compression, allow_incomplete)
11321202
11331203 Skips the palette and reads in the image data for a direct colour image.
11341204
11381208 */
11391209 static i_img *
11401210 read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count,
1141 int clr_used, int compression, long offbits) {
1211 int clr_used, int compression, long offbits,
1212 int allow_incomplete) {
11421213 i_img *im;
1143 int x, y, lasty, yinc;
1214 int x, y, starty, lasty, yinc;
11441215 i_color *line, *p;
11451216 int pix_size = bit_count / 8;
11461217 int line_size = xsize * pix_size;
11601231 extras = line_size - xsize * pix_size;
11611232
11621233 if (ysize > 0) {
1163 y = ysize-1;
1234 starty = ysize-1;
11641235 lasty = -1;
11651236 yinc = -1;
11661237 }
11671238 else {
11681239 /* when ysize is -ve it's a top-down image */
11691240 ysize = -ysize;
1170 y = 0;
1241 starty = 0;
11711242 lasty = ysize;
11721243 yinc = 1;
11731244 }
1245 y = starty;
11741246 if (compression == BI_RGB) {
11751247 compression_name = "BI_RGB";
11761248 masks = std_masks[pix_size-2];
12101282 return NULL;
12111283 }
12121284
1285 if (offbits < base_offset) {
1286 i_push_errorf(0, "image data offset too small (%ld)", offbits);
1287 return NULL;
1288 }
1289
12131290 if (offbits > base_offset) {
12141291 /* this will be slow if the offset is large, but that should be
12151292 rare */
12431320 for (x = 0; x < xsize; ++x) {
12441321 unsigned pixel;
12451322 if (!read_packed(ig, unpack_code, &pixel)) {
1246 i_push_error(0, "failed reading image data");
12471323 myfree(line);
1248 i_img_destroy(im);
1249 return NULL;
1324 if (allow_incomplete) {
1325 i_tags_setn(&im->tags, "i_incomplete", 1);
1326 i_tags_setn(&im->tags, "i_lines_read", abs(starty - y));
1327 return im;
1328 }
1329 else {
1330 i_push_error(0, "failed reading image data");
1331 i_img_destroy(im);
1332 return NULL;
1333 }
12501334 }
12511335 for (i = 0; i < 3; ++i) {
12521336 if (masks.shifts[i] > 0)
3232 =cut
3333 */
3434 void i_rgb_to_hsvf(i_fcolor *color) {
35 double h, s, v;
35 double h = 0, s, v;
3636 double temp;
3737 double Cr, Cg, Cb;
3838
7373 =cut
7474 */
7575 void i_rgb_to_hsv(i_color *color) {
76 double h, s, v;
76 double h = 0, s, v;
7777 double temp;
7878 double Cr, Cg, Cb;
7979
620620 fill->base.fill_with_color = fill_hatch;
621621 fill->base.fill_with_fcolor = fill_hatchf;
622622 fill->base.destroy = NULL;
623 fill->fg = fg ? *fg : fcolor_to_color(ffg);
624 fill->bg = bg ? *bg : fcolor_to_color(fbg);
625 fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
626 fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
623 /* Some Sun C didn't like the condition expressions that were here.
624 See https://rt.cpan.org/Ticket/Display.html?id=21944
625 */
626 if (fg)
627 fill->fg = *fg;
628 else
629 fill->fg = fcolor_to_color(ffg);
630 if (bg)
631 fill->bg = *bg;
632 else
633 fill->bg = fcolor_to_color(fbg);
634 if (ffg)
635 fill->ffg = *ffg;
636 else
637 fill->ffg = color_to_fcolor(fg);
638 if (fbg)
639 fill->fbg = *fbg;
640 else
641 fill->fbg = color_to_fcolor(bg);
627642 if (combine) {
628643 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
629644 }
660675 int mask = 128 >> xpos;
661676
662677 while (width-- > 0) {
663 *data++ = (byte & mask) ? f->fg : f->bg;
678 if (byte & mask)
679 *data++ = f->fg;
680 else
681 *data++ = f->bg;
664682
665683 if ((mask >>= 1) == 0)
666684 mask = 128;
682700 int mask = 128 >> xpos;
683701
684702 while (width-- > 0) {
685 *data++ = (byte & mask) ? f->ffg : f->fbg;
703 if (byte & mask)
704 *data++ = f->ffg;
705 else
706 *data++ = f->fbg;
686707
687708 if ((mask >>= 1) == 0)
688709 mask = 128;
19451945 printf("'%s'\n", name);
19461946 }
19471947 }
1948 fflush(stdout);
19481949 }
19491950
19501951 int
19651966 }
19661967
19671968 if (handle->load_cond) {
1968 i_push_errorf(rc, "error loading names (%d)", handle->load_cond);
1969 i_push_errorf(handle->load_cond, "error loading names (%d)", handle->load_cond);
19691970 return 0;
19701971 }
19711972
326326 FT_Glyph_Metrics *gm;
327327 int start = 0;
328328 int loadFlags = FT_LOAD_DEFAULT;
329 int rightb;
329 int rightb = 0;
330330
331331 mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %d, bbox %p)\n",
332332 handle, cheight, cwidth, text, len, bbox));
644644 int ch;
645645 i_color pel;
646646 int loadFlags = FT_LOAD_DEFAULT;
647 i_render render;
647648
648649 mm_log((1, "i_ft2_text(handle %p, im %p, tx %d, ty %d, cl %p, cheight %f, cwidth %f, text %p, len %d, align %d, aa %d)\n",
649650 handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
661662 /* set the base-line based on the string ascent */
662663 if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
663664 return 0;
665
666 if (aa)
667 i_render_init(&render, im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
664668
665669 if (!align) {
666670 /* this may need adjustment */
687691 ft2_push_message(error);
688692 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
689693 c, index);
694 if (aa)
695 i_render_done(&render);
690696 return 0;
691697 }
692698 slot = handle->face->glyph;
697703 if (error) {
698704 ft2_push_message(error);
699705 i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
706 if (aa)
707 i_render_done(&render);
700708 return 0;
701709 }
702710 if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
727735 last_mode = slot->bitmap.pixel_mode;
728736 last_grays = slot->bitmap.num_grays;
729737 }
730
738
731739 bmp = slot->bitmap.buffer;
732740 for (y = 0; y < slot->bitmap.rows; ++y) {
733 for (x = 0; x < slot->bitmap.width; ++x) {
734 int value = map[bmp[x]];
735 if (value) {
736 i_gpix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
737 for (ch = 0; ch < im->channels; ++ch) {
738 pel.channel[ch] =
739 ((255-value)*pel.channel[ch] + value * cl->channel[ch]) / 255;
740 }
741 i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, &pel);
742 }
743 }
741 if (last_mode == ft_pixel_mode_grays &&
742 last_grays != 255) {
743 for (x = 0; x < slot->bitmap.width; ++x)
744 bmp[x] = map[bmp[x]];
745 }
746 i_render_color(&render, tx + slot->bitmap_left, ty-slot->bitmap_top+y,
747 slot->bitmap.width, bmp, cl);
744748 bmp += slot->bitmap.pitch;
745749 }
746750 }
749753 tx += slot->advance.x / 64;
750754 ty -= slot->advance.y / 64;
751755 }
756
757 if (aa)
758 i_render_done(&render);
752759
753760 return 1;
754761 }
+14
-14
gif.c less more
00 #include "imageri.h"
11 #include <gif_lib.h>
2 #ifdef _MSCVER
2 #ifdef _MSC_VER
33 #include <io.h>
44 #else
55 #include <unistd.h>
518518
519519 GifRowType GifRow;
520520 int got_gce = 0;
521 int trans_index; /* transparent index if we see a GCE */
522 int gif_delay; /* delay from a GCE */
523 int user_input; /* user input flag from a GCE */
524 int disposal; /* disposal method from a GCE */
521 int trans_index = 0; /* transparent index if we see a GCE */
522 int gif_delay = 0; /* delay from a GCE */
523 int user_input = 0; /* user input flag from a GCE */
524 int disposal = 0; /* disposal method from a GCE */
525525 int got_ns_loop = 0;
526 int ns_loop;
526 int ns_loop = 0;
527527 char *comment = NULL; /* a comment */
528528 i_img **results = NULL;
529529 int result_alloc = 0;
747747 else
748748 trans_index = -1;
749749 gif_delay = Extension[2] + 256 * Extension[3];
750 user_input = (Extension[0] & 2) != 0;
751 disposal = (Extension[0] >> 2) & 3;
750 user_input = (Extension[1] & 2) != 0;
751 disposal = (Extension[1] >> 2) & 7;
752752 }
753753 if (ExtCode == 0xFF && *Extension == 11) {
754754 if (memcmp(Extension+1, "NETSCAPE2.0", 11) == 0) {
16591659
16601660 static undef_int
16611661 i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
1662 unsigned char *result;
1662 unsigned char *result = NULL;
16631663 int color_bits;
16641664 ColorMapObject *map;
16651665 int scrw = 0, scrh = 0;
16661666 int imgn, orig_count, orig_size;
16671667 int posx, posy;
1668 int trans_index;
1668 int trans_index = -1;
16691669 i_mempool mp;
16701670 int *localmaps;
16711671 int anylocal;
16731673 int glob_img_count;
16741674 i_color *orig_colors = quant->mc_colors;
16751675 i_color *glob_colors = NULL;
1676 int glob_color_count;
1676 int glob_color_count = 0;
16771677 int glob_want_trans;
1678 int glob_paletted; /* the global map was made from the image palettes */
1679 int colors_paletted;
1680 int want_trans;
1678 int glob_paletted = 0; /* the global map was made from the image palettes */
1679 int colors_paletted = 0;
1680 int want_trans = 0;
16811681 int interlace;
16821682 int gif_background;
16831683
21522152 return NULL;
21532153 }
21542154
2155
2156
2157
2158 /*
2155 /*
2156 =item i_img_is_monochrome(img, &zero_is_white)
2157
2158 Tests an image to check it meets our monochrome tests.
2159
2160 The idea is that a file writer can use this to test where it should
2161 write the image in whatever bi-level format it uses, eg. pbm for pnm.
2162
2163 For performance of encoders we require monochrome images:
2164
2165 =over
2166
2167 =item *
2168
2169 be paletted
2170
2171 =item *
2172
2173 have a palette of two colors, containing only (0,0,0) and
2174 (255,255,255) in either order.
2175
21592176 =back
21602177
2178 zero_is_white is set to non-zero iff the first palette entry is white.
2179
2180 =cut
2181 */
2182
2183 int
2184 i_img_is_monochrome(i_img *im, int *zero_is_white) {
2185 if (im->type == i_palette_type
2186 && i_colorcount(im) == 2) {
2187 i_color colors[2];
2188 i_getcolors(im, 0, colors, 2);
2189 if (im->channels == 3) {
2190 if (colors[0].rgb.r == 255 &&
2191 colors[0].rgb.g == 255 &&
2192 colors[0].rgb.b == 255 &&
2193 colors[1].rgb.r == 0 &&
2194 colors[1].rgb.g == 0 &&
2195 colors[1].rgb.b == 0) {
2196 *zero_is_white = 0;
2197 return 1;
2198 }
2199 else if (colors[0].rgb.r == 0 &&
2200 colors[0].rgb.g == 0 &&
2201 colors[0].rgb.b == 0 &&
2202 colors[1].rgb.r == 255 &&
2203 colors[1].rgb.g == 255 &&
2204 colors[1].rgb.b == 255) {
2205 *zero_is_white = 1;
2206 return 1;
2207 }
2208 }
2209 else if (im->channels == 1) {
2210 if (colors[0].channel[0] == 255 &&
2211 colors[1].channel[1] == 0) {
2212 *zero_is_white = 0;
2213 return 1;
2214 }
2215 else if (colors[0].channel[0] == 0 &&
2216 colors[0].channel[0] == 255) {
2217 *zero_is_white = 1;
2218 return 1;
2219 }
2220 }
2221 }
2222
2223 *zero_is_white = 0;
2224 return 0;
2225 }
2226
2227 /*
2228 =back
2229
21612230 =head1 AUTHOR
21622231
21632232 Arnar M. Hrafnkelsson <addi@umich.edu>
275275
276276 #ifdef WIN32
277277
278 extern int i_wf_bbox(const char *face, int size, const char *text, int length, int *bbox);
278 extern int i_wf_bbox(const char *face, int size, const char *text, int length, int *bbox, int utf8);
279279 extern int i_wf_text(const char *face, i_img *im, int tx, int ty, const i_color *cl,
280 int size, const char *text, int len, int align, int aa);
280 int size, const char *text, int len, int align, int aa, int utf8);
281281 extern int i_wf_cp(const char *face, i_img *im, int tx, int ty, int channel,
282 int size, const char *text, int len, int align, int aa);
282 int size, const char *text, int len, int align, int aa, int utf8);
283283 extern int i_wf_addfont(char const *file);
284284
285285 #endif
351351 extern i_img *i_img_double_new(int x, int y, int ch);
352352 extern i_img *i_img_double_new_low(i_img *im, int x, int y, int ch);
353353
354 extern int i_img_is_monochrome(i_img *im, int *zero_is_white);
354355
355356 const char * i_test_format_probe(io_glue *data, int length);
356357
362363 #endif /* HAVE_LIBJPEG */
363364
364365 #ifdef HAVE_LIBTIFF
365 i_img * i_readtiff_wiol(io_glue *ig, int length, int page);
366 i_img * i_readtiff_wiol(io_glue *ig, int allow_incomplete, int page);
366367 i_img ** i_readtiff_multi_wiol(io_glue *ig, int length, int *count);
367368 undef_int i_writetiff_wiol(i_img *im, io_glue *ig);
368369 undef_int i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count);
400401 i_img * i_readraw_wiol(io_glue *ig, int x, int y, int datachannels, int storechannels, int intrl);
401402 undef_int i_writeraw_wiol(i_img* im, io_glue *ig);
402403
403 i_img * i_readpnm_wiol(io_glue *ig, int length);
404 i_img * i_readpnm_wiol(io_glue *ig, int allow_incomplete);
404405 undef_int i_writeppm_wiol(i_img *im, io_glue *ig);
405406
406407 extern int i_writebmp_wiol(i_img *im, io_glue *ig);
407 extern i_img *i_readbmp_wiol(io_glue *ig);
408 extern i_img *i_readbmp_wiol(io_glue *ig, int allow_incomplete);
408409
409410 int tga_header_verify(unsigned char headbuf[18]);
410411
559560
560561 #endif /* IMAGER_MALLOC_DEBUG */
561562
562 #endif
563 #include "imrender.h"
564
565 #endif
386386 mc_web_map, /* Use the 216 colour web colour map */
387387 mc_addi, /* Addi's algorithm */
388388 mc_median_cut, /* median cut - similar to giflib, hopefully */
389 mc_mono, /* fixed mono color map */
389390 mc_mask = 0xFF /* (mask for generator) */
390391 } i_make_colors;
391392
517518
518519 #include "iolayert.h"
519520
521 #include "rendert.h"
522
520523 #endif
521524
228228 static int tiff_load_ifd(imtiff *tiff, unsigned long offset);
229229 static void tiff_final(imtiff *tiff);
230230 static void tiff_clear_ifd(imtiff *tiff);
231 #if 0 /* currently unused, but that may change */
231232 static int tiff_get_bytes(imtiff *tiff, unsigned char *to, size_t offset,
232233 size_t count);
234 #endif
233235 static int tiff_get_tag_double(imtiff *, int index, double *result);
234236 static int tiff_get_tag_int(imtiff *, int index, int *result);
235237 static unsigned tiff_get16(imtiff *, unsigned long offset);
14111413 + 0x10000 * tiff->base[offset+1] + 0x1000000 * tiff->base[offset];
14121414 }
14131415
1416 #if 0 /* currently unused, but that may change */
1417
14141418 /*
14151419 =item tiff_get_bytes
14161420
14321436
14331437 return 1;
14341438 }
1439
1440 #endif
14351441
14361442 /*
14371443 =item tiff_get16s
15511557
15521558 =head1 REVISION
15531559
1554 $Revision: 1016 $
1555
1556 =cut
1557 */
1560 $Revision: 1117 $
1561
1562 =cut
1563 */
0 #ifndef IMAGER_IMRENDER_H
1 #define IMAGER_IMRENDER_H
2
3 #include "rendert.h"
4
5 extern void
6 i_render_init(i_render *r, i_img *im, int width);
7 extern void
8 i_render_done(i_render *r);
9 extern void
10 i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
11 i_color const *color);
12
13 #endif
350350 This doesn't support the extended UTF8 encoding used by later versions
351351 of Perl.
352352
353 This doesn't check that the UTF8 charecter is using the shortest
354 possible representation.
355
353356 =cut
354357 */
355358
356 unsigned long i_utf8_advance(char const **p, int *len) {
359 unsigned long
360 i_utf8_advance(char const **p, int *len) {
357361 unsigned char c;
358362 int i, ci, clen = 0;
359363 unsigned char codes[3];
364368 for (i = 0; i < sizeof(utf8_sizes)/sizeof(*utf8_sizes); ++i) {
365369 if ((c & utf8_sizes[i].mask) == utf8_sizes[i].expect) {
366370 clen = utf8_sizes[i].size;
371 break;
367372 }
368373 }
369374 if (clen == 0 || *len < clen-1) {
4545 $img->read(file=>$filename, type=>$type)
4646 or die "Cannot read $filename: ", $img->errstr;
4747
48 In most cases Imager can auto-detect the file type, so you can just
49 supply the filename:
50
51 $img->read(file => $filename)
52 or die "Cannot read $filename: ", $img->errstr;
53
54 The read() method accepts the C<allow_partial> parameter. If this is
55 non-zero then read() can return true on an incomplete image and set
56 the C<i_incomplete> tag.
57
4858 =item write
4959
5060 and the C<write()> method to write an image:
6070 my @imgs = Imager->read_multi(file=>$filename, type=>$type)
6171 or die "Cannot read $filename: ", Imager->errstr;
6272
73 As with the read() method, Imager will normally detect the C<type>
74 automatically.
75
6376 =item write_multi
6477
6578 and if you want to write multiple images to a single file use the
7083
7184 =back
7285
73 If the I<filename> includes an extension that Imager recognizes, then
74 you don't need the I<type>, but you may want to provide one anyway.
75 See L</Guessing types> for information on controlling this
76 recognition.
86 When writing, if the I<filename> includes an extension that Imager
87 recognizes, then you don't need the I<type>, but you may want to
88 provide one anyway. See L</Guessing types> for information on
89 controlling this recognition.
7790
7891 The C<type> parameter is a lowercase representation of the file type,
7992 and can be any of the following:
101114
102115 =over
103116
104 =item file
105
106 The C<file> parameter is the name of the image file to be written to
107 or read from. If Imager recognizes the extension of the file you do
108 not need to supply a C<type>.
117 =item *
118
119 file - The C<file> parameter is the name of the image file to be
120 written to or read from. If Imager recognizes the extension of the
121 file you do not need to supply a C<type>.
109122
110123 # write in tiff format
111124 $image->write(file => "example.tif")
118131 $image->read(file => 'example.tif')
119132 or die $image->errstr;
120133
121 =item fh
122
123 C<fh> is a file handle, typically either returned from
134 =item
135
136 fh - C<fh> is a file handle, typically either returned from
124137 C<<IO::File->new()>>, or a glob from an C<open> call. You should call
125138 C<binmode> on the handle before passing it to Imager.
126139
135148 $image->read(fd => $cgi->param('file'))
136149 or die $image->errstr;
137150
138 =item fd
139
140 C<fd> is a file descriptor. You can get this by calling the
151 =item
152
153 fd - C<fd> is a file descriptor. You can get this by calling the
141154 C<fileno()> function on a file handle, or by using one of the standard
142155 file descriptor numbers.
143156
148161 $image->write(fd => file(STDOUT), type => 'gif')
149162 or die $image->errstr;
150163
151 =item data
152
153 When reading data, C<data> is a scalar containing the image file data,
154 when writing, C<data> is a reference to the scalar to save the image
155 file data too. For GIF images you will need giflib 4 or higher, and
156 you may need to patch giflib to use this option for writing.
164 =item
165
166 data - When reading data, C<data> is a scalar containing the image
167 file data, when writing, C<data> is a reference to the scalar to save
168 the image file data too. For GIF images you will need giflib 4 or
169 higher, and you may need to patch giflib to use this option for
170 writing.
157171
158172 my $data;
159173 $image->write(data => \$data, type => 'tiff')
163177 my @images = Imager->read_multi(data => $data)
164178 or die Imager->errstr;
165179
166 =item callback
167
168 Imager will make calls back to your supplied coderefs to read, write
169 and seek from/to/through the image file.
180 =item *
181
182 callback - Imager will make calls back to your supplied coderefs to
183 read, write and seek from/to/through the image file.
170184
171185 When reading from a file you can use either C<callback> or C<readcb>
172186 to supply the read callback, and when writing C<callback> or
351365
352366 PNM does not support the spatial resolution tags.
353367
368 The following tags are set when reading a PNM file:
369
370 =over
371
372 =item *
373
374 X<pnm_maxval>pnm_maxval - the maxvals number from the PGM/PPM header.
375 Always set to 2 for a PBM file.
376
377 =item *
378
379 X<pnm_type>pnm_type - the type number from the PNM header, 1 for ASCII
380 PBM files, 2 for ASCII PGM files, 3 for ASCII PPM files, 4 for binary
381 PBM files, 5 for binary PGM files, 6 for binary PPM files.
382
383 =back
384
385 The following tag is checked when writing an image with more than
386 8-bits/sample:
387
388 =over
389
390 =item *
391
392 X<pnm_write_wide_data>pnm_write_wide_data - if this is non-zero then
393 write() can write PGM/PPM files with 16-bits/sample. Some
394 applications, for example GIMP 2.2, and tools can only read
395 8-bit/sample binary PNM files, so Imager will only write a 16-bit
396 image when this tag is non-zero.
397
398 =back
399
354400 =head2 JPEG
355401
356402 You can supply a C<jpegquality> parameter (0-100) when writing a JPEG
372418 =item jpeg_density_unit
373419
374420 The value of the density unit field in the JFIF header. This is
375 ignored on writing if the i_aspect_only tag is non-zero.
421 ignored on writing if the C<i_aspect_only> tag is non-zero.
376422
377423 The C<i_xres> and C<i_yres> tags are expressed in pixels per inch no
378424 matter the value of this tag, they will be converted to/from the value
563609
564610 =item gif_loop
565611
566 the number of loops from the Netscape Loop extension. This may be zero.
612 the number of loops from the Netscape Loop extension. This may be
613 zero to loop forever.
567614
568615 =item gif_comment
569616
739786 names in the TIFF specification. These are set in images read from a
740787 TIFF and saved when writing a TIFF image.
741788
789 =back
790
742791 You can supply a C<page> parameter to the C<read()> method to read
743792 some page other than the first. The page is 0 based:
744793
745794 # read the second image in the file
746795 $image->read(file=>"example.tif", page=>1)
747796 or die "Cannot read second page: ",$image->errstr,"\n";
748
749 =back
750797
751798 Note: Imager uses the TIFF*RGBA* family of libtiff functions,
752799 unfortunately these don't support alpha channels on CMYK images. This
135135 truncate the range by the specified fraction at the top and bottom of
136136 the range respectivly.
137137
138 # increase contrast, losing little detail
138 # increase contrast per channel, losing little detail
139139 $img->filter(type=>"autolevels")
140140 or die $img->errstr;
141141
477477
478478 =item unsharpmask
479479
480 performs an unsharp mask on the image. This is the result of
481 subtracting a gaussian blurred version of the image from the original.
482 I<stddev> controls the stddev parameter of the gaussian blur. Each
483 output pixel is: in + I<scale> * (in - blurred).
480 performs an unsharp mask on the image. This increases the contrast of
481 edges in the image.
482
483 This is the result of subtracting a gaussian blurred version of the
484 image from the original. I<stddev> controls the stddev parameter of
485 the gaussian blur. Each output pixel is: in + I<scale> * (in -
486 blurred).
484487
485488 $img->filter(type=>"unsharpmask", stddev=>1, scale=>0.5)
486489 or die $img->errstr;
490
491 unsharpmark has the following parameters:
492
493 =over
494
495 =item *
496
497 stddev - this is equivalent to the C<Radius> value in the GIMP's
498 unsharpmask filter. This controls the size of the contrast increase
499 around edges, larger values will remove fine detail. You should
500 probably experiement on the types of images you plan to work with.
501 Default: 2.0.
502
503 =item *
504
505 scale - controls the strength of the edge enhancement, equivalent to
506 I<Amount> in the GIMP's unsharp mask filter. Default: 1.0.
507
508 =back
487509
488510 =item watermark
489511
645667
646668 =head1 REVISION
647669
648 $Revision: 978 $
670 $Revision: 1192 $
649671
650672 =cut
22 use vars qw(@ISA $VERSION);
33 @ISA = qw(Imager::Font);
44
5 $VERSION = "1.004";
5 $VERSION = "1.005";
66
77 # called by Imager::Font::new()
88 # since Win32's HFONTs include the size information this
1616 sub _bounding_box {
1717 my ($self, %opts) = @_;
1818
19 my @bbox = Imager::i_wf_bbox($self->{face}, $opts{size}, $opts{string});
19 my @bbox = Imager::i_wf_bbox($self->{face}, $opts{size}, $opts{string}, $opts{utf8});
2020 }
2121
2222 sub _draw {
2626 if (exists $input{channel}) {
2727 Imager::i_wf_cp($self->{face}, $input{image}{IMG}, $input{x}, $input{'y'},
2828 $input{channel}, $input{size},
29 $input{string}, $input{align}, $input{aa});
29 $input{string}, $input{align}, $input{aa}, $input{utf8});
3030 }
3131 else {
3232 Imager::i_wf_text($self->{face}, $input{image}{IMG}, $input{x},
3333 $input{'y'}, $input{color}, $input{size},
34 $input{string}, $input{align}, $input{aa});
34 $input{string}, $input{align}, $input{aa}, $input{utf8});
3535 }
3636 }
3737
38
39 sub utf8 {
40 return 1;
41 }
3842
3943 1;
4044
678678
679679 =over
680680
681 =item i_xres
682
683 =item i_yres
684
685 The spatial resolution of the image in pixels per inch. If the image
686 format uses a different scale, eg. pixels per meter, then this value
687 is converted. A floating point number stored as a string.
681 =item *
682
683 X<i_xres tag>X<i_yres tag>X<tags, i_xres>X<tags, i_yres>i_xres, i_yres
684 - The spatial resolution of the image in pixels per inch. If the
685 image format uses a different scale, eg. pixels per meter, then this
686 value is converted. A floating point number stored as a string.
688687
689688 # our image was generated as a 300 dpi image
690689 $img->settag(name => 'i_xres', value => 300);
696695 $img->settag(name => 'i_xres', value => 100 * 2.54);
697696 $img->settag(name => 'i_yres', value => 100 * 2.54);
698697
699 =item i_aspect_only
700
701 If this is non-zero then the values in i_xres and i_yres are treated
702 as a ratio only. If the image format does not support aspect ratios
703 then this is scaled so the smaller value is 72dpi.
704
705 =item i_incomplete
706
707 If this tag is present then the whole image could not be read. This
708 isn't implemented for all images yet, and may not be.
709
710 =item i_format
711
712 The file format this file was read from.
698 =item *
699
700 X<i_aspect_only tag>X<tags, i_aspect_only>i_aspect_only - If this is
701 non-zero then the values in i_xres and i_yres are treated as a ratio
702 only. If the image format does not support aspect ratios then this is
703 scaled so the smaller value is 72dpi.
704
705 =item *
706
707 X<i_incomplete tag>X<tags, i_incomplete>i_incomplete - If this tag is
708 present then the whole image could not be read. This isn't
709 implemented for all images yet, and may not be.
710
711 =item *
712
713 X<i_lines_read tag>X<tags, i_lines_read>i_lines_read - If
714 C<i_incomplete> is set then this tag may be set to the number of
715 scanlines successfully read from the file. This can be used to decide
716 whether an image is worth processing.
717
718 =item *
719
720 X<i_format tag>X<tags, i_format>i_format - The file format this file
721 was read from.
713722
714723 =back
715724
716725 =head2 Quantization options
717726
718 These options can be specified when calling write_multi() for gif
719 files, when writing a single image with the gifquant option set to
720 'gen', or for direct calls to i_writegif_gen and i_writegif_callback.
727 These options can be specified when calling
728 L<Imager::ImageTypes/to_paletted>, write_multi() for gif files, when
729 writing a single image with the gifquant option set to 'gen', or for
730 direct calls to i_writegif_gen and i_writegif_callback.
721731
722732 =over
723733
835845
836846 =over
837847
838 =item none
839
840 Only colors supplied in 'colors' are used.
841
842 =item webmap
843
844 The web color map is used (need url here.)
845
846 =item addi
847
848 The original code for generating the color map (Addi's code) is used.
849
850 =item mediancut
851
852 Uses a mediancut algorithm, faster than 'addi', but not as good a
848 =item *
849
850 none - only colors supplied in 'colors' are used.
851
852 =item *
853
854 webmap - the web color map is used (need url here.)
855
856 =item *
857
858 addi - The original code for generating the color map (Addi's code) is
859 used.
860
861 =item *
862
863 mediancut - Uses a mediancut algorithm, faster than 'addi', but not as good a
853864 result.
865
866 =item *
867
868 mono, monochrome - a fixed black and white palette, suitable for
869 producing bi-level images (eg. facsimile)
854870
855871 =back
856872
9911007
9921008 =head1 REVISION
9931009
994 $Revision: 1082 $
1010 $Revision: 1137 $
9951011
9961012 =head1 AUTHORS
9971013
6060
6161 @EXPORT = qw(RBC_ADD RBC_SUBTRACT RBC_MULT RBC_DIV RBC_MOD RBC_POW RBC_UMINUS RBC_MULTP RBC_ADDP RBC_SUBTRACTP RBC_SIN RBC_COS RBC_ATAN2 RBC_SQRT RBC_DISTANCE RBC_GETP1 RBC_GETP2 RBC_GETP3 RBC_VALUE RBC_HUE RBC_SAT RBC_HSV RBC_RED RBC_GREEN RBC_BLUE RBC_RGB RBC_INT RBC_IF RBC_IFP RBC_LE RBC_LT RBC_GE RBC_GT RBC_EQ RBC_NE RBC_AND RBC_OR RBC_NOT RBC_ABS RBC_RET RBC_JUMP RBC_JUMPZ RBC_JUMPNZ RBC_SET RBC_SETP RBC_PRINT RBC_RGBA RBC_HSVA RBC_ALPHA RBC_LOG RBC_EXP RBC_OP_COUNT);
6262
63 %Attr = (
64 'abs' => {
65 'func' => 1,
66 'opcode' => 38,
67 'parms' => 1,
68 'result' => 'r',
69 'types' => 'r'
70 },
71 'add' => {
72 'func' => 0,
73 'opcode' => 0,
74 'parms' => 2,
75 'result' => 'r',
76 'types' => 'rr'
77 },
78 'addp' => {
79 'func' => 0,
80 'opcode' => 8,
81 'parms' => 2,
82 'result' => 'p',
83 'types' => 'pp'
84 },
85 'alpha' => {
86 'func' => 1,
87 'opcode' => 48,
88 'parms' => 1,
89 'result' => 'r',
90 'types' => 'p'
91 },
92 'and' => {
93 'func' => 0,
94 'opcode' => 35,
95 'parms' => 2,
96 'result' => 'r',
97 'types' => 'rr'
98 },
99 'atan2' => {
100 'func' => 1,
101 'opcode' => 12,
102 'parms' => 2,
103 'result' => 'r',
104 'types' => 'rr'
105 },
106 'blue' => {
107 'func' => 1,
108 'opcode' => 24,
109 'parms' => 1,
110 'result' => 'r',
111 'types' => 'p'
112 },
113 'cos' => {
114 'func' => 1,
115 'opcode' => 11,
116 'parms' => 1,
117 'result' => 'r',
118 'types' => 'r'
119 },
120 'distance' => {
121 'func' => 1,
122 'opcode' => 14,
123 'parms' => 4,
124 'result' => 'r',
125 'types' => 'rrrr'
126 },
127 'div' => {
128 'func' => 0,
129 'opcode' => 3,
130 'parms' => 2,
131 'result' => 'r',
132 'types' => 'rr'
133 },
134 'eq' => {
135 'func' => 0,
136 'opcode' => 33,
137 'parms' => 2,
138 'result' => 'r',
139 'types' => 'rr'
140 },
141 'exp' => {
142 'func' => 1,
143 'opcode' => 50,
144 'parms' => 1,
145 'result' => 'r',
146 'types' => 'r'
147 },
148 'ge' => {
149 'func' => 0,
150 'opcode' => 31,
151 'parms' => 2,
152 'result' => 'r',
153 'types' => 'rr'
154 },
155 'getp1' => {
156 'func' => 1,
157 'opcode' => 15,
158 'parms' => 2,
159 'result' => 'p',
160 'types' => 'rr'
161 },
162 'getp2' => {
163 'func' => 1,
164 'opcode' => 16,
165 'parms' => 2,
166 'result' => 'p',
167 'types' => 'rr'
168 },
169 'getp3' => {
170 'func' => 1,
171 'opcode' => 17,
172 'parms' => 2,
173 'result' => 'p',
174 'types' => 'rr'
175 },
176 'green' => {
177 'func' => 1,
178 'opcode' => 23,
179 'parms' => 1,
180 'result' => 'r',
181 'types' => 'p'
182 },
183 'gt' => {
184 'func' => 0,
185 'opcode' => 32,
186 'parms' => 2,
187 'result' => 'r',
188 'types' => 'rr'
189 },
190 'hsv' => {
191 'func' => 1,
192 'opcode' => 21,
193 'parms' => 3,
194 'result' => 'p',
195 'types' => 'rrr'
196 },
197 'hsva' => {
198 'func' => 1,
199 'opcode' => 47,
200 'parms' => 4,
201 'result' => 'p',
202 'types' => 'rrrr'
203 },
204 'hue' => {
205 'func' => 1,
206 'opcode' => 19,
207 'parms' => 1,
208 'result' => 'r',
209 'types' => 'p'
210 },
211 'if' => {
212 'func' => 1,
213 'opcode' => 27,
214 'parms' => 3,
215 'result' => 'r',
216 'types' => 'rrr'
217 },
218 'ifp' => {
219 'func' => 1,
220 'opcode' => 28,
221 'parms' => 3,
222 'result' => 'p',
223 'types' => 'rpp'
224 },
225 'int' => {
226 'func' => 1,
227 'opcode' => 26,
228 'parms' => 1,
229 'result' => 'r',
230 'types' => 'r'
231 },
232 'jump' => {
233 'func' => 0,
234 'opcode' => 40,
235 'parms' => 0,
236 'result' => undef,
237 'types' => ''
238 },
239 'jumpnz' => {
240 'func' => 0,
241 'opcode' => 42,
242 'parms' => 1,
243 'result' => undef,
244 'types' => 'r'
245 },
246 'jumpz' => {
247 'func' => 0,
248 'opcode' => 41,
249 'parms' => 1,
250 'result' => undef,
251 'types' => 'r'
252 },
253 'le' => {
254 'func' => 0,
255 'opcode' => 29,
256 'parms' => 2,
257 'result' => 'r',
258 'types' => 'rr'
259 },
260 'log' => {
261 'func' => 1,
262 'opcode' => 49,
263 'parms' => 1,
264 'result' => 'r',
265 'types' => 'r'
266 },
267 'lt' => {
268 'func' => 0,
269 'opcode' => 30,
270 'parms' => 2,
271 'result' => 'r',
272 'types' => 'rr'
273 },
274 'mod' => {
275 'func' => 0,
276 'opcode' => 4,
277 'parms' => 2,
278 'result' => 'r',
279 'types' => 'rr'
280 },
281 'mult' => {
282 'func' => 0,
283 'opcode' => 2,
284 'parms' => 2,
285 'result' => 'r',
286 'types' => 'rr'
287 },
288 'multp' => {
289 'func' => 0,
290 'opcode' => 7,
291 'parms' => 2,
292 'result' => 'p',
293 'types' => 'pr'
294 },
295 'ne' => {
296 'func' => 0,
297 'opcode' => 34,
298 'parms' => 2,
299 'result' => 'r',
300 'types' => 'rr'
301 },
302 'not' => {
303 'func' => 0,
304 'opcode' => 37,
305 'parms' => 1,
306 'result' => 'r',
307 'types' => 'r'
308 },
309 'op_count' => {
310 'func' => 0,
311 'opcode' => 51,
312 'parms' => 0,
313 'result' => undef,
314 'types' => ''
315 },
316 'or' => {
317 'func' => 0,
318 'opcode' => 36,
319 'parms' => 2,
320 'result' => 'r',
321 'types' => 'rr'
322 },
323 'pow' => {
324 'func' => 0,
325 'opcode' => 5,
326 'parms' => 2,
327 'result' => 'r',
328 'types' => 'rr'
329 },
330 'print' => {
331 'func' => 0,
332 'opcode' => 45,
333 'parms' => 1,
334 'result' => undef,
335 'types' => 'r'
336 },
337 'red' => {
338 'func' => 1,
339 'opcode' => 22,
340 'parms' => 1,
341 'result' => 'r',
342 'types' => 'p'
343 },
344 'ret' => {
345 'func' => 0,
346 'opcode' => 39,
347 'parms' => 1,
348 'result' => undef,
349 'types' => 'p'
350 },
351 'rgb' => {
352 'func' => 1,
353 'opcode' => 25,
354 'parms' => 3,
355 'result' => 'p',
356 'types' => 'rrr'
357 },
358 'rgba' => {
359 'func' => 1,
360 'opcode' => 46,
361 'parms' => 4,
362 'result' => 'p',
363 'types' => 'rrrr'
364 },
365 'sat' => {
366 'func' => 1,
367 'opcode' => 20,
368 'parms' => 1,
369 'result' => 'r',
370 'types' => 'p'
371 },
372 'set' => {
373 'func' => 0,
374 'opcode' => 43,
375 'parms' => 1,
376 'result' => 'r',
377 'types' => 'r'
378 },
379 'setp' => {
380 'func' => 0,
381 'opcode' => 44,
382 'parms' => 1,
383 'result' => 'p',
384 'types' => 'p'
385 },
386 'sin' => {
387 'func' => 1,
388 'opcode' => 10,
389 'parms' => 1,
390 'result' => 'r',
391 'types' => 'r'
392 },
393 'sqrt' => {
394 'func' => 1,
395 'opcode' => 13,
396 'parms' => 1,
397 'result' => 'r',
398 'types' => 'r'
399 },
400 'subtract' => {
401 'func' => 0,
402 'opcode' => 1,
403 'parms' => 2,
404 'result' => 'r',
405 'types' => 'rr'
406 },
407 'subtractp' => {
408 'func' => 0,
409 'opcode' => 9,
410 'parms' => 2,
411 'result' => 'p',
412 'types' => 'pp'
413 },
414 'uminus' => {
415 'func' => 0,
416 'opcode' => 6,
417 'parms' => 1,
418 'result' => 'r',
419 'types' => 'r'
420 },
421 'value' => {
422 'func' => 1,
423 'opcode' => 18,
424 'parms' => 1,
425 'result' => 'r',
426 'types' => 'p'
427 }
428 );
63 %Attr =
64 (
65 'abs' =>
66 {
67 'func' => 1,
68 'opcode' => 38,
69 'parms' => 1,
70 'result' => 'r',
71 'types' => 'r',
72 },
73 'add' =>
74 {
75 'func' => 0,
76 'opcode' => 0,
77 'parms' => 2,
78 'result' => 'r',
79 'types' => 'rr',
80 },
81 'addp' =>
82 {
83 'func' => 0,
84 'opcode' => 8,
85 'parms' => 2,
86 'result' => 'p',
87 'types' => 'pp',
88 },
89 'alpha' =>
90 {
91 'func' => 1,
92 'opcode' => 48,
93 'parms' => 1,
94 'result' => 'r',
95 'types' => 'p',
96 },
97 'and' =>
98 {
99 'func' => 0,
100 'opcode' => 35,
101 'parms' => 2,
102 'result' => 'r',
103 'types' => 'rr',
104 },
105 'atan2' =>
106 {
107 'func' => 1,
108 'opcode' => 12,
109 'parms' => 2,
110 'result' => 'r',
111 'types' => 'rr',
112 },
113 'blue' =>
114 {
115 'func' => 1,
116 'opcode' => 24,
117 'parms' => 1,
118 'result' => 'r',
119 'types' => 'p',
120 },
121 'cos' =>
122 {
123 'func' => 1,
124 'opcode' => 11,
125 'parms' => 1,
126 'result' => 'r',
127 'types' => 'r',
128 },
129 'distance' =>
130 {
131 'func' => 1,
132 'opcode' => 14,
133 'parms' => 4,
134 'result' => 'r',
135 'types' => 'rrrr',
136 },
137 'div' =>
138 {
139 'func' => 0,
140 'opcode' => 3,
141 'parms' => 2,
142 'result' => 'r',
143 'types' => 'rr',
144 },
145 'eq' =>
146 {
147 'func' => 0,
148 'opcode' => 33,
149 'parms' => 2,
150 'result' => 'r',
151 'types' => 'rr',
152 },
153 'exp' =>
154 {
155 'func' => 1,
156 'opcode' => 50,
157 'parms' => 1,
158 'result' => 'r',
159 'types' => 'r',
160 },
161 'ge' =>
162 {
163 'func' => 0,
164 'opcode' => 31,
165 'parms' => 2,
166 'result' => 'r',
167 'types' => 'rr',
168 },
169 'getp1' =>
170 {
171 'func' => 1,
172 'opcode' => 15,
173 'parms' => 2,
174 'result' => 'p',
175 'types' => 'rr',
176 },
177 'getp2' =>
178 {
179 'func' => 1,
180 'opcode' => 16,
181 'parms' => 2,
182 'result' => 'p',
183 'types' => 'rr',
184 },
185 'getp3' =>
186 {
187 'func' => 1,
188 'opcode' => 17,
189 'parms' => 2,
190 'result' => 'p',
191 'types' => 'rr',
192 },
193 'green' =>
194 {
195 'func' => 1,
196 'opcode' => 23,
197 'parms' => 1,
198 'result' => 'r',
199 'types' => 'p',
200 },
201 'gt' =>
202 {
203 'func' => 0,
204 'opcode' => 32,
205 'parms' => 2,
206 'result' => 'r',
207 'types' => 'rr',
208 },
209 'hsv' =>
210 {
211 'func' => 1,
212 'opcode' => 21,
213 'parms' => 3,
214 'result' => 'p',
215 'types' => 'rrr',
216 },
217 'hsva' =>
218 {
219 'func' => 1,
220 'opcode' => 47,
221 'parms' => 4,
222 'result' => 'p',
223 'types' => 'rrrr',
224 },
225 'hue' =>
226 {
227 'func' => 1,
228 'opcode' => 19,
229 'parms' => 1,
230 'result' => 'r',
231 'types' => 'p',
232 },
233 'if' =>
234 {
235 'func' => 1,
236 'opcode' => 27,
237 'parms' => 3,
238 'result' => 'r',
239 'types' => 'rrr',
240 },
241 'ifp' =>
242 {
243 'func' => 1,
244 'opcode' => 28,
245 'parms' => 3,
246 'result' => 'p',
247 'types' => 'rpp',
248 },
249 'int' =>
250 {
251 'func' => 1,
252 'opcode' => 26,
253 'parms' => 1,
254 'result' => 'r',
255 'types' => 'r',
256 },
257 'jump' =>
258 {
259 'func' => 0,
260 'opcode' => 40,
261 'parms' => 0,
262 'result' => undef,
263 'types' => '',
264 },
265 'jumpnz' =>
266 {
267 'func' => 0,
268 'opcode' => 42,
269 'parms' => 1,
270 'result' => undef,
271 'types' => 'r',
272 },
273 'jumpz' =>
274 {
275 'func' => 0,
276 'opcode' => 41,
277 'parms' => 1,
278 'result' => undef,
279 'types' => 'r',
280 },
281 'le' =>
282 {
283 'func' => 0,
284 'opcode' => 29,
285 'parms' => 2,
286 'result' => 'r',
287 'types' => 'rr',
288 },
289 'log' =>
290 {
291 'func' => 1,
292 'opcode' => 49,
293 'parms' => 1,
294 'result' => 'r',
295 'types' => 'r',
296 },
297 'lt' =>
298 {
299 'func' => 0,
300 'opcode' => 30,
301 'parms' => 2,
302 'result' => 'r',
303 'types' => 'rr',
304 },
305 'mod' =>
306 {
307 'func' => 0,
308 'opcode' => 4,
309 'parms' => 2,
310 'result' => 'r',
311 'types' => 'rr',
312 },
313 'mult' =>
314 {
315 'func' => 0,
316 'opcode' => 2,
317 'parms' => 2,
318 'result' => 'r',
319 'types' => 'rr',
320 },
321 'multp' =>
322 {
323 'func' => 0,
324 'opcode' => 7,
325 'parms' => 2,
326 'result' => 'p',
327 'types' => 'pr',
328 },
329 'ne' =>
330 {
331 'func' => 0,
332 'opcode' => 34,
333 'parms' => 2,
334 'result' => 'r',
335 'types' => 'rr',
336 },
337 'not' =>
338 {
339 'func' => 0,
340 'opcode' => 37,
341 'parms' => 1,
342 'result' => 'r',
343 'types' => 'r',
344 },
345 'op_count' =>
346 {
347 'func' => 0,
348 'opcode' => 51,
349 'parms' => 0,
350 'result' => undef,
351 'types' => '',
352 },
353 'or' =>
354 {
355 'func' => 0,
356 'opcode' => 36,
357 'parms' => 2,
358 'result' => 'r',
359 'types' => 'rr',
360 },
361 'pow' =>
362 {
363 'func' => 0,
364 'opcode' => 5,
365 'parms' => 2,
366 'result' => 'r',
367 'types' => 'rr',
368 },
369 'print' =>
370 {
371 'func' => 0,
372 'opcode' => 45,
373 'parms' => 1,
374 'result' => undef,
375 'types' => 'r',
376 },
377 'red' =>
378 {
379 'func' => 1,
380 'opcode' => 22,
381 'parms' => 1,
382 'result' => 'r',
383 'types' => 'p',
384 },
385 'ret' =>
386 {
387 'func' => 0,
388 'opcode' => 39,
389 'parms' => 1,
390 'result' => undef,
391 'types' => 'p',
392 },
393 'rgb' =>
394 {
395 'func' => 1,
396 'opcode' => 25,
397 'parms' => 3,
398 'result' => 'p',
399 'types' => 'rrr',
400 },
401 'rgba' =>
402 {
403 'func' => 1,
404 'opcode' => 46,
405 'parms' => 4,
406 'result' => 'p',
407 'types' => 'rrrr',
408 },
409 'sat' =>
410 {
411 'func' => 1,
412 'opcode' => 20,
413 'parms' => 1,
414 'result' => 'r',
415 'types' => 'p',
416 },
417 'set' =>
418 {
419 'func' => 0,
420 'opcode' => 43,
421 'parms' => 1,
422 'result' => 'r',
423 'types' => 'r',
424 },
425 'setp' =>
426 {
427 'func' => 0,
428 'opcode' => 44,
429 'parms' => 1,
430 'result' => 'p',
431 'types' => 'p',
432 },
433 'sin' =>
434 {
435 'func' => 1,
436 'opcode' => 10,
437 'parms' => 1,
438 'result' => 'r',
439 'types' => 'r',
440 },
441 'sqrt' =>
442 {
443 'func' => 1,
444 'opcode' => 13,
445 'parms' => 1,
446 'result' => 'r',
447 'types' => 'r',
448 },
449 'subtract' =>
450 {
451 'func' => 0,
452 'opcode' => 1,
453 'parms' => 2,
454 'result' => 'r',
455 'types' => 'rr',
456 },
457 'subtractp' =>
458 {
459 'func' => 0,
460 'opcode' => 9,
461 'parms' => 2,
462 'result' => 'p',
463 'types' => 'pp',
464 },
465 'uminus' =>
466 {
467 'func' => 0,
468 'opcode' => 6,
469 'parms' => 1,
470 'result' => 'r',
471 'types' => 'r',
472 },
473 'value' =>
474 {
475 'func' => 1,
476 'opcode' => 18,
477 'parms' => 1,
478 'result' => 'r',
479 'types' => 'p',
480 },
481 );
429482 $MaxOperands = 4;
430483 $PackCode = "i";
431484 1;
0 package Imager::Test;
1 use strict;
2 use Test::Builder;
3 require Exporter;
4 use vars qw(@ISA @EXPORT_OK);
5 @ISA = qw(Exporter);
6 @EXPORT_OK = qw(diff_text_with_nul test_image_raw test_image_16 is_color3 is_color1 is_image);
7
8 sub diff_text_with_nul {
9 my ($desc, $text1, $text2, @params) = @_;
10
11 my $builder = Test::Builder->new;
12
13 print "# $desc\n";
14 my $imbase = Imager->new(xsize => 100, ysize => 100);
15 my $imcopy = Imager->new(xsize => 100, ysize => 100);
16
17 $builder->ok($imbase->string(x => 5, 'y' => 50, size => 20,
18 string => $text1,
19 @params), "$desc - draw text1");
20 $builder->ok($imcopy->string(x => 5, 'y' => 50, size => 20,
21 string => $text2,
22 @params), "$desc - draw text2");
23 $builder->isnt_num(Imager::i_img_diff($imbase->{IMG}, $imcopy->{IMG}), 0,
24 "$desc - check result different");
25 }
26
27 sub is_color3($$$$$) {
28 my ($color, $red, $green, $blue, $comment) = @_;
29
30 my $builder = Test::Builder->new;
31
32 unless (defined $color) {
33 $builder->ok(0, $comment);
34 $builder->diag("color is undef");
35 return;
36 }
37 unless ($color->can('rgba')) {
38 $builder->ok(0, $comment);
39 $builder->diag("color is not a color object");
40 return;
41 }
42
43 my ($cr, $cg, $cb) = $color->rgba;
44 unless ($builder->ok($cr == $red && $cg == $green && $cb == $blue, $comment)) {
45 $builder->diag(<<END_DIAG);
46 Color mismatch:
47 Red: $red vs $cr
48 Green: $green vs $cg
49 Blue: $blue vs $cb
50 END_DIAG
51 return;
52 }
53
54 return 1;
55 }
56
57 sub is_color1($$$) {
58 my ($color, $grey, $comment) = @_;
59
60 my $builder = Test::Builder->new;
61
62 unless (defined $color) {
63 $builder->ok(0, $comment);
64 $builder->diag("color is undef");
65 return;
66 }
67 unless ($color->can('rgba')) {
68 $builder->ok(0, $comment);
69 $builder->diag("color is not a color object");
70 return;
71 }
72
73 my ($cgrey) = $color->rgba;
74 unless ($builder->ok($cgrey == $grey, $comment)) {
75 $builder->diag(<<END_DIAG);
76 Color mismatch:
77 Grey: $grey vs $cgrey
78 END_DIAG
79 return;
80 }
81
82 return 1;
83 }
84
85 sub test_image_raw {
86 my $green=Imager::i_color_new(0,255,0,255);
87 my $blue=Imager::i_color_new(0,0,255,255);
88 my $red=Imager::i_color_new(255,0,0,255);
89
90 my $img=Imager::ImgRaw::new(150,150,3);
91
92 Imager::i_box_filled($img,70,25,130,125,$green);
93 Imager::i_box_filled($img,20,25,80,125,$blue);
94 Imager::i_arc($img,75,75,30,0,361,$red);
95 Imager::i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]);
96
97 $img;
98 }
99
100 sub test_image_16 {
101 my $green = Imager::Color->new(0, 255, 0, 255);
102 my $blue = Imager::Color->new(0, 0, 255, 255);
103 my $red = Imager::Color->new(255, 0, 0, 255);
104 my $img = Imager->new(xsize => 150, ysize => 150, bits => 16);
105 $img->box(filled => 1, color => $green, box => [ 70, 25, 130, 125 ]);
106 $img->box(filled => 1, color => $blue, box => [ 20, 25, 80, 125 ]);
107 $img->arc(x => 75, y => 75, r => 30, color => $red);
108 $img->filter(type => 'conv', coef => [ 0.1, 0.2, 0.4, 0.2, 0.1 ]);
109
110 $img;
111 }
112
113 sub is_image($$$) {
114 my ($left, $right, $comment) = @_;
115
116 my $builder = Test::Builder->new;
117
118 unless (defined $left) {
119 $builder->ok(0, $comment);
120 $builder->diag("left is undef");
121 return;
122 }
123 unless (defined $right) {
124 $builder->ok(0, $comment);
125 $builder->diag("right is undef");
126 return;
127 }
128 unless ($left->{IMG}) {
129 $builder->ok(0, $comment);
130 $builder->diag("left image has no low level object");
131 return;
132 }
133 unless ($right->{IMG}) {
134 $builder->ok(0, $comment);
135 $builder->diag("right image has no low level object");
136 return;
137 }
138 unless ($left->getwidth == $right->getwidth) {
139 $builder->ok(0, $comment);
140 $builder->diag("left width " . $left->getwidth . " vs right width "
141 . $right->getwidth);
142 return;
143 }
144 unless ($left->getheight == $right->getheight) {
145 $builder->ok(0, $comment);
146 $builder->diag("left height " . $left->getheight . " vs right height "
147 . $right->getheight);
148 return;
149 }
150 unless ($left->getchannels == $right->getchannels) {
151 $builder->ok(0, $comment);
152 $builder->diag("left channels " . $left->getchannels . " vs right channels "
153 . $right->getchannels);
154 return;
155 }
156 my $diff = Imager::i_img_diff($left->{IMG}, $right->{IMG});
157 unless ($diff == 0) {
158 $builder->ok(0, $comment);
159 $builder->diag("image data different - $diff");
160 return;
161 }
162
163 return $builder->ok(1, $comment);
164 }
165
166 1;
167
168 __END__
169
170 =head1 NAME
171
172 Imager::Test - common functions used in testing Imager
173
174 =head1 SYNOPSIS
175
176 use Imager::Test 'diff_text_with_nul';
177 diff_text_with_nul($test_name, $text1, $text2, @string_options);
178
179 =head1 DESCRIPTION
180
181 This is a repository of functions used in testing Imager.
182
183 Some functions will only be useful in testing Imager itself, while
184 others should be useful in testing modules that use Imager.
185
186 No functions are exported by default.
187
188 =head1 FUNCTIONS
189
190 =over
191
192 =item is_color3($color, $red, $blue, $green, $comment)
193
194 Tests is $color matches the given ($red, $blue, $green)
195
196 =item is_image($im1, $im2, $comment)
197
198 Tests if the 2 images have the same content. Both images must be
199 defined, have the same width, height, channels and the same color in
200 each pixel. The color comparison is done at 8-bits per pixel. The
201 color representation such as direct vs paletted, bits per sample are
202 not checked.
203
204 =item test_image_raw()
205
206 Returns a 150x150x3 Imager::ImgRaw test image.
207
208 =item test_image_16()
209
210 Returns a 150x150x3 16-bit/sample OO test image.
211
212 =item diff_text_with_nul($test_name, $text1, $text2, @options)
213
214 Creates 2 test images and writes $text1 to the first image and $text2
215 to the second image with the string() method. Each call adds 3 ok/not
216 ok to the output of the test script.
217
218 Extra options that should be supplied include the font and either a
219 color or channel parameter.
220
221 This was explicitly created for regression tests on #21770.
222
223 =back
224
225 =head1 AUTHOR
226
227 Tony Cook <tony@develop-help.com>
228
229 =cut
3838 i_color *vals;
3939 int x, y;
4040 int i, ch;
41 int minset = -1, maxset;
41 int minset = -1, maxset = 0;
4242
4343 mm_log((1,"i_map(im %p, maps %p, chmask %u)\n", im, maps, mask));
4444
+499
-130
pnm.c less more
1414 =head1 SYNOPSIS
1515
1616 io_glue *ig = io_new_fd( fd );
17 i_img *im = i_readpnm_wiol(ig, -1); // no limit on how much is read
17 i_img *im = i_readpnm_wiol(ig, 0); // no limit on how much is read
1818 // or
1919 io_glue *ig = io_new_fd( fd );
2020 return_code = i_writepnm_wiol(im, ig);
7474 =cut
7575 */
7676
77 #define gnext(mb) (((mb)->cp == (mb)->len) ? gnextf(mb) : (mb)->buf + (mb)->cp++)
78
7779 static
7880 char *
79 gnext(mbuf *mb) {
81 gnextf(mbuf *mb) {
8082 io_glue *ig = mb->ig;
8183 if (mb->cp == mb->len) {
8284 mb->cp = 0;
8789 return NULL;
8890 }
8991 if (mb->len == 0) {
90 i_push_error(errno, "unexpected end of file");
9192 mm_log((1, "i_readpnm: end of file\n"));
9293 return NULL;
9394 }
107108 =cut
108109 */
109110
111 #define gpeek(mb) ((mb)->cp == (mb)->len ? gpeekf(mb) : (mb)->buf + (mb)->cp)
112
110113 static
111114 char *
112 gpeek(mbuf *mb) {
115 gpeekf(mbuf *mb) {
113116 io_glue *ig = mb->ig;
114117 if (mb->cp == mb->len) {
115118 mb->cp = 0;
120123 return NULL;
121124 }
122125 if (mb->len == 0) {
123 i_push_error(0, "unexpected end of file");
124126 mm_log((1, "i_readpnm: end of file\n"));
125127 return NULL;
126128 }
128130 return &mb->buf[mb->cp];
129131 }
130132
131
133 int
134 gread(mbuf *mb, unsigned char *buf, size_t read_size) {
135 int total_read = 0;
136 if (mb->cp != mb->len) {
137 int avail_size = mb->len - mb->cp;
138 int use_size = read_size > avail_size ? avail_size : read_size;
139 memcpy(buf, mb->buf+mb->cp, use_size);
140 mb->cp += use_size;
141 total_read += use_size;
142 read_size -= use_size;
143 buf += use_size;
144 }
145 if (read_size) {
146 io_glue *ig = mb->ig;
147 int read_res = i_io_read(ig, buf, read_size);
148 if (read_res >= 0) {
149 total_read += read_res;
150 }
151 }
152 return total_read;
153 }
132154
133155
134156 /*
201223
202224 if (!skip_spaces(mb)) return 0;
203225
226 if (!(cp = gpeek(mb)))
227 return 0;
228 if (!misnumber(*cp))
229 return 0;
204230 while( (cp = gpeek(mb)) && misnumber(*cp) ) {
205231 *i = *i*10+(*cp-'0');
206232 cp = gnext(mb);
208234 return 1;
209235 }
210236
237 static
238 i_img *
239 read_pgm_ppm_bin8(mbuf *mb, i_img *im, int width, int height,
240 int channels, int maxval, int allow_incomplete) {
241 i_color *line, *linep;
242 int read_size;
243 unsigned char *read_buf, *readp;
244 int x, y, ch;
245 int rounder = maxval / 2;
246
247 line = mymalloc(width * sizeof(i_color));
248 read_size = channels * width;
249 read_buf = mymalloc(read_size);
250 for(y=0;y<height;y++) {
251 linep = line;
252 readp = read_buf;
253 if (gread(mb, read_buf, read_size) != read_size) {
254 myfree(line);
255 myfree(read_buf);
256 if (allow_incomplete) {
257 i_tags_setn(&im->tags, "i_incomplete", 1);
258 i_tags_setn(&im->tags, "i_lines_read", y);
259 return im;
260 }
261 else {
262 i_push_error(0, "short read - file truncated?");
263 i_img_destroy(im);
264 return NULL;
265 }
266 }
267 if (maxval == 255) {
268 for(x=0; x<width; x++) {
269 for(ch=0; ch<channels; ch++) {
270 linep->channel[ch] = *readp++;
271 }
272 ++linep;
273 }
274 }
275 else {
276 for(x=0; x<width; x++) {
277 for(ch=0; ch<channels; ch++) {
278 /* we just clamp samples to the correct range */
279 unsigned sample = *readp++;
280 if (sample > maxval)
281 sample = maxval;
282 linep->channel[ch] = (sample * 255 + rounder) / maxval;
283 }
284 ++linep;
285 }
286 }
287 i_plin(im, 0, width, y, line);
288 }
289 myfree(read_buf);
290 myfree(line);
291
292 return im;
293 }
294
295 static
296 i_img *
297 read_pgm_ppm_bin16(mbuf *mb, i_img *im, int width, int height,
298 int channels, int maxval, int allow_incomplete) {
299 i_fcolor *line, *linep;
300 int read_size;
301 unsigned char *read_buf, *readp;
302 int x, y, ch;
303 double maxvalf = maxval;
304
305 line = mymalloc(width * sizeof(i_fcolor));
306 read_size = channels * width * 2;
307 read_buf = mymalloc(read_size);
308 for(y=0;y<height;y++) {
309 linep = line;
310 readp = read_buf;
311 if (gread(mb, read_buf, read_size) != read_size) {
312 myfree(line);
313 myfree(read_buf);
314 if (allow_incomplete) {
315 i_tags_setn(&im->tags, "i_incomplete", 1);
316 i_tags_setn(&im->tags, "i_lines_read", y);
317 return im;
318 }
319 else {
320 i_push_error(0, "short read - file truncated?");
321 i_img_destroy(im);
322 return NULL;
323 }
324 }
325 for(x=0; x<width; x++) {
326 for(ch=0; ch<channels; ch++) {
327 unsigned sample = (readp[0] << 8) + readp[1];
328 if (sample > maxval)
329 sample = maxval;
330 readp += 2;
331 linep->channel[ch] = sample / maxvalf;
332 }
333 ++linep;
334 }
335 i_plinf(im, 0, width, y, line);
336 }
337 myfree(read_buf);
338 myfree(line);
339
340 return im;
341 }
342
343 static
344 i_img *
345 read_pbm_bin(mbuf *mb, i_img *im, int width, int height, int allow_incomplete) {
346 i_palidx *line, *linep;
347 int read_size;
348 unsigned char *read_buf, *readp;
349 int x, y;
350 unsigned mask;
351
352 line = mymalloc(width * sizeof(i_palidx));
353 read_size = (width + 7) / 8;
354 read_buf = mymalloc(read_size);
355 for(y = 0; y < height; y++) {
356 if (gread(mb, read_buf, read_size) != read_size) {
357 myfree(line);
358 myfree(read_buf);
359 if (allow_incomplete) {
360 i_tags_setn(&im->tags, "i_incomplete", 1);
361 i_tags_setn(&im->tags, "i_lines_read", y);
362 return im;
363 }
364 else {
365 i_push_error(0, "short read - file truncated?");
366 i_img_destroy(im);
367 return NULL;
368 }
369 }
370 linep = line;
371 readp = read_buf;
372 mask = 0x80;
373 for(x = 0; x < width; ++x) {
374 *linep++ = *readp & mask ? 1 : 0;
375 mask >>= 1;
376 if (mask == 0) {
377 ++readp;
378 mask = 0x80;
379 }
380 }
381 i_ppal(im, 0, width, y, line);
382 }
383 myfree(read_buf);
384 myfree(line);
385
386 return im;
387 }
388
389 /* unlike pgm/ppm pbm:
390 - doesn't require spaces between samples (bits)
391 - 1 (maxval) is black instead of white
392 */
393 static
394 i_img *
395 read_pbm_ascii(mbuf *mb, i_img *im, int width, int height, int allow_incomplete) {
396 i_palidx *line, *linep;
397 int x, y;
398
399 line = mymalloc(width * sizeof(i_palidx));
400 for(y = 0; y < height; y++) {
401 linep = line;
402 for(x = 0; x < width; ++x) {
403 char *cp;
404 skip_spaces(mb);
405 if (!(cp = gnext(mb)) || (*cp != '0' && *cp != '1')) {
406 myfree(line);
407 if (allow_incomplete) {
408 i_tags_setn(&im->tags, "i_incomplete", 1);
409 i_tags_setn(&im->tags, "i_lines_read", y);
410 return im;
411 }
412 else {
413 if (cp)
414 i_push_error(0, "invalid data for ascii pnm");
415 else
416 i_push_error(0, "short read - file truncated?");
417 i_img_destroy(im);
418 return NULL;
419 }
420 }
421 *linep++ = *cp == '0' ? 0 : 1;
422 }
423 i_ppal(im, 0, width, y, line);
424 }
425 myfree(line);
426
427 return im;
428 }
429
430 static
431 i_img *
432 read_pgm_ppm_ascii(mbuf *mb, i_img *im, int width, int height, int channels,
433 int maxval, int allow_incomplete) {
434 i_color *line, *linep;
435 int x, y, ch;
436 int rounder = maxval / 2;
437
438 line = mymalloc(width * sizeof(i_color));
439 for(y=0;y<height;y++) {
440 linep = line;
441 for(x=0; x<width; x++) {
442 for(ch=0; ch<channels; ch++) {
443 int sample;
444
445 if (!gnum(mb, &sample)) {
446 myfree(line);
447 if (allow_incomplete) {
448 i_tags_setn(&im->tags, "i_incomplete", 1);
449 i_tags_setn(&im->tags, "i_lines_read", 1);
450 return im;
451 }
452 else {
453 if (gpeek(mb))
454 i_push_error(0, "invalid data for ascii pnm");
455 else
456 i_push_error(0, "short read - file truncated?");
457 i_img_destroy(im);
458 return NULL;
459 }
460 }
461 if (sample > maxval)
462 sample = maxval;
463 linep->channel[ch] = (sample * 255 + rounder) / maxval;
464 }
465 ++linep;
466 }
467 i_plin(im, 0, width, y, line);
468 }
469 myfree(line);
470
471 return im;
472 }
473
474 static
475 i_img *
476 read_pgm_ppm_ascii_16(mbuf *mb, i_img *im, int width, int height,
477 int channels, int maxval, int allow_incomplete) {
478 i_fcolor *line, *linep;
479 int x, y, ch;
480 double maxvalf = maxval;
481
482 line = mymalloc(width * sizeof(i_fcolor));
483 for(y=0;y<height;y++) {
484 linep = line;
485 for(x=0; x<width; x++) {
486 for(ch=0; ch<channels; ch++) {
487 int sample;
488
489 if (!gnum(mb, &sample)) {
490 myfree(line);
491 if (allow_incomplete) {
492 i_tags_setn(&im->tags, "i_incomplete", 1);
493 i_tags_setn(&im->tags, "i_lines_read", y);
494 return im;
495 }
496 else {
497 if (gpeek(mb))
498 i_push_error(0, "invalid data for ascii pnm");
499 else
500 i_push_error(0, "short read - file truncated?");
501 i_img_destroy(im);
502 return NULL;
503 }
504 }
505 if (sample > maxval)
506 sample = maxval;
507 linep->channel[ch] = sample / maxvalf;
508 }
509 ++linep;
510 }
511 i_plinf(im, 0, width, y, line);
512 }
513 myfree(line);
514
515 return im;
516 }
211517
212518 /*
213 =item i_readpnm_wiol(ig, length)
519 =item i_readpnm_wiol(ig, allow_incomplete)
214520
215521 Retrieve an image and stores in the iolayer object. Returns NULL on fatal error.
216522
217523 ig - io_glue object
218 length - maximum length to read from data source, before closing it -1
219 signifies no limit.
524 allow_incomplete - allows a partial file to be read successfully
220525
221526 =cut
222527 */
223528
224529
225530 i_img *
226 i_readpnm_wiol(io_glue *ig, int length) {
531 i_readpnm_wiol(io_glue *ig, int allow_incomplete) {
227532 i_img* im;
228533 int type;
229 int x, y, ch;
230534 int width, height, maxval, channels, pcount;
231535 int rounder;
232536 char *cp;
233 unsigned char *uc;
234537 mbuf buf;
235 i_color val;
236538
237539 i_clear_error();
238
239 mm_log((1,"i_readpnm(ig %p, length %d)\n", ig, length));
540 mm_log((1,"i_readpnm(ig %p, allow_incomplete %d)\n", ig, allow_incomplete));
240541
241542 io_glue_commit_types(ig);
242543 init_buf(&buf, ig);
326627 mm_log((1, "i_readpnm: maxval of %d is over 65535 - invalid pnm file\n"));
327628 return NULL;
328629 }
329 else if (type >= 4 && maxval > 255) {
330 i_push_errorf(0, "maxval of %d is over 255 - not currently supported by Imager for binary pnm", maxval);
331 mm_log((1, "i_readpnm: maxval of %d is over 255 - not currently supported by Imager for binary pnm\n", maxval));
332 return NULL;
333 }
334630 } else maxval=1;
335631 rounder = maxval / 2;
336632
349645 }
350646
351647 mm_log((1, "i_readpnm: (%d x %d), channels = %d, maxval = %d\n", width, height, channels, maxval));
352
353 im = i_img_empty_ch(NULL, width, height, channels);
354
355 i_tags_add(&im->tags, "i_format", 0, "pnm", -1, 0);
648
649 if (type == 1 || type == 4) {
650 i_color pbm_pal[2];
651 pbm_pal[0].channel[0] = 255;
652 pbm_pal[1].channel[0] = 0;
653
654 im = i_img_pal_new(width, height, 1, 256);
655 i_addcolors(im, pbm_pal, 2);
656 }
657 else {
658 if (maxval > 255)
659 im = i_img_16_new(width, height, channels);
660 else
661 im = i_img_8_new(width, height, channels);
662 }
356663
357664 switch (type) {
358665 case 1: /* Ascii types */
666 im = read_pbm_ascii(&buf, im, width, height, allow_incomplete);
667 break;
668
359669 case 2:
360670 case 3:
361 for(y=0;y<height;y++) for(x=0; x<width; x++) {
362 for(ch=0; ch<channels; ch++) {
363 int t;
364 if (gnum(&buf, &t)) val.channel[ch] = (t * 255 + rounder) / maxval;
365 else {
366 mm_log((1,"i_readpnm: gnum() returned false in data\n"));
367 return im;
368 }
369 }
370 i_ppix(im, x, y, &val);
371 }
671 if (maxval > 255)
672 im = read_pgm_ppm_ascii_16(&buf, im, width, height, channels, maxval, allow_incomplete);
673 else
674 im = read_pgm_ppm_ascii(&buf, im, width, height, channels, maxval, allow_incomplete);
372675 break;
373676
374677 case 4: /* binary pbm */
375 for(y=0;y<height;y++) for(x=0; x<width; x+=8) {
376 if ( (uc = (unsigned char*)gnext(&buf)) ) {
377 int xt;
378 int pc = width-x < 8 ? width-x : 8;
379 /* mm_log((1,"i_readpnm: y=%d x=%d pc=%d\n", y, x, pc)); */
380 for(xt = 0; xt<pc; xt++) {
381 val.channel[0] = (*uc & (128>>xt)) ? 0 : 255;
382 i_ppix(im, x+xt, y, &val);
383 }
384 } else {
385 mm_log((1,"i_readpnm: gnext() returned false in data\n"));
386 return im;
387 }
388 }
678 im = read_pbm_bin(&buf, im, width, height, allow_incomplete);
389679 break;
390680
391681 case 5: /* binary pgm */
392682 case 6: /* binary ppm */
393 for(y=0;y<height;y++) for(x=0; x<width; x++) {
394 for(ch=0; ch<channels; ch++) {
395 if ( (uc = (unsigned char*)gnext(&buf)) )
396 val.channel[ch] = (*uc * 255 + rounder) / maxval;
397 else {
398 mm_log((1,"i_readpnm: gnext() returned false in data\n"));
399 return im;
400 }
401 }
402 i_ppix(im, x, y, &val);
403 }
683 if (maxval > 255)
684 im = read_pgm_ppm_bin16(&buf, im, width, height, channels, maxval, allow_incomplete);
685 else
686 im = read_pgm_ppm_bin8(&buf, im, width, height, channels, maxval, allow_incomplete);
404687 break;
688
405689 default:
406690 mm_log((1, "type %s [P%d] unsupported\n", typenames[type-1], type));
407691 return NULL;
408692 }
693
694 if (!im)
695 return NULL;
696
697 i_tags_add(&im->tags, "i_format", 0, "pnm", -1, 0);
698 i_tags_setn(&im->tags, "pnm_maxval", maxval);
699 i_tags_setn(&im->tags, "pnm_type", type);
700
409701 return im;
410702 }
411703
704 static
705 int
706 write_pbm(i_img *im, io_glue *ig, int zero_is_white) {
707 int x, y;
708 i_palidx *line;
709 int write_size;
710 unsigned char *write_buf;
711 unsigned char *writep;
712 char header[255];
713 unsigned mask;
714
715 sprintf(header, "P4\012# CREATOR: Imager\012%d %d\012",
716 im->xsize, im->ysize);
717 if (i_io_write(ig, header, strlen(header)) < 0) {
718 i_push_error(0, "could not write pbm header");
719 return 0;
720 }
721 write_size = (im->xsize + 7) / 8;
722 line = mymalloc(sizeof(i_palidx) * im->xsize);
723 write_buf = mymalloc(write_size);
724 for (y = 0; y < im->ysize; ++y) {
725 i_gpal(im, 0, im->xsize, y, line);
726 mask = 0x80;
727 writep = write_buf;
728 memset(write_buf, 0, write_size);
729 for (x = 0; x < im->xsize; ++x) {
730 if (zero_is_white ? line[x] : !line[x])
731 *writep |= mask;
732 mask >>= 1;
733 if (!mask) {
734 ++writep;
735 mask = 0x80;
736 }
737 }
738 if (i_io_write(ig, write_buf, write_size) != write_size) {
739 i_push_error(0, "write failure");
740 myfree(write_buf);
741 myfree(line);
742 return 0;
743 }
744 }
745 myfree(write_buf);
746 myfree(line);
747
748 return 1;
749 }
750
751 static
752 int
753 write_ppm_data_8(i_img *im, io_glue *ig) {
754 int write_size = im->xsize * im->channels;
755 unsigned char *data = mymalloc(write_size);
756 int y = 0;
757 int rc = 1;
758
759 while (y < im->ysize && rc >= 0) {
760 i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
761 if (i_io_write(ig, data, write_size) != write_size) {
762 i_push_error(errno, "could not write ppm data");
763 rc = 0;
764 break;
765 }
766 ++y;
767 }
768 myfree(data);
769
770 return rc;
771 }
772
773 static
774 int
775 write_ppm_data_16(i_img *im, io_glue *ig) {
776 int sample_count = im->channels * im->xsize;
777 int write_size = sample_count * 2;
778 int line_size = sample_count * sizeof(i_fsample_t);
779 i_fsample_t *line_buf = mymalloc(line_size);
780 i_fsample_t *samplep;
781 unsigned char *write_buf = mymalloc(write_size);
782 unsigned char *writep;
783 int sample_num;
784 int y = 0;
785 int rc = 1;
786
787 while (y < im->ysize) {
788 i_gsampf(im, 0, im->xsize, y, line_buf, NULL, im->channels);
789 samplep = line_buf;
790 writep = write_buf;
791 for (sample_num = 0; sample_num < sample_count; ++sample_num) {
792 unsigned sample16 = SampleFTo16(*samplep++);
793 *writep++ = sample16 >> 8;
794 *writep++ = sample16 & 0xFF;
795 }
796 if (i_io_write(ig, write_buf, write_size) != write_size) {
797 i_push_error(errno, "could not write ppm data");
798 rc = 0;
799 break;
800 }
801 ++y;
802 }
803 myfree(line_buf);
804 myfree(write_buf);
805
806 return rc;
807 }
412808
413809 undef_int
414810 i_writeppm_wiol(i_img *im, io_glue *ig) {
415811 char header[255];
416 int rc;
812 int zero_is_white;
813 int wide_data;
417814
418815 mm_log((1,"i_writeppm(im %p, ig %p)\n", im, ig));
419816 i_clear_error();
423820
424821 io_glue_commit_types(ig);
425822
426 if (im->channels == 3) {
427 sprintf(header,"P6\n#CREATOR: Imager\n%d %d\n255\n",im->xsize,im->ysize);
428 if (ig->writecb(ig,header,strlen(header))<0) {
823 if (i_img_is_monochrome(im, &zero_is_white)) {
824 return write_pbm(im, ig, zero_is_white);
825 }
826 else {
827 int type;
828 int maxval;
829
830 if (!i_tags_get_int(&im->tags, "pnm_write_wide_data", 0, &wide_data))
831 wide_data = 0;
832
833 if (im->channels == 3) {
834 type = 6;
835 }
836 else if (im->channels == 1) {
837 type = 5;
838 }
839 else {
840 i_push_error(0, "can only save 1 or 3 channel images to pnm");
841 mm_log((1,"i_writeppm: ppm/pgm is 1 or 3 channel only (current image is %d)\n",im->channels));
842 return(0);
843 }
844 if (im->bits <= 8 || !wide_data)
845 maxval = 255;
846 else
847 maxval = 65535;
848
849 sprintf(header,"P%d\n#CREATOR: Imager\n%d %d\n%d\n",
850 type, im->xsize, im->ysize, maxval);
851
852 if (ig->writecb(ig,header,strlen(header)) != strlen(header)) {
429853 i_push_error(errno, "could not write ppm header");
430854 mm_log((1,"i_writeppm: unable to write ppm header.\n"));
431855 return(0);
432856 }
433857
434858 if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) {
435 rc = ig->writecb(ig,im->idata,im->bytes);
859 if (ig->writecb(ig,im->idata,im->bytes) != im->bytes) {
860 i_push_error(errno, "could not write ppm data");
861 return 0;
862 }
863 }
864 else if (maxval == 255) {
865 if (!write_ppm_data_8(im, ig))
866 return 0;
436867 }
437868 else {
438 unsigned char *data = mymalloc(3 * im->xsize);
439 if (data != NULL) {
440 int y = 0;
441 static int rgb_chan[3] = { 0, 1, 2 };
442
443 rc = 0;
444 while (y < im->ysize && rc >= 0) {
445 i_gsamp(im, 0, im->xsize, y, data, rgb_chan, 3);
446 rc = ig->writecb(ig, data, im->xsize * 3);
447 ++y;
448 }
449 myfree(data);
450 }
451 else {
452 i_push_error(0, "Out of memory");
869 if (!write_ppm_data_16(im, ig))
453870 return 0;
454 }
455 }
456 if (rc<0) {
457 i_push_error(errno, "could not write ppm data");
458 mm_log((1,"i_writeppm: unable to write ppm data.\n"));
459 return(0);
460 }
461 }
462 else if (im->channels == 1) {
463 sprintf(header, "P5\n#CREATOR: Imager\n%d %d\n255\n",
464 im->xsize, im->ysize);
465 if (ig->writecb(ig,header, strlen(header)) < 0) {
466 i_push_error(errno, "could not write pgm header");
467 mm_log((1,"i_writeppm: unable to write pgm header.\n"));
468 return(0);
469 }
470
471 if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) {
472 rc=ig->writecb(ig,im->idata,im->bytes);
473 }
474 else {
475 unsigned char *data = mymalloc(im->xsize);
476 if (data != NULL) {
477 int y = 0;
478 int chan = 0;
479
480 rc = 0;
481 while (y < im->ysize && rc >= 0) {
482 i_gsamp(im, 0, im->xsize, y, data, &chan, 1);
483 rc = ig->writecb(ig, data, im->xsize);
484 ++y;
485 }
486 myfree(data);
487 }
488 else {
489 i_push_error(0, "Out of memory");
490 return 0;
491 }
492 }
493 if (rc<0) {
494 i_push_error(errno, "could not write pgm data");
495 mm_log((1,"i_writeppm: unable to write pgm data.\n"));
496 return(0);
497 }
498 }
499 else {
500 i_push_error(0, "can only save 1 or 3 channel images to pnm");
501 mm_log((1,"i_writeppm: ppm/pgm is 1 or 3 channel only (current image is %d)\n",im->channels));
502 return(0);
871 }
503872 }
504873 ig->closecb(ig);
505874
511880
512881 =head1 AUTHOR
513882
514 Arnar M. Hrafnkelsson <addi@umich.edu>
883 Arnar M. Hrafnkelsson <addi@umich.edu>, Tony Cook<tony@imager.perl.org>
515884
516885 =head1 SEE ALSO
517886
338338 (maxx-p_eval_aty(line, miny))*(p_eval_atx(line, maxx)-miny)/2.0;
339339 return r;
340340 }
341
342 return 0; /* silence compiler warning */
341343 }
342344
343345
531533 i_poly_aa_low(i_img *im, int l, const double *x, const double *y, void const *ctx, scanline_flusher flusher) {
532534 int i ,k; /* Index variables */
533535 int clc; /* Lines inside current interval */
534 pcord tempy;
535 int cscl; /* Current scanline */
536 /* initialize to avoid compiler warnings */
537 pcord tempy = 0;
538 int cscl = 0; /* Current scanline */
536539
537540 ss_scanline templine; /* scanline accumulator */
538541 p_point *pset; /* List of points in polygon */
55
66 static void makemap_addi(i_quantize *, i_img **imgs, int count);
77 static void makemap_mediancut(i_quantize *, i_img **imgs, int count);
8 static void makemap_mono(i_quantize *);
89
910 static
1011 void
6869
6970 case mc_median_cut:
7071 makemap_mediancut(quant, imgs, count);
72 break;
73
74 case mc_mono:
75 makemap_mono(quant);
7176 break;
7277
7378 case mc_addi:
615620 color_count = 1;
616621
617622 while (color_count < quant->mc_size) {
618 int max_index, max_ch; /* index/channel with biggest spread */
623 /* initialized to avoid compiler warnings */
624 int max_index = 0, max_ch = 0; /* index/channel with biggest spread */
619625 int max_size;
620626 medcut_partition *workpart;
621627 int cum_total;
693699 }
694700 /*printf("out %d colors\n", quant->mc_count);*/
695701 i_mempool_destroy(&mp);
702 }
703
704 static void
705 makemap_mono(i_quantize *quant) {
706 quant->mc_colors[0].rgba.r = 0;
707 quant->mc_colors[0].rgba.g = 0;
708 quant->mc_colors[0].rgba.b = 0;
709 quant->mc_colors[0].rgba.a = 255;
710 quant->mc_colors[1].rgba.r = 255;
711 quant->mc_colors[1].rgba.g = 255;
712 quant->mc_colors[1].rgba.b = 255;
713 quant->mc_colors[1].rgba.a = 255;
714 quant->mc_count = 2;
696715 }
697716
698717 #define pboxjump 32
10861105 #endif
10871106
10881107 static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
1089 int x, y, i, k, bst_idx;
1108 int x, y, i, k, bst_idx = 0;
10901109 i_color val;
10911110 int pixdev = quant->perturb;
10921111 CF_VARS;
11831202 int errw;
11841203 int difftotal;
11851204 int x, y, dx, dy;
1186 int bst_idx;
1205 int bst_idx = 0;
11871206 CF_VARS;
11881207
11891208 if ((quant->errdiff & ed_mask) == ed_custom) {
4343 }
4444 }
4545 print OUT "\n\@EXPORT = qw(@ops);\n\n";
46 my $dumper = Data::Dumper->new([\%attr],["*Attr"]);
47 $dumper->Sortkeys(1);
48 print OUT $dumper->Dump;
46 # previously we used Data::Dumper, with Sortkeys()
47 # to make sure the generated code only changed when the data
48 # changed. Unfortunately Sortkeys isn't supported in some versions of
49 # perl we try to support, so we now generate this manually
50 print OUT "%Attr =\n (\n";
51 for my $opname (sort keys %attr) {
52 my $op = $attr{$opname};
53 print OUT " '$opname' =>\n {\n";
54 for my $attrname (sort keys %$op) {
55 my $attr = $op->{$attrname};
56 print OUT " '$attrname' => ";
57 if (defined $attr) {
58 if ($attr =~ /^\d+$/) {
59 print OUT $attr;
60 }
61 else {
62 print OUT "'$attr'";
63 }
64 }
65 else {
66 print OUT "undef";
67 }
68
69 print OUT ",\n";
70 }
71 print OUT " },\n";
72 }
73 print OUT " );\n";
4974 print OUT "\$MaxOperands = $max_opr;\n";
5075 print OUT qq/\$PackCode = "$reg_pack";\n/;
5176 print OUT <<'EOS';
0 /*
1 Render utilities
2 */
3 #include "imager.h"
4
5 #define RENDER_MAGIC 0x765AE
6
7 typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *src, i_color const *color);
8
9 #code
10
11 static void IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
12 static void IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
13
14 static render_color_f IM_SUFFIX(render_color_tab)[] =
15 {
16 NULL,
17 IM_SUFFIX(render_color_13),
18 IM_SUFFIX(render_color_alpha),
19 IM_SUFFIX(render_color_13),
20 IM_SUFFIX(render_color_alpha),
21 };
22
23 #/code
24
25 void
26 i_render_init(i_render *r, i_img *im, int width) {
27 r->magic = RENDER_MAGIC;
28 r->im = im;
29 r->width = width;
30 r->line_8 = NULL;
31 r->line_double = NULL;
32 #code im->bits <= 8
33 r->IM_SUFFIX(line) = mymalloc(sizeof(i_fcolor) * width);
34 #/code
35 }
36
37 void
38 i_render_done(i_render *r) {
39 if (r->line_8)
40 myfree(r->line_8);
41 else
42 myfree(r->line_double);
43 r->magic = 0;
44 }
45
46 void
47 i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
48 i_color const *color) {
49 i_img *im = r->im;
50 if (y < 0 || y >= im->ysize)
51 return;
52 if (x < 0) {
53 width += x;
54 src -= x;
55 x = 0;
56 }
57 if (x + width > im->xsize) {
58 width = im->xsize - x;
59 }
60 if (x >= im->xsize || x + width <= 0 || width <= 0)
61 return;
62
63 /* avoid as much work as we can */
64 while (width > 0 && *src == 0) {
65 --width;
66 ++src;
67 ++x;
68 }
69 while (width > 0 && src[width-1] == 0) {
70 --width;
71 }
72 if (!width)
73 return;
74
75 /* make sure our line buffer is big enough */
76 if (width > r->width) {
77 int new_width = r->width * 2;
78 if (new_width < width)
79 new_width = width;
80
81 if (r->line_8)
82 r->line_8 = myrealloc(r->line_8, sizeof(i_color) * new_width);
83 else
84 r->line_double = myrealloc(r->line_double, sizeof(i_fcolor) * new_width);
85 }
86
87 #code r->im->bits <= 8
88 (IM_SUFFIX(render_color_tab)[im->channels])(r, x, y, width, src, color);
89 #/code
90 }
91
92 static void
93 dump_src(const char *note, unsigned char const *src, int width) {
94 int i;
95 printf("%s - %p/%d\n", note, src, width);
96 for (i = 0; i < width; ++i) {
97 printf("%02x ", src[i]);
98 }
99 putchar('\n');
100 }
101
102 #code
103
104 static
105 void
106 IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width,
107 unsigned char const *src, i_color const *color) {
108 i_img *im = r->im;
109 IM_COLOR *linep = r->IM_SUFFIX(line);
110 int ch, channels = im->channels;
111 int fetch_offset;
112 #undef STORE_COLOR
113 #ifdef IM_EIGHT_BIT
114 #define STORE_COLOR (*color)
115 #else
116 i_fcolor fcolor;
117
118 for (ch = 0; ch < channels; ++ch) {
119 fcolor.channel[ch] = color->channel[ch] / 255.0;
120 }
121 #define STORE_COLOR fcolor
122 #endif
123
124 fetch_offset = 0;
125 while (fetch_offset < width && *src == 0xFF) {
126 *linep++ = STORE_COLOR;
127 ++src;
128 ++fetch_offset;
129 }
130 IM_GLIN(im, x+fetch_offset, x+width, y, linep);
131 while (fetch_offset < width) {
132 #ifdef IM_EIGHT_BIT
133 IM_WORK_T alpha = *src++;
134 #else
135 IM_WORK_T alpha = *src++ / 255.0;
136 #endif
137 if (alpha == IM_SAMPLE_MAX)
138 *linep = STORE_COLOR;
139 else if (alpha) {
140 for (ch = 0; ch < channels; ++ch) {
141 linep->channel[ch] = (linep->channel[ch] * (IM_SAMPLE_MAX - alpha)
142 + STORE_COLOR.channel[ch] * alpha) / IM_SAMPLE_MAX;
143 }
144 }
145 ++linep;
146 ++fetch_offset;
147 }
148 IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line));
149 }
150
151 static
152 void
153 IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width,
154 unsigned char const *src, i_color const *color) {
155 IM_COLOR *linep = r->IM_SUFFIX(line);
156 int ch;
157 int alpha_channel = r->im->channels - 1;
158 int fetch_offset;
159 #undef STORE_COLOR
160 #ifdef IM_EIGHT_BIT
161 #define STORE_COLOR (*color)
162 #else
163 i_fcolor fcolor;
164
165 for (ch = 0; ch < r->im->channels; ++ch) {
166 fcolor.channel[ch] = color->channel[ch] / 255.0;
167 }
168 #define STORE_COLOR fcolor
169 #endif
170
171 fetch_offset = 0;
172 while (fetch_offset < width && *src == 0xFF) {
173 *linep++ = STORE_COLOR;
174 ++src;
175 ++fetch_offset;
176 }
177 IM_GLIN(r->im, x+fetch_offset, x+width, y, linep);
178 while (fetch_offset < width) {
179 #ifdef IM_EIGHT_BIT
180 IM_WORK_T src_alpha = *src++;
181 #else
182 IM_WORK_T src_alpha = *src++ / 255.0;
183 #endif
184 if (src_alpha == IM_SAMPLE_MAX)
185 *linep = STORE_COLOR;
186 else if (src_alpha) {
187 IM_WORK_T remains = - src_alpha;
188 IM_WORK_T orig_alpha = linep->channel[alpha_channel];
189 IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX;
190 for (ch = 0; ch < alpha_channel; ++ch) {
191 linep->channel[ch] = ( src_alpha * STORE_COLOR.channel[ch]
192 + remains * linep->channel[ch] * orig_alpha / IM_SAMPLE_MAX
193 ) / dest_alpha;
194 }
195 linep->channel[alpha_channel] = dest_alpha;
196 }
197 ++linep;
198 ++fetch_offset;
199 }
200 IM_PLIN(r->im, x, x+width, y, r->IM_SUFFIX(line));
201 }
202
203 #/code
0 #ifndef IMAGER_RENDERT_H
1 #define IMAGER_RENDERT_H
2
3 typedef struct {
4 int magic;
5 i_img *im;
6 i_color *line_8;
7 i_fcolor *line_double;
8 int width;
9 } i_render;
10
11 #endif
9292 header->colormap = (headbuf[100]<<24) + (headbuf[101]<<16)+(headbuf[102]<<8)+headbuf[103];
9393 }
9494
95 #if 0 /* this is currently unused */
9596
9697 /*
9798 =item rgb_header_pack(header, headbuf)
145146 return -1;
146147 }
147148
148
149 #endif
149150
150151
151152
294295 for(y=0; y<height; y++) {
295296 for(c=0; c<channels; c++) {
296297 unsigned long iidx = 0, oidx = 0, span = 0;
297 unsigned char cval;
298 unsigned char cval = 0;
298299 int rle = 0;
299300 int ci = height*c+y;
300301 int datalen = lengthtab[ci];
214214 sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
215215 sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
216216 }
217 else {
218 sx = sy = 0;
219 }
217220
218221 /* anything outside these ranges is either a broken co-ordinate
219222 or outside the source */
289292 sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
290293 sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
291294 }
295 else {
296 sx = sy = 0;
297 }
292298
293299 /* anything outside these ranges is either a broken co-ordinate
294300 or outside the source */
388394 if (abs(sz) > 0.0000001) {
389395 sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
390396 sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
397 }
398 else {
399 sx = sy = 0;
391400 }
392401
393402 /* anything outside these ranges is either a broken co-ordinate
9696
9797 Demonstrates using Inline and Imager's API to convert captured BGR
9898 image data into an Imager image.
99
100 flasher.pl
101
102 Animate an image fading down to a background color and back again.
103
104 Demonstrates setting an alpha channel with convert(), rubthrough(),
105 and writing animated GIFs.
0 #!perl
1 use strict;
2 use Imager;
3 use Getopt::Long;
4
5 my $delay = 10;
6 my $frames = 20;
7 my $low_pct = 30;
8 my $back = '#FFFFFF';
9 my $verbose = 0;
10 GetOptions('delay|d=i', \$delay,
11 'frames|f=i', \$frames,
12 'lowpct|p=i', \$low_pct,
13 'back|b=s', \$back,
14 'verbose|v' => \$verbose);
15
16 my $back_color = Imager::Color->new($back)
17 or die "Cannot convert $back to a color: ", Imager->errstr, "\n";
18
19 $low_pct >= 0 && $low_pct < 100
20 or die "lowpct must be >=0 and < 100\n";
21
22 $delay > 0 and $delay < 255
23 or die "delay must be between 1 and 255\n";
24
25 $frames > 1
26 or die "frames must be > 1\n";
27
28 my $in_name = shift
29 or usage();
30
31 my $out_name = shift
32 or usage();
33
34 my $base = Imager->new;
35 $base->read(file => $in_name)
36 or die "Cannot read image file $in_name: ", $base->errstr, "\n";
37
38 # convert to RGBA to simplify the convert() matrix
39 $base = $base->convert(preset => 'rgb') unless $base->getchannels >=3;
40 $base = $base->convert(preset => 'addalpha') unless $base->getchannels == 4;
41
42 my $width = $base->getwidth;
43 my $height = $base->getheight;
44
45 my @down;
46 my $down_frames = $frames / 2;
47 my $step = (100 - $low_pct) / $down_frames;
48 my $percent = 100 - $step;
49 ++$|;
50 print "Generating frames\n" if $verbose;
51 for my $frame_no (1 .. $down_frames) {
52 print "\rFrame $frame_no/$down_frames";
53
54 # canvas with our background color
55 my $canvas = Imager->new(xsize => $width, ysize => $height);
56 $canvas->box(filled => 1, color => $back_color);
57
58 # make a version of our original with the alpha scaled
59 my $scale = $percent / 100.0;
60 my $draw = $base->convert(matrix => [ [ 1, 0, 0, 0 ],
61 [ 0, 1, 0, 0 ],
62 [ 0, 0, 1, 0 ],
63 [ 0, 0, 0, $scale ] ]);
64
65 # draw it on the canvas
66 $canvas->rubthrough(src => $draw);
67
68 push @down, $canvas;
69 $percent -= $step;
70 }
71 print "\n" if $verbose;
72
73 # generate a sequence going from the original down to the most faded
74 my @frames = $base;
75 push @frames, @down;
76 # remove the most faded frame so it isn't repeated
77 pop @down;
78 # and back up again
79 push @frames, reverse @down;
80
81 print "Writing frames\n" if $verbose;
82 Imager->write_multi({ file => $out_name,
83 type => 'gif',
84 gif_loop => 0, # loop forever
85 gif_delay => $delay,
86 translate => 'errdiff',
87 make_colors => 'mediancut',
88 },
89 @frames)
90 or die "Cannot write $out_name: ", Imager->errstr, "\n";
91
92 sub usage {
93 die <<EOS;
94 Produce an animated gif that cycles an image fading into a background and
95 unfading back to the original image.
96 Usage: $0 [options] input output
97 Input can be any image supported by Imager.
98 Output should be a .gif file.
99 Options include:
100 -v | --verbose
101 Progress reports
102 -d <delay> | --delay <delay>
103 Delay between frames in 1/100 sec. Default 10.
104 -p <percent> | --percent <percent>
105 Low percentage coverage. Default: 30
106 -b <color> | --back <color>
107 Color to fade towards, in some format Imager understands.
108 Default: #FFFFFF
109 -f <frames> | --frames <frames>
110 Rough total number of frames to produce. Default: 20.
111 EOS
112 }
113
114 =head1 NAME
115
116 flasher.pl - produces a slowly flashing GIF based on an input image
117
118 =head1 SYNOPSIS
119
120 perl flasher.pl [options] input output.gif
121
122 =head1 DESCRIPTION
123
124 flasher.pl generates an animation from the given image to I<lowpct>%
125 coverage on a blank image of color I<back>.
126
127 =head1 OPTIONS
128
129 =over
130
131 =item *
132
133 -f I<frames>, --frames I<frames> - the total number of frames. This is
134 always rounded up to the next even number. Default: 20
135
136 =item *
137
138 -d I<delay>, --delay I<delay> - the delay in 1/100 second between
139 frames. Default: 10.
140
141 =item *
142
143 -p I<percent>, --lowpct I<percent> - the lowest coverage of the image.
144 Default: 30
145
146 =item *
147
148 -b I<color>, --back I<color> - the background color to fade to.
149 Default: #FFFFFF.
150
151 =item *
152
153 -v, --verbose - produce progress information.
154
155 =item
156
157 =back
158
159 =head1 AUTHOR
160
161 Tony Cook <tonyc@cpan.org>
162
163 =cut
164
112112 for (y = 0; y < y_out; ++y) {
113113 if (y_out == src->ysize) {
114114 /* no vertical scaling, just load it */
115 #ifdef IM_EIGHT_BIT
115116 int x, ch;
116 #ifdef IM_EIGHT_BIT
117117 /* load and convert to doubles */
118118 IM_GLIN(src, 0, src->xsize, y, in_row);
119119 for (x = 0; x < src->xsize; ++x) {
154154 }
155155 /* we've accumulated a vertically scaled row */
156156 if (x_out == src->xsize) {
157 #if IM_EIGHT_BIT
157158 int x, ch;
158 #if IM_EIGHT_BIT
159159 /* no need to scale, but we need to convert it */
160160 for (x = 0; x < x_out; ++x) {
161161 for (ch = 0; ch < result->channels; ++ch)
+0
-1408
t/Test/Builder.pm less more
0 package Test::Builder;
1
2 use 5.004;
3
4 # $^C was only introduced in 5.005-ish. We do this to prevent
5 # use of uninitialized value warnings in older perls.
6 $^C ||= 0;
7
8 use strict;
9 use vars qw($VERSION $CLASS);
10 $VERSION = '0.17';
11 $CLASS = __PACKAGE__;
12
13 my $IsVMS = $^O eq 'VMS';
14
15 # Make Test::Builder thread-safe for ithreads.
16 BEGIN {
17 use Config;
18 if( $] >= 5.008 && $Config{useithreads} ) {
19 require threads;
20 require threads::shared;
21 threads::shared->import;
22 }
23 else {
24 *share = sub { 0 };
25 *lock = sub { 0 };
26 }
27 }
28
29 use vars qw($Level);
30 my($Test_Died) = 0;
31 my($Have_Plan) = 0;
32 my $Original_Pid = $$;
33 my $Curr_Test = 0; share($Curr_Test);
34 my @Test_Results = (); share(@Test_Results);
35 my @Test_Details = (); share(@Test_Details);
36
37
38 =head1 NAME
39
40 Test::Builder - Backend for building test libraries
41
42 =head1 SYNOPSIS
43
44 package My::Test::Module;
45 use Test::Builder;
46 require Exporter;
47 @ISA = qw(Exporter);
48 @EXPORT = qw(ok);
49
50 my $Test = Test::Builder->new;
51 $Test->output('my_logfile');
52
53 sub import {
54 my($self) = shift;
55 my $pack = caller;
56
57 $Test->exported_to($pack);
58 $Test->plan(@_);
59
60 $self->export_to_level(1, $self, 'ok');
61 }
62
63 sub ok {
64 my($test, $name) = @_;
65
66 $Test->ok($test, $name);
67 }
68
69
70 =head1 DESCRIPTION
71
72 Test::Simple and Test::More have proven to be popular testing modules,
73 but they're not always flexible enough. Test::Builder provides the a
74 building block upon which to write your own test libraries I<which can
75 work together>.
76
77 =head2 Construction
78
79 =over 4
80
81 =item B<new>
82
83 my $Test = Test::Builder->new;
84
85 Returns a Test::Builder object representing the current state of the
86 test.
87
88 Since you only run one test per program, there is B<one and only one>
89 Test::Builder object. No matter how many times you call new(), you're
90 getting the same object. (This is called a singleton).
91
92 =cut
93
94 my $Test;
95 sub new {
96 my($class) = shift;
97 $Test ||= bless ['Move along, nothing to see here'], $class;
98 return $Test;
99 }
100
101 =back
102
103 =head2 Setting up tests
104
105 These methods are for setting up tests and declaring how many there
106 are. You usually only want to call one of these methods.
107
108 =over 4
109
110 =item B<exported_to>
111
112 my $pack = $Test->exported_to;
113 $Test->exported_to($pack);
114
115 Tells Test::Builder what package you exported your functions to.
116 This is important for getting TODO tests right.
117
118 =cut
119
120 my $Exported_To;
121 sub exported_to {
122 my($self, $pack) = @_;
123
124 if( defined $pack ) {
125 $Exported_To = $pack;
126 }
127 return $Exported_To;
128 }
129
130 =item B<plan>
131
132 $Test->plan('no_plan');
133 $Test->plan( skip_all => $reason );
134 $Test->plan( tests => $num_tests );
135
136 A convenient way to set up your tests. Call this and Test::Builder
137 will print the appropriate headers and take the appropriate actions.
138
139 If you call plan(), don't call any of the other methods below.
140
141 =cut
142
143 sub plan {
144 my($self, $cmd, $arg) = @_;
145
146 return unless $cmd;
147
148 if( $Have_Plan ) {
149 die sprintf "You tried to plan twice! Second plan at %s line %d\n",
150 ($self->caller)[1,2];
151 }
152
153 if( $cmd eq 'no_plan' ) {
154 $self->no_plan;
155 }
156 elsif( $cmd eq 'skip_all' ) {
157 return $self->skip_all($arg);
158 }
159 elsif( $cmd eq 'tests' ) {
160 if( $arg ) {
161 return $self->expected_tests($arg);
162 }
163 elsif( !defined $arg ) {
164 die "Got an undefined number of tests. Looks like you tried to ".
165 "say how many tests you plan to run but made a mistake.\n";
166 }
167 elsif( !$arg ) {
168 die "You said to run 0 tests! You've got to run something.\n";
169 }
170 }
171 else {
172 require Carp;
173 my @args = grep { defined } ($cmd, $arg);
174 Carp::croak("plan() doesn't understand @args");
175 }
176
177 return 1;
178 }
179
180 =item B<expected_tests>
181
182 my $max = $Test->expected_tests;
183 $Test->expected_tests($max);
184
185 Gets/sets the # of tests we expect this test to run and prints out
186 the appropriate headers.
187
188 =cut
189
190 my $Expected_Tests = 0;
191 sub expected_tests {
192 my($self, $max) = @_;
193
194 if( defined $max ) {
195 $Expected_Tests = $max;
196 $Have_Plan = 1;
197
198 $self->_print("1..$max\n") unless $self->no_header;
199 }
200 return $Expected_Tests;
201 }
202
203
204 =item B<no_plan>
205
206 $Test->no_plan;
207
208 Declares that this test will run an indeterminate # of tests.
209
210 =cut
211
212 my($No_Plan) = 0;
213 sub no_plan {
214 $No_Plan = 1;
215 $Have_Plan = 1;
216 }
217
218 =item B<has_plan>
219
220 $plan = $Test->has_plan
221
222 Find out whether a plan has been defined. $plan is either C<undef> (no plan has been set), C<no_plan> (indeterminate # of tests) or an integer (the number of expected tests).
223
224 =cut
225
226 sub has_plan {
227 return($Expected_Tests) if $Expected_Tests;
228 return('no_plan') if $No_Plan;
229 return(undef);
230 };
231
232
233 =item B<skip_all>
234
235 $Test->skip_all;
236 $Test->skip_all($reason);
237
238 Skips all the tests, using the given $reason. Exits immediately with 0.
239
240 =cut
241
242 my $Skip_All = 0;
243 sub skip_all {
244 my($self, $reason) = @_;
245
246 my $out = "1..0";
247 $out .= " # Skip $reason" if $reason;
248 $out .= "\n";
249
250 $Skip_All = 1;
251
252 $self->_print($out) unless $self->no_header;
253 exit(0);
254 }
255
256 =back
257
258 =head2 Running tests
259
260 These actually run the tests, analogous to the functions in
261 Test::More.
262
263 $name is always optional.
264
265 =over 4
266
267 =item B<ok>
268
269 $Test->ok($test, $name);
270
271 Your basic test. Pass if $test is true, fail if $test is false. Just
272 like Test::Simple's ok().
273
274 =cut
275
276 sub ok {
277 my($self, $test, $name) = @_;
278
279 # $test might contain an object which we don't want to accidentally
280 # store, so we turn it into a boolean.
281 $test = $test ? 1 : 0;
282
283 unless( $Have_Plan ) {
284 require Carp;
285 Carp::croak("You tried to run a test without a plan! Gotta have a plan.");
286 }
287
288 lock $Curr_Test;
289 $Curr_Test++;
290
291 $self->diag(<<ERR) if defined $name and $name =~ /^[\d\s]+$/;
292 You named your test '$name'. You shouldn't use numbers for your test names.
293 Very confusing.
294 ERR
295
296 my($pack, $file, $line) = $self->caller;
297
298 my $todo = $self->todo($pack);
299
300 my $out;
301 my $result = {};
302 share($result);
303
304 unless( $test ) {
305 $out .= "not ";
306 @$result{ 'ok', 'actual_ok' } = ( ( $todo ? 1 : 0 ), 0 );
307 }
308 else {
309 @$result{ 'ok', 'actual_ok' } = ( 1, $test );
310 }
311
312 $out .= "ok";
313 $out .= " $Curr_Test" if $self->use_numbers;
314
315 if( defined $name ) {
316 $name =~ s|#|\\#|g; # # in a name can confuse Test::Harness.
317 $out .= " - $name";
318 $result->{name} = $name;
319 }
320 else {
321 $result->{name} = '';
322 }
323
324 if( $todo ) {
325 my $what_todo = $todo;
326 $out .= " # TODO $what_todo";
327 $result->{reason} = $what_todo;
328 $result->{type} = 'todo';
329 }
330 else {
331 $result->{reason} = '';
332 $result->{type} = '';
333 }
334
335 $Test_Results[$Curr_Test-1] = $result;
336 $out .= "\n";
337
338 $self->_print($out);
339
340 unless( $test ) {
341 my $msg = $todo ? "Failed (TODO)" : "Failed";
342 $self->diag(" $msg test ($file at line $line)\n");
343 }
344
345 return $test ? 1 : 0;
346 }
347
348 =item B<is_eq>
349
350 $Test->is_eq($got, $expected, $name);
351
352 Like Test::More's is(). Checks if $got eq $expected. This is the
353 string version.
354
355 =item B<is_num>
356
357 $Test->is_num($got, $expected, $name);
358
359 Like Test::More's is(). Checks if $got == $expected. This is the
360 numeric version.
361
362 =cut
363
364 sub is_eq {
365 my($self, $got, $expect, $name) = @_;
366 local $Level = $Level + 1;
367
368 if( !defined $got || !defined $expect ) {
369 # undef only matches undef and nothing else
370 my $test = !defined $got && !defined $expect;
371
372 $self->ok($test, $name);
373 $self->_is_diag($got, 'eq', $expect) unless $test;
374 return $test;
375 }
376
377 return $self->cmp_ok($got, 'eq', $expect, $name);
378 }
379
380 sub is_num {
381 my($self, $got, $expect, $name) = @_;
382 local $Level = $Level + 1;
383
384 if( !defined $got || !defined $expect ) {
385 # undef only matches undef and nothing else
386 my $test = !defined $got && !defined $expect;
387
388 $self->ok($test, $name);
389 $self->_is_diag($got, '==', $expect) unless $test;
390 return $test;
391 }
392
393 return $self->cmp_ok($got, '==', $expect, $name);
394 }
395
396 sub _is_diag {
397 my($self, $got, $type, $expect) = @_;
398
399 foreach my $val (\$got, \$expect) {
400 if( defined $$val ) {
401 if( $type eq 'eq' ) {
402 # quote and force string context
403 $$val = "'$$val'"
404 }
405 else {
406 # force numeric context
407 $$val = $$val+0;
408 }
409 }
410 else {
411 $$val = 'undef';
412 }
413 }
414
415 return $self->diag(sprintf <<DIAGNOSTIC, $got, $expect);
416 got: %s
417 expected: %s
418 DIAGNOSTIC
419
420 }
421
422 =item B<isnt_eq>
423
424 $Test->isnt_eq($got, $dont_expect, $name);
425
426 Like Test::More's isnt(). Checks if $got ne $dont_expect. This is
427 the string version.
428
429 =item B<isnt_num>
430
431 $Test->is_num($got, $dont_expect, $name);
432
433 Like Test::More's isnt(). Checks if $got ne $dont_expect. This is
434 the numeric version.
435
436 =cut
437
438 sub isnt_eq {
439 my($self, $got, $dont_expect, $name) = @_;
440 local $Level = $Level + 1;
441
442 if( !defined $got || !defined $dont_expect ) {
443 # undef only matches undef and nothing else
444 my $test = defined $got || defined $dont_expect;
445
446 $self->ok($test, $name);
447 $self->_cmp_diag('ne', $got, $dont_expect) unless $test;
448 return $test;
449 }
450
451 return $self->cmp_ok($got, 'ne', $dont_expect, $name);
452 }
453
454 sub isnt_num {
455 my($self, $got, $dont_expect, $name) = @_;
456 local $Level = $Level + 1;
457
458 if( !defined $got || !defined $dont_expect ) {
459 # undef only matches undef and nothing else
460 my $test = defined $got || defined $dont_expect;
461
462 $self->ok($test, $name);
463 $self->_cmp_diag('!=', $got, $dont_expect) unless $test;
464 return $test;
465 }
466
467 return $self->cmp_ok($got, '!=', $dont_expect, $name);
468 }
469
470
471 =item B<like>
472
473 $Test->like($this, qr/$regex/, $name);
474 $Test->like($this, '/$regex/', $name);
475
476 Like Test::More's like(). Checks if $this matches the given $regex.
477
478 You'll want to avoid qr// if you want your tests to work before 5.005.
479
480 =item B<unlike>
481
482 $Test->unlike($this, qr/$regex/, $name);
483 $Test->unlike($this, '/$regex/', $name);
484
485 Like Test::More's unlike(). Checks if $this B<does not match> the
486 given $regex.
487
488 =cut
489
490 sub like {
491 my($self, $this, $regex, $name) = @_;
492
493 local $Level = $Level + 1;
494 $self->_regex_ok($this, $regex, '=~', $name);
495 }
496
497 sub unlike {
498 my($self, $this, $regex, $name) = @_;
499
500 local $Level = $Level + 1;
501 $self->_regex_ok($this, $regex, '!~', $name);
502 }
503
504 =item B<maybe_regex>
505
506 $Test->maybe_regex(qr/$regex/);
507 $Test->maybe_regex('/$regex/');
508
509 Convenience method for building testing functions that take regular
510 expressions as arguments, but need to work before perl 5.005.
511
512 Takes a quoted regular expression produced by qr//, or a string
513 representing a regular expression.
514
515 Returns a Perl value which may be used instead of the corresponding
516 regular expression, or undef if it's argument is not recognised.
517
518 For example, a version of like(), sans the useful diagnostic messages,
519 could be written as:
520
521 sub laconic_like {
522 my ($self, $this, $regex, $name) = @_;
523 my $usable_regex = $self->maybe_regex($regex);
524 die "expecting regex, found '$regex'\n"
525 unless $usable_regex;
526 $self->ok($this =~ m/$usable_regex/, $name);
527 }
528
529 =cut
530
531
532 sub maybe_regex {
533 my ($self, $regex) = @_;
534 my $usable_regex = undef;
535 if( ref $regex eq 'Regexp' ) {
536 $usable_regex = $regex;
537 }
538 # Check if it looks like '/foo/'
539 elsif( my($re, $opts) = $regex =~ m{^ /(.*)/ (\w*) $ }sx ) {
540 $usable_regex = length $opts ? "(?$opts)$re" : $re;
541 };
542 return($usable_regex)
543 };
544
545 sub _regex_ok {
546 my($self, $this, $regex, $cmp, $name) = @_;
547
548 local $Level = $Level + 1;
549
550 my $ok = 0;
551 my $usable_regex = $self->maybe_regex($regex);
552 unless (defined $usable_regex) {
553 $ok = $self->ok( 0, $name );
554 $self->diag(" '$regex' doesn't look much like a regex to me.");
555 return $ok;
556 }
557
558 {
559 local $^W = 0;
560 my $test = $this =~ /$usable_regex/ ? 1 : 0;
561 $test = !$test if $cmp eq '!~';
562 $ok = $self->ok( $test, $name );
563 }
564
565 unless( $ok ) {
566 $this = defined $this ? "'$this'" : 'undef';
567 my $match = $cmp eq '=~' ? "doesn't match" : "matches";
568 $self->diag(sprintf <<DIAGNOSTIC, $this, $match, $regex);
569 %s
570 %13s '%s'
571 DIAGNOSTIC
572
573 }
574
575 return $ok;
576 }
577
578 =item B<cmp_ok>
579
580 $Test->cmp_ok($this, $type, $that, $name);
581
582 Works just like Test::More's cmp_ok().
583
584 $Test->cmp_ok($big_num, '!=', $other_big_num);
585
586 =cut
587
588 sub cmp_ok {
589 my($self, $got, $type, $expect, $name) = @_;
590
591 my $test;
592 {
593 local $^W = 0;
594 local($@,$!); # don't interfere with $@
595 # eval() sometimes resets $!
596 $test = eval "\$got $type \$expect";
597 }
598 local $Level = $Level + 1;
599 my $ok = $self->ok($test, $name);
600
601 unless( $ok ) {
602 if( $type =~ /^(eq|==)$/ ) {
603 $self->_is_diag($got, $type, $expect);
604 }
605 else {
606 $self->_cmp_diag($got, $type, $expect);
607 }
608 }
609 return $ok;
610 }
611
612 sub _cmp_diag {
613 my($self, $got, $type, $expect) = @_;
614
615 $got = defined $got ? "'$got'" : 'undef';
616 $expect = defined $expect ? "'$expect'" : 'undef';
617 return $self->diag(sprintf <<DIAGNOSTIC, $got, $type, $expect);
618 %s
619 %s
620 %s
621 DIAGNOSTIC
622 }
623
624 =item B<BAILOUT>
625
626 $Test->BAILOUT($reason);
627
628 Indicates to the Test::Harness that things are going so badly all
629 testing should terminate. This includes running any additional test
630 scripts.
631
632 It will exit with 255.
633
634 =cut
635
636 sub BAILOUT {
637 my($self, $reason) = @_;
638
639 $self->_print("Bail out! $reason");
640 exit 255;
641 }
642
643 =item B<skip>
644
645 $Test->skip;
646 $Test->skip($why);
647
648 Skips the current test, reporting $why.
649
650 =cut
651
652 sub skip {
653 my($self, $why) = @_;
654 $why ||= '';
655
656 unless( $Have_Plan ) {
657 require Carp;
658 Carp::croak("You tried to run tests without a plan! Gotta have a plan.");
659 }
660
661 lock($Curr_Test);
662 $Curr_Test++;
663
664 my %result;
665 share(%result);
666 %result = (
667 'ok' => 1,
668 actual_ok => 1,
669 name => '',
670 type => 'skip',
671 reason => $why,
672 );
673 $Test_Results[$Curr_Test-1] = \%result;
674
675 my $out = "ok";
676 $out .= " $Curr_Test" if $self->use_numbers;
677 $out .= " # skip $why\n";
678
679 $Test->_print($out);
680
681 return 1;
682 }
683
684
685 =item B<todo_skip>
686
687 $Test->todo_skip;
688 $Test->todo_skip($why);
689
690 Like skip(), only it will declare the test as failing and TODO. Similar
691 to
692
693 print "not ok $tnum # TODO $why\n";
694
695 =cut
696
697 sub todo_skip {
698 my($self, $why) = @_;
699 $why ||= '';
700
701 unless( $Have_Plan ) {
702 require Carp;
703 Carp::croak("You tried to run tests without a plan! Gotta have a plan.");
704 }
705
706 lock($Curr_Test);
707 $Curr_Test++;
708
709 my %result;
710 share(%result);
711 %result = (
712 'ok' => 1,
713 actual_ok => 0,
714 name => '',
715 type => 'todo_skip',
716 reason => $why,
717 );
718
719 $Test_Results[$Curr_Test-1] = \%result;
720
721 my $out = "not ok";
722 $out .= " $Curr_Test" if $self->use_numbers;
723 $out .= " # TODO & SKIP $why\n";
724
725 $Test->_print($out);
726
727 return 1;
728 }
729
730
731 =begin _unimplemented
732
733 =item B<skip_rest>
734
735 $Test->skip_rest;
736 $Test->skip_rest($reason);
737
738 Like skip(), only it skips all the rest of the tests you plan to run
739 and terminates the test.
740
741 If you're running under no_plan, it skips once and terminates the
742 test.
743
744 =end _unimplemented
745
746 =back
747
748
749 =head2 Test style
750
751 =over 4
752
753 =item B<level>
754
755 $Test->level($how_high);
756
757 How far up the call stack should $Test look when reporting where the
758 test failed.
759
760 Defaults to 1.
761
762 Setting $Test::Builder::Level overrides. This is typically useful
763 localized:
764
765 {
766 local $Test::Builder::Level = 2;
767 $Test->ok($test);
768 }
769
770 =cut
771
772 sub level {
773 my($self, $level) = @_;
774
775 if( defined $level ) {
776 $Level = $level;
777 }
778 return $Level;
779 }
780
781 $CLASS->level(1);
782
783
784 =item B<use_numbers>
785
786 $Test->use_numbers($on_or_off);
787
788 Whether or not the test should output numbers. That is, this if true:
789
790 ok 1
791 ok 2
792 ok 3
793
794 or this if false
795
796 ok
797 ok
798 ok
799
800 Most useful when you can't depend on the test output order, such as
801 when threads or forking is involved.
802
803 Test::Harness will accept either, but avoid mixing the two styles.
804
805 Defaults to on.
806
807 =cut
808
809 my $Use_Nums = 1;
810 sub use_numbers {
811 my($self, $use_nums) = @_;
812
813 if( defined $use_nums ) {
814 $Use_Nums = $use_nums;
815 }
816 return $Use_Nums;
817 }
818
819 =item B<no_header>
820
821 $Test->no_header($no_header);
822
823 If set to true, no "1..N" header will be printed.
824
825 =item B<no_ending>
826
827 $Test->no_ending($no_ending);
828
829 Normally, Test::Builder does some extra diagnostics when the test
830 ends. It also changes the exit code as described in Test::Simple.
831
832 If this is true, none of that will be done.
833
834 =cut
835
836 my($No_Header, $No_Ending) = (0,0);
837 sub no_header {
838 my($self, $no_header) = @_;
839
840 if( defined $no_header ) {
841 $No_Header = $no_header;
842 }
843 return $No_Header;
844 }
845
846 sub no_ending {
847 my($self, $no_ending) = @_;
848
849 if( defined $no_ending ) {
850 $No_Ending = $no_ending;
851 }
852 return $No_Ending;
853 }
854
855
856 =back
857
858 =head2 Output
859
860 Controlling where the test output goes.
861
862 It's ok for your test to change where STDOUT and STDERR point to,
863 Test::Builder's default output settings will not be affected.
864
865 =over 4
866
867 =item B<diag>
868
869 $Test->diag(@msgs);
870
871 Prints out the given $message. Normally, it uses the failure_output()
872 handle, but if this is for a TODO test, the todo_output() handle is
873 used.
874
875 Output will be indented and marked with a # so as not to interfere
876 with test output. A newline will be put on the end if there isn't one
877 already.
878
879 We encourage using this rather than calling print directly.
880
881 Returns false. Why? Because diag() is often used in conjunction with
882 a failing test (C<ok() || diag()>) it "passes through" the failure.
883
884 return ok(...) || diag(...);
885
886 =for blame transfer
887 Mark Fowler <mark@twoshortplanks.com>
888
889 =cut
890
891 sub diag {
892 my($self, @msgs) = @_;
893 return unless @msgs;
894
895 # Prevent printing headers when compiling (i.e. -c)
896 return if $^C;
897
898 # Escape each line with a #.
899 foreach (@msgs) {
900 $_ = 'undef' unless defined;
901 s/^/# /gms;
902 }
903
904 push @msgs, "\n" unless $msgs[-1] =~ /\n\Z/;
905
906 local $Level = $Level + 1;
907 my $fh = $self->todo ? $self->todo_output : $self->failure_output;
908 local($\, $", $,) = (undef, ' ', '');
909 print $fh @msgs;
910
911 return 0;
912 }
913
914 =begin _private
915
916 =item B<_print>
917
918 $Test->_print(@msgs);
919
920 Prints to the output() filehandle.
921
922 =end _private
923
924 =cut
925
926 sub _print {
927 my($self, @msgs) = @_;
928
929 # Prevent printing headers when only compiling. Mostly for when
930 # tests are deparsed with B::Deparse
931 return if $^C;
932
933 local($\, $", $,) = (undef, ' ', '');
934 my $fh = $self->output;
935
936 # Escape each line after the first with a # so we don't
937 # confuse Test::Harness.
938 foreach (@msgs) {
939 s/\n(.)/\n# $1/sg;
940 }
941
942 push @msgs, "\n" unless $msgs[-1] =~ /\n\Z/;
943
944 print $fh @msgs;
945 }
946
947
948 =item B<output>
949
950 $Test->output($fh);
951 $Test->output($file);
952
953 Where normal "ok/not ok" test output should go.
954
955 Defaults to STDOUT.
956
957 =item B<failure_output>
958
959 $Test->failure_output($fh);
960 $Test->failure_output($file);
961
962 Where diagnostic output on test failures and diag() should go.
963
964 Defaults to STDERR.
965
966 =item B<todo_output>
967
968 $Test->todo_output($fh);
969 $Test->todo_output($file);
970
971 Where diagnostics about todo test failures and diag() should go.
972
973 Defaults to STDOUT.
974
975 =cut
976
977 my($Out_FH, $Fail_FH, $Todo_FH);
978 sub output {
979 my($self, $fh) = @_;
980
981 if( defined $fh ) {
982 $Out_FH = _new_fh($fh);
983 }
984 return $Out_FH;
985 }
986
987 sub failure_output {
988 my($self, $fh) = @_;
989
990 if( defined $fh ) {
991 $Fail_FH = _new_fh($fh);
992 }
993 return $Fail_FH;
994 }
995
996 sub todo_output {
997 my($self, $fh) = @_;
998
999 if( defined $fh ) {
1000 $Todo_FH = _new_fh($fh);
1001 }
1002 return $Todo_FH;
1003 }
1004
1005 sub _new_fh {
1006 my($file_or_fh) = shift;
1007
1008 my $fh;
1009 unless( UNIVERSAL::isa($file_or_fh, 'GLOB') ) {
1010 $fh = do { local *FH };
1011 open $fh, ">$file_or_fh" or
1012 die "Can't open test output log $file_or_fh: $!";
1013 }
1014 else {
1015 $fh = $file_or_fh;
1016 }
1017
1018 return $fh;
1019 }
1020
1021 unless( $^C ) {
1022 # We dup STDOUT and STDERR so people can change them in their
1023 # test suites while still getting normal test output.
1024 open(TESTOUT, ">&STDOUT") or die "Can't dup STDOUT: $!";
1025 open(TESTERR, ">&STDERR") or die "Can't dup STDERR: $!";
1026
1027 # Set everything to unbuffered else plain prints to STDOUT will
1028 # come out in the wrong order from our own prints.
1029 _autoflush(\*TESTOUT);
1030 _autoflush(\*STDOUT);
1031 _autoflush(\*TESTERR);
1032 _autoflush(\*STDERR);
1033
1034 $CLASS->output(\*TESTOUT);
1035 $CLASS->failure_output(\*TESTERR);
1036 $CLASS->todo_output(\*TESTOUT);
1037 }
1038
1039 sub _autoflush {
1040 my($fh) = shift;
1041 my $old_fh = select $fh;
1042 $| = 1;
1043 select $old_fh;
1044 }
1045
1046
1047 =back
1048
1049
1050 =head2 Test Status and Info
1051
1052 =over 4
1053
1054 =item B<current_test>
1055
1056 my $curr_test = $Test->current_test;
1057 $Test->current_test($num);
1058
1059 Gets/sets the current test # we're on.
1060
1061 You usually shouldn't have to set this.
1062
1063 =cut
1064
1065 sub current_test {
1066 my($self, $num) = @_;
1067
1068 lock($Curr_Test);
1069 if( defined $num ) {
1070 unless( $Have_Plan ) {
1071 require Carp;
1072 Carp::croak("Can't change the current test number without a plan!");
1073 }
1074
1075 $Curr_Test = $num;
1076 if( $num > @Test_Results ) {
1077 my $start = @Test_Results ? $#Test_Results + 1 : 0;
1078 for ($start..$num-1) {
1079 my %result;
1080 share(%result);
1081 %result = ( ok => 1,
1082 actual_ok => undef,
1083 reason => 'incrementing test number',
1084 type => 'unknown',
1085 name => undef
1086 );
1087 $Test_Results[$_] = \%result;
1088 }
1089 }
1090 }
1091 return $Curr_Test;
1092 }
1093
1094
1095 =item B<summary>
1096
1097 my @tests = $Test->summary;
1098
1099 A simple summary of the tests so far. True for pass, false for fail.
1100 This is a logical pass/fail, so todos are passes.
1101
1102 Of course, test #1 is $tests[0], etc...
1103
1104 =cut
1105
1106 sub summary {
1107 my($self) = shift;
1108
1109 return map { $_->{'ok'} } @Test_Results;
1110 }
1111
1112 =item B<details>
1113
1114 my @tests = $Test->details;
1115
1116 Like summary(), but with a lot more detail.
1117
1118 $tests[$test_num - 1] =
1119 { 'ok' => is the test considered a pass?
1120 actual_ok => did it literally say 'ok'?
1121 name => name of the test (if any)
1122 type => type of test (if any, see below).
1123 reason => reason for the above (if any)
1124 };
1125
1126 'ok' is true if Test::Harness will consider the test to be a pass.
1127
1128 'actual_ok' is a reflection of whether or not the test literally
1129 printed 'ok' or 'not ok'. This is for examining the result of 'todo'
1130 tests.
1131
1132 'name' is the name of the test.
1133
1134 'type' indicates if it was a special test. Normal tests have a type
1135 of ''. Type can be one of the following:
1136
1137 skip see skip()
1138 todo see todo()
1139 todo_skip see todo_skip()
1140 unknown see below
1141
1142 Sometimes the Test::Builder test counter is incremented without it
1143 printing any test output, for example, when current_test() is changed.
1144 In these cases, Test::Builder doesn't know the result of the test, so
1145 it's type is 'unkown'. These details for these tests are filled in.
1146 They are considered ok, but the name and actual_ok is left undef.
1147
1148 For example "not ok 23 - hole count # TODO insufficient donuts" would
1149 result in this structure:
1150
1151 $tests[22] = # 23 - 1, since arrays start from 0.
1152 { ok => 1, # logically, the test passed since it's todo
1153 actual_ok => 0, # in absolute terms, it failed
1154 name => 'hole count',
1155 type => 'todo',
1156 reason => 'insufficient donuts'
1157 };
1158
1159 =cut
1160
1161 sub details {
1162 return @Test_Results;
1163 }
1164
1165 =item B<todo>
1166
1167 my $todo_reason = $Test->todo;
1168 my $todo_reason = $Test->todo($pack);
1169
1170 todo() looks for a $TODO variable in your tests. If set, all tests
1171 will be considered 'todo' (see Test::More and Test::Harness for
1172 details). Returns the reason (ie. the value of $TODO) if running as
1173 todo tests, false otherwise.
1174
1175 todo() is pretty part about finding the right package to look for
1176 $TODO in. It uses the exported_to() package to find it. If that's
1177 not set, it's pretty good at guessing the right package to look at.
1178
1179 Sometimes there is some confusion about where todo() should be looking
1180 for the $TODO variable. If you want to be sure, tell it explicitly
1181 what $pack to use.
1182
1183 =cut
1184
1185 sub todo {
1186 my($self, $pack) = @_;
1187
1188 $pack = $pack || $self->exported_to || $self->caller(1);
1189
1190 no strict 'refs';
1191 return defined ${$pack.'::TODO'} ? ${$pack.'::TODO'}
1192 : 0;
1193 }
1194
1195 =item B<caller>
1196
1197 my $package = $Test->caller;
1198 my($pack, $file, $line) = $Test->caller;
1199 my($pack, $file, $line) = $Test->caller($height);
1200
1201 Like the normal caller(), except it reports according to your level().
1202
1203 =cut
1204
1205 sub caller {
1206 my($self, $height) = @_;
1207 $height ||= 0;
1208
1209 my @caller = CORE::caller($self->level + $height + 1);
1210 return wantarray ? @caller : $caller[0];
1211 }
1212
1213 =back
1214
1215 =cut
1216
1217 =begin _private
1218
1219 =over 4
1220
1221 =item B<_sanity_check>
1222
1223 _sanity_check();
1224
1225 Runs a bunch of end of test sanity checks to make sure reality came
1226 through ok. If anything is wrong it will die with a fairly friendly
1227 error message.
1228
1229 =cut
1230
1231 #'#
1232 sub _sanity_check {
1233 _whoa($Curr_Test < 0, 'Says here you ran a negative number of tests!');
1234 _whoa(!$Have_Plan and $Curr_Test,
1235 'Somehow your tests ran without a plan!');
1236 _whoa($Curr_Test != @Test_Results,
1237 'Somehow you got a different number of results than tests ran!');
1238 }
1239
1240 =item B<_whoa>
1241
1242 _whoa($check, $description);
1243
1244 A sanity check, similar to assert(). If the $check is true, something
1245 has gone horribly wrong. It will die with the given $description and
1246 a note to contact the author.
1247
1248 =cut
1249
1250 sub _whoa {
1251 my($check, $desc) = @_;
1252 if( $check ) {
1253 die <<WHOA;
1254 WHOA! $desc
1255 This should never happen! Please contact the author immediately!
1256 WHOA
1257 }
1258 }
1259
1260 =item B<_my_exit>
1261
1262 _my_exit($exit_num);
1263
1264 Perl seems to have some trouble with exiting inside an END block. 5.005_03
1265 and 5.6.1 both seem to do odd things. Instead, this function edits $?
1266 directly. It should ONLY be called from inside an END block. It
1267 doesn't actually exit, that's your job.
1268
1269 =cut
1270
1271 sub _my_exit {
1272 $? = $_[0];
1273
1274 return 1;
1275 }
1276
1277
1278 =back
1279
1280 =end _private
1281
1282 =cut
1283
1284 $SIG{__DIE__} = sub {
1285 # We don't want to muck with death in an eval, but $^S isn't
1286 # totally reliable. 5.005_03 and 5.6.1 both do the wrong thing
1287 # with it. Instead, we use caller. This also means it runs under
1288 # 5.004!
1289 my $in_eval = 0;
1290 for( my $stack = 1; my $sub = (CORE::caller($stack))[3]; $stack++ ) {
1291 $in_eval = 1 if $sub =~ /^\(eval\)/;
1292 }
1293 $Test_Died = 1 unless $in_eval;
1294 };
1295
1296 sub _ending {
1297 my $self = shift;
1298
1299 _sanity_check();
1300
1301 # Don't bother with an ending if this is a forked copy. Only the parent
1302 # should do the ending.
1303 do{ _my_exit($?) && return } if $Original_Pid != $$;
1304
1305 # Bailout if plan() was never called. This is so
1306 # "require Test::Simple" doesn't puke.
1307 do{ _my_exit(0) && return } if !$Have_Plan && !$Test_Died;
1308
1309 # Figure out if we passed or failed and print helpful messages.
1310 if( @Test_Results ) {
1311 # The plan? We have no plan.
1312 if( $No_Plan ) {
1313 $self->_print("1..$Curr_Test\n") unless $self->no_header;
1314 $Expected_Tests = $Curr_Test;
1315 }
1316
1317 # 5.8.0 threads bug. Shared arrays will not be auto-extended
1318 # by a slice. Worse, we have to fill in every entry else
1319 # we'll get an "Invalid value for shared scalar" error
1320 for my $idx ($#Test_Results..$Expected_Tests-1) {
1321 my %empty_result = ();
1322 share(%empty_result);
1323 $Test_Results[$idx] = \%empty_result
1324 unless defined $Test_Results[$idx];
1325 }
1326
1327 my $num_failed = grep !$_->{'ok'}, @Test_Results[0..$Expected_Tests-1];
1328 $num_failed += abs($Expected_Tests - @Test_Results);
1329
1330 if( $Curr_Test < $Expected_Tests ) {
1331 $self->diag(<<"FAIL");
1332 Looks like you planned $Expected_Tests tests but only ran $Curr_Test.
1333 FAIL
1334 }
1335 elsif( $Curr_Test > $Expected_Tests ) {
1336 my $num_extra = $Curr_Test - $Expected_Tests;
1337 $self->diag(<<"FAIL");
1338 Looks like you planned $Expected_Tests tests but ran $num_extra extra.
1339 FAIL
1340 }
1341 elsif ( $num_failed ) {
1342 $self->diag(<<"FAIL");
1343 Looks like you failed $num_failed tests of $Expected_Tests.
1344 FAIL
1345 }
1346
1347 if( $Test_Died ) {
1348 $self->diag(<<"FAIL");
1349 Looks like your test died just after $Curr_Test.
1350 FAIL
1351
1352 _my_exit( 255 ) && return;
1353 }
1354
1355 _my_exit( $num_failed <= 254 ? $num_failed : 254 ) && return;
1356 }
1357 elsif ( $Skip_All ) {
1358 _my_exit( 0 ) && return;
1359 }
1360 elsif ( $Test_Died ) {
1361 $self->diag(<<'FAIL');
1362 Looks like your test died before it could output anything.
1363 FAIL
1364 }
1365 else {
1366 $self->diag("No tests run!\n");
1367 _my_exit( 255 ) && return;
1368 }
1369 }
1370
1371 END {
1372 $Test->_ending if defined $Test and !$Test->no_ending;
1373 }
1374
1375 =head1 THREADS
1376
1377 In perl 5.8.0 and later, Test::Builder is thread-safe. The test
1378 number is shared amongst all threads. This means if one thread sets
1379 the test number using current_test() they will all be effected.
1380
1381 =head1 EXAMPLES
1382
1383 CPAN can provide the best examples. Test::Simple, Test::More,
1384 Test::Exception and Test::Differences all use Test::Builder.
1385
1386 =head1 SEE ALSO
1387
1388 Test::Simple, Test::More, Test::Harness
1389
1390 =head1 AUTHORS
1391
1392 Original code by chromatic, maintained by Michael G Schwern
1393 E<lt>schwern@pobox.comE<gt>
1394
1395 =head1 COPYRIGHT
1396
1397 Copyright 2002 by chromatic E<lt>chromatic@wgz.orgE<gt>,
1398 Michael G Schwern E<lt>schwern@pobox.comE<gt>.
1399
1400 This program is free software; you can redistribute it and/or
1401 modify it under the same terms as Perl itself.
1402
1403 See F<http://www.perl.com/perl/misc/Artistic.html>
1404
1405 =cut
1406
1407 1;
+0
-1248
t/Test/More.pm less more
0 package Test::More;
1
2 use 5.004;
3
4 use strict;
5 use Test::Builder;
6
7
8 # Can't use Carp because it might cause use_ok() to accidentally succeed
9 # even though the module being used forgot to use Carp. Yes, this
10 # actually happened.
11 sub _carp {
12 my($file, $line) = (caller(1))[1,2];
13 warn @_, " at $file line $line\n";
14 }
15
16
17
18 require Exporter;
19 use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS $TODO);
20 $VERSION = '0.47';
21 @ISA = qw(Exporter);
22 @EXPORT = qw(ok use_ok require_ok
23 is isnt like unlike is_deeply
24 cmp_ok
25 skip todo todo_skip
26 pass fail
27 eq_array eq_hash eq_set
28 $TODO
29 plan
30 can_ok isa_ok
31 diag
32 );
33
34 my $Test = Test::Builder->new;
35
36
37 # 5.004's Exporter doesn't have export_to_level.
38 sub _export_to_level
39 {
40 my $pkg = shift;
41 my $level = shift;
42 (undef) = shift; # redundant arg
43 my $callpkg = caller($level);
44 $pkg->export($callpkg, @_);
45 }
46
47
48 =head1 NAME
49
50 Test::More - yet another framework for writing test scripts
51
52 =head1 SYNOPSIS
53
54 use Test::More tests => $Num_Tests;
55 # or
56 use Test::More qw(no_plan);
57 # or
58 use Test::More skip_all => $reason;
59
60 BEGIN { use_ok( 'Some::Module' ); }
61 require_ok( 'Some::Module' );
62
63 # Various ways to say "ok"
64 ok($this eq $that, $test_name);
65
66 is ($this, $that, $test_name);
67 isnt($this, $that, $test_name);
68
69 # Rather than print STDERR "# here's what went wrong\n"
70 diag("here's what went wrong");
71
72 like ($this, qr/that/, $test_name);
73 unlike($this, qr/that/, $test_name);
74
75 cmp_ok($this, '==', $that, $test_name);
76
77 is_deeply($complex_structure1, $complex_structure2, $test_name);
78
79 SKIP: {
80 skip $why, $how_many unless $have_some_feature;
81
82 ok( foo(), $test_name );
83 is( foo(42), 23, $test_name );
84 };
85
86 TODO: {
87 local $TODO = $why;
88
89 ok( foo(), $test_name );
90 is( foo(42), 23, $test_name );
91 };
92
93 can_ok($module, @methods);
94 isa_ok($object, $class);
95
96 pass($test_name);
97 fail($test_name);
98
99 # Utility comparison functions.
100 eq_array(\@this, \@that);
101 eq_hash(\%this, \%that);
102 eq_set(\@this, \@that);
103
104 # UNIMPLEMENTED!!!
105 my @status = Test::More::status;
106
107 # UNIMPLEMENTED!!!
108 BAIL_OUT($why);
109
110
111 =head1 DESCRIPTION
112
113 B<STOP!> If you're just getting started writing tests, have a look at
114 Test::Simple first. This is a drop in replacement for Test::Simple
115 which you can switch to once you get the hang of basic testing.
116
117 The purpose of this module is to provide a wide range of testing
118 utilities. Various ways to say "ok" with better diagnostics,
119 facilities to skip tests, test future features and compare complicated
120 data structures. While you can do almost anything with a simple
121 C<ok()> function, it doesn't provide good diagnostic output.
122
123
124 =head2 I love it when a plan comes together
125
126 Before anything else, you need a testing plan. This basically declares
127 how many tests your script is going to run to protect against premature
128 failure.
129
130 The preferred way to do this is to declare a plan when you C<use Test::More>.
131
132 use Test::More tests => $Num_Tests;
133
134 There are rare cases when you will not know beforehand how many tests
135 your script is going to run. In this case, you can declare that you
136 have no plan. (Try to avoid using this as it weakens your test.)
137
138 use Test::More qw(no_plan);
139
140 In some cases, you'll want to completely skip an entire testing script.
141
142 use Test::More skip_all => $skip_reason;
143
144 Your script will declare a skip with the reason why you skipped and
145 exit immediately with a zero (success). See L<Test::Harness> for
146 details.
147
148 If you want to control what functions Test::More will export, you
149 have to use the 'import' option. For example, to import everything
150 but 'fail', you'd do:
151
152 use Test::More tests => 23, import => ['!fail'];
153
154 Alternatively, you can use the plan() function. Useful for when you
155 have to calculate the number of tests.
156
157 use Test::More;
158 plan tests => keys %Stuff * 3;
159
160 or for deciding between running the tests at all:
161
162 use Test::More;
163 if( $^O eq 'MacOS' ) {
164 plan skip_all => 'Test irrelevant on MacOS';
165 }
166 else {
167 plan tests => 42;
168 }
169
170 =cut
171
172 sub plan {
173 my(@plan) = @_;
174
175 my $caller = caller;
176
177 $Test->exported_to($caller);
178
179 my @imports = ();
180 foreach my $idx (0..$#plan) {
181 if( $plan[$idx] eq 'import' ) {
182 my($tag, $imports) = splice @plan, $idx, 2;
183 @imports = @$imports;
184 last;
185 }
186 }
187
188 $Test->plan(@plan);
189
190 __PACKAGE__->_export_to_level(1, __PACKAGE__, @imports);
191 }
192
193 sub import {
194 my($class) = shift;
195 goto &plan;
196 }
197
198
199 =head2 Test names
200
201 By convention, each test is assigned a number in order. This is
202 largely done automatically for you. However, it's often very useful to
203 assign a name to each test. Which would you rather see:
204
205 ok 4
206 not ok 5
207 ok 6
208
209 or
210
211 ok 4 - basic multi-variable
212 not ok 5 - simple exponential
213 ok 6 - force == mass * acceleration
214
215 The later gives you some idea of what failed. It also makes it easier
216 to find the test in your script, simply search for "simple
217 exponential".
218
219 All test functions take a name argument. It's optional, but highly
220 suggested that you use it.
221
222
223 =head2 I'm ok, you're not ok.
224
225 The basic purpose of this module is to print out either "ok #" or "not
226 ok #" depending on if a given test succeeded or failed. Everything
227 else is just gravy.
228
229 All of the following print "ok" or "not ok" depending on if the test
230 succeeded or failed. They all also return true or false,
231 respectively.
232
233 =over 4
234
235 =item B<ok>
236
237 ok($this eq $that, $test_name);
238
239 This simply evaluates any expression (C<$this eq $that> is just a
240 simple example) and uses that to determine if the test succeeded or
241 failed. A true expression passes, a false one fails. Very simple.
242
243 For example:
244
245 ok( $exp{9} == 81, 'simple exponential' );
246 ok( Film->can('db_Main'), 'set_db()' );
247 ok( $p->tests == 4, 'saw tests' );
248 ok( !grep !defined $_, @items, 'items populated' );
249
250 (Mnemonic: "This is ok.")
251
252 $test_name is a very short description of the test that will be printed
253 out. It makes it very easy to find a test in your script when it fails
254 and gives others an idea of your intentions. $test_name is optional,
255 but we B<very> strongly encourage its use.
256
257 Should an ok() fail, it will produce some diagnostics:
258
259 not ok 18 - sufficient mucus
260 # Failed test 18 (foo.t at line 42)
261
262 This is actually Test::Simple's ok() routine.
263
264 =cut
265
266 sub ok ($;$) {
267 my($test, $name) = @_;
268 $Test->ok($test, $name);
269 }
270
271 =item B<is>
272
273 =item B<isnt>
274
275 is ( $this, $that, $test_name );
276 isnt( $this, $that, $test_name );
277
278 Similar to ok(), is() and isnt() compare their two arguments
279 with C<eq> and C<ne> respectively and use the result of that to
280 determine if the test succeeded or failed. So these:
281
282 # Is the ultimate answer 42?
283 is( ultimate_answer(), 42, "Meaning of Life" );
284
285 # $foo isn't empty
286 isnt( $foo, '', "Got some foo" );
287
288 are similar to these:
289
290 ok( ultimate_answer() eq 42, "Meaning of Life" );
291 ok( $foo ne '', "Got some foo" );
292
293 (Mnemonic: "This is that." "This isn't that.")
294
295 So why use these? They produce better diagnostics on failure. ok()
296 cannot know what you are testing for (beyond the name), but is() and
297 isnt() know what the test was and why it failed. For example this
298 test:
299
300 my $foo = 'waffle'; my $bar = 'yarblokos';
301 is( $foo, $bar, 'Is foo the same as bar?' );
302
303 Will produce something like this:
304
305 not ok 17 - Is foo the same as bar?
306 # Failed test (foo.t at line 139)
307 # got: 'waffle'
308 # expected: 'yarblokos'
309
310 So you can figure out what went wrong without rerunning the test.
311
312 You are encouraged to use is() and isnt() over ok() where possible,
313 however do not be tempted to use them to find out if something is
314 true or false!
315
316 # XXX BAD! $pope->isa('Catholic') eq 1
317 is( $pope->isa('Catholic'), 1, 'Is the Pope Catholic?' );
318
319 This does not check if C<$pope->isa('Catholic')> is true, it checks if
320 it returns 1. Very different. Similar caveats exist for false and 0.
321 In these cases, use ok().
322
323 ok( $pope->isa('Catholic') ), 'Is the Pope Catholic?' );
324
325 For those grammatical pedants out there, there's an C<isn't()>
326 function which is an alias of isnt().
327
328 =cut
329
330 sub is ($$;$) {
331 $Test->is_eq(@_);
332 }
333
334 sub isnt ($$;$) {
335 $Test->isnt_eq(@_);
336 }
337
338 *isn't = \&isnt;
339
340
341 =item B<like>
342
343 like( $this, qr/that/, $test_name );
344
345 Similar to ok(), like() matches $this against the regex C<qr/that/>.
346
347 So this:
348
349 like($this, qr/that/, 'this is like that');
350
351 is similar to:
352
353 ok( $this =~ /that/, 'this is like that');
354
355 (Mnemonic "This is like that".)
356
357 The second argument is a regular expression. It may be given as a
358 regex reference (i.e. C<qr//>) or (for better compatibility with older
359 perls) as a string that looks like a regex (alternative delimiters are
360 currently not supported):
361
362 like( $this, '/that/', 'this is like that' );
363
364 Regex options may be placed on the end (C<'/that/i'>).
365
366 Its advantages over ok() are similar to that of is() and isnt(). Better
367 diagnostics on failure.
368
369 =cut
370
371 sub like ($$;$) {
372 $Test->like(@_);
373 }
374
375
376 =item B<unlike>
377
378 unlike( $this, qr/that/, $test_name );
379
380 Works exactly as like(), only it checks if $this B<does not> match the
381 given pattern.
382
383 =cut
384
385 sub unlike {
386 $Test->unlike(@_);
387 }
388
389
390 =item B<cmp_ok>
391
392 cmp_ok( $this, $op, $that, $test_name );
393
394 Halfway between ok() and is() lies cmp_ok(). This allows you to
395 compare two arguments using any binary perl operator.
396
397 # ok( $this eq $that );
398 cmp_ok( $this, 'eq', $that, 'this eq that' );
399
400 # ok( $this == $that );
401 cmp_ok( $this, '==', $that, 'this == that' );
402
403 # ok( $this && $that );
404 cmp_ok( $this, '&&', $that, 'this || that' );
405 ...etc...
406
407 Its advantage over ok() is when the test fails you'll know what $this
408 and $that were:
409
410 not ok 1
411 # Failed test (foo.t at line 12)
412 # '23'
413 # &&
414 # undef
415
416 It's also useful in those cases where you are comparing numbers and
417 is()'s use of C<eq> will interfere:
418
419 cmp_ok( $big_hairy_number, '==', $another_big_hairy_number );
420
421 =cut
422
423 sub cmp_ok($$$;$) {
424 $Test->cmp_ok(@_);
425 }
426
427
428 =item B<can_ok>
429
430 can_ok($module, @methods);
431 can_ok($object, @methods);
432
433 Checks to make sure the $module or $object can do these @methods
434 (works with functions, too).
435
436 can_ok('Foo', qw(this that whatever));
437
438 is almost exactly like saying:
439
440 ok( Foo->can('this') &&
441 Foo->can('that') &&
442 Foo->can('whatever')
443 );
444
445 only without all the typing and with a better interface. Handy for
446 quickly testing an interface.
447
448 No matter how many @methods you check, a single can_ok() call counts
449 as one test. If you desire otherwise, use:
450
451 foreach my $meth (@methods) {
452 can_ok('Foo', $meth);
453 }
454
455 =cut
456
457 sub can_ok ($@) {
458 my($proto, @methods) = @_;
459 my $class = ref $proto || $proto;
460
461 unless( @methods ) {
462 my $ok = $Test->ok( 0, "$class->can(...)" );
463 $Test->diag(' can_ok() called with no methods');
464 return $ok;
465 }
466
467 my @nok = ();
468 foreach my $method (@methods) {
469 local($!, $@); # don't interfere with caller's $@
470 # eval sometimes resets $!
471 eval { $proto->can($method) } || push @nok, $method;
472 }
473
474 my $name;
475 $name = @methods == 1 ? "$class->can('$methods[0]')"
476 : "$class->can(...)";
477
478 my $ok = $Test->ok( !@nok, $name );
479
480 $Test->diag(map " $class->can('$_') failed\n", @nok);
481
482 return $ok;
483 }
484
485 =item B<isa_ok>
486
487 isa_ok($object, $class, $object_name);
488 isa_ok($ref, $type, $ref_name);
489
490 Checks to see if the given $object->isa($class). Also checks to make
491 sure the object was defined in the first place. Handy for this sort
492 of thing:
493
494 my $obj = Some::Module->new;
495 isa_ok( $obj, 'Some::Module' );
496
497 where you'd otherwise have to write
498
499 my $obj = Some::Module->new;
500 ok( defined $obj && $obj->isa('Some::Module') );
501
502 to safeguard against your test script blowing up.
503
504 It works on references, too:
505
506 isa_ok( $array_ref, 'ARRAY' );
507
508 The diagnostics of this test normally just refer to 'the object'. If
509 you'd like them to be more specific, you can supply an $object_name
510 (for example 'Test customer').
511
512 =cut
513
514 sub isa_ok ($$;$) {
515 my($object, $class, $obj_name) = @_;
516
517 my $diag;
518 $obj_name = 'The object' unless defined $obj_name;
519 my $name = "$obj_name isa $class";
520 if( !defined $object ) {
521 $diag = "$obj_name isn't defined";
522 }
523 elsif( !ref $object ) {
524 $diag = "$obj_name isn't a reference";
525 }
526 else {
527 # We can't use UNIVERSAL::isa because we want to honor isa() overrides
528 local($@, $!); # eval sometimes resets $!
529 my $rslt = eval { $object->isa($class) };
530 if( $@ ) {
531 if( $@ =~ /^Can't call method "isa" on unblessed reference/ ) {
532 if( !UNIVERSAL::isa($object, $class) ) {
533 my $ref = ref $object;
534 $diag = "$obj_name isn't a '$class' it's a '$ref'";
535 }
536 } else {
537 die <<WHOA;
538 WHOA! I tried to call ->isa on your object and got some weird error.
539 This should never happen. Please contact the author immediately.
540 Here's the error.
541 $@
542 WHOA
543 }
544 }
545 elsif( !$rslt ) {
546 my $ref = ref $object;
547 $diag = "$obj_name isn't a '$class' it's a '$ref'";
548 }
549 }
550
551
552
553 my $ok;
554 if( $diag ) {
555 $ok = $Test->ok( 0, $name );
556 $Test->diag(" $diag\n");
557 }
558 else {
559 $ok = $Test->ok( 1, $name );
560 }
561
562 return $ok;
563 }
564
565
566 =item B<pass>
567
568 =item B<fail>
569
570 pass($test_name);
571 fail($test_name);
572
573 Sometimes you just want to say that the tests have passed. Usually
574 the case is you've got some complicated condition that is difficult to
575 wedge into an ok(). In this case, you can simply use pass() (to
576 declare the test ok) or fail (for not ok). They are synonyms for
577 ok(1) and ok(0).
578
579 Use these very, very, very sparingly.
580
581 =cut
582
583 sub pass (;$) {
584 $Test->ok(1, @_);
585 }
586
587 sub fail (;$) {
588 $Test->ok(0, @_);
589 }
590
591 =back
592
593 =head2 Diagnostics
594
595 If you pick the right test function, you'll usually get a good idea of
596 what went wrong when it failed. But sometimes it doesn't work out
597 that way. So here we have ways for you to write your own diagnostic
598 messages which are safer than just C<print STDERR>.
599
600 =over 4
601
602 =item B<diag>
603
604 diag(@diagnostic_message);
605
606 Prints a diagnostic message which is guaranteed not to interfere with
607 test output. Handy for this sort of thing:
608
609 ok( grep(/foo/, @users), "There's a foo user" ) or
610 diag("Since there's no foo, check that /etc/bar is set up right");
611
612 which would produce:
613
614 not ok 42 - There's a foo user
615 # Failed test (foo.t at line 52)
616 # Since there's no foo, check that /etc/bar is set up right.
617
618 You might remember C<ok() or diag()> with the mnemonic C<open() or
619 die()>.
620
621 B<NOTE> The exact formatting of the diagnostic output is still
622 changing, but it is guaranteed that whatever you throw at it it won't
623 interfere with the test.
624
625 =cut
626
627 sub diag {
628 $Test->diag(@_);
629 }
630
631
632 =back
633
634 =head2 Module tests
635
636 You usually want to test if the module you're testing loads ok, rather
637 than just vomiting if its load fails. For such purposes we have
638 C<use_ok> and C<require_ok>.
639
640 =over 4
641
642 =item B<use_ok>
643
644 BEGIN { use_ok($module); }
645 BEGIN { use_ok($module, @imports); }
646
647 These simply use the given $module and test to make sure the load
648 happened ok. It's recommended that you run use_ok() inside a BEGIN
649 block so its functions are exported at compile-time and prototypes are
650 properly honored.
651
652 If @imports are given, they are passed through to the use. So this:
653
654 BEGIN { use_ok('Some::Module', qw(foo bar)) }
655
656 is like doing this:
657
658 use Some::Module qw(foo bar);
659
660 don't try to do this:
661
662 BEGIN {
663 use_ok('Some::Module');
664
665 ...some code that depends on the use...
666 ...happening at compile time...
667 }
668
669 instead, you want:
670
671 BEGIN { use_ok('Some::Module') }
672 BEGIN { ...some code that depends on the use... }
673
674
675 =cut
676
677 sub use_ok ($;@) {
678 my($module, @imports) = @_;
679 @imports = () unless @imports;
680
681 my $pack = caller;
682
683 local($@,$!); # eval sometimes interferes with $!
684 eval <<USE;
685 package $pack;
686 require $module;
687 '$module'->import(\@imports);
688 USE
689
690 my $ok = $Test->ok( !$@, "use $module;" );
691
692 unless( $ok ) {
693 chomp $@;
694 $Test->diag(<<DIAGNOSTIC);
695 Tried to use '$module'.
696 Error: $@
697 DIAGNOSTIC
698
699 }
700
701 return $ok;
702 }
703
704 =item B<require_ok>
705
706 require_ok($module);
707
708 Like use_ok(), except it requires the $module.
709
710 =cut
711
712 sub require_ok ($) {
713 my($module) = shift;
714
715 my $pack = caller;
716
717 local($!, $@); # eval sometimes interferes with $!
718 eval <<REQUIRE;
719 package $pack;
720 require $module;
721 REQUIRE
722
723 my $ok = $Test->ok( !$@, "require $module;" );
724
725 unless( $ok ) {
726 chomp $@;
727 $Test->diag(<<DIAGNOSTIC);
728 Tried to require '$module'.
729 Error: $@
730 DIAGNOSTIC
731
732 }
733
734 return $ok;
735 }
736
737 =back
738
739 =head2 Conditional tests
740
741 Sometimes running a test under certain conditions will cause the
742 test script to die. A certain function or method isn't implemented
743 (such as fork() on MacOS), some resource isn't available (like a
744 net connection) or a module isn't available. In these cases it's
745 necessary to skip tests, or declare that they are supposed to fail
746 but will work in the future (a todo test).
747
748 For more details on the mechanics of skip and todo tests see
749 L<Test::Harness>.
750
751 The way Test::More handles this is with a named block. Basically, a
752 block of tests which can be skipped over or made todo. It's best if I
753 just show you...
754
755 =over 4
756
757 =item B<SKIP: BLOCK>
758
759 SKIP: {
760 skip $why, $how_many if $condition;
761
762 ...normal testing code goes here...
763 }
764
765 This declares a block of tests that might be skipped, $how_many tests
766 there are, $why and under what $condition to skip them. An example is
767 the easiest way to illustrate:
768
769 SKIP: {
770 eval { require HTML::Lint };
771
772 skip "HTML::Lint not installed", 2 if $@;
773
774 my $lint = new HTML::Lint;
775 isa_ok( $lint, "HTML::Lint" );
776
777 $lint->parse( $html );
778 is( $lint->errors, 0, "No errors found in HTML" );
779 }
780
781 If the user does not have HTML::Lint installed, the whole block of
782 code I<won't be run at all>. Test::More will output special ok's
783 which Test::Harness interprets as skipped, but passing, tests.
784 It's important that $how_many accurately reflects the number of tests
785 in the SKIP block so the # of tests run will match up with your plan.
786
787 It's perfectly safe to nest SKIP blocks. Each SKIP block must have
788 the label C<SKIP>, or Test::More can't work its magic.
789
790 You don't skip tests which are failing because there's a bug in your
791 program, or for which you don't yet have code written. For that you
792 use TODO. Read on.
793
794 =cut
795
796 #'#
797 sub skip {
798 my($why, $how_many) = @_;
799
800 unless( defined $how_many ) {
801 # $how_many can only be avoided when no_plan is in use.
802 _carp "skip() needs to know \$how_many tests are in the block"
803 unless $Test::Builder::No_Plan;
804 $how_many = 1;
805 }
806
807 for( 1..$how_many ) {
808 $Test->skip($why);
809 }
810
811 local $^W = 0;
812 last SKIP;
813 }
814
815
816 =item B<TODO: BLOCK>
817
818 TODO: {
819 local $TODO = $why if $condition;
820
821 ...normal testing code goes here...
822 }
823
824 Declares a block of tests you expect to fail and $why. Perhaps it's
825 because you haven't fixed a bug or haven't finished a new feature:
826
827 TODO: {
828 local $TODO = "URI::Geller not finished";
829
830 my $card = "Eight of clubs";
831 is( URI::Geller->your_card, $card, 'Is THIS your card?' );
832
833 my $spoon;
834 URI::Geller->bend_spoon;
835 is( $spoon, 'bent', "Spoon bending, that's original" );
836 }
837
838 With a todo block, the tests inside are expected to fail. Test::More
839 will run the tests normally, but print out special flags indicating
840 they are "todo". Test::Harness will interpret failures as being ok.
841 Should anything succeed, it will report it as an unexpected success.
842 You then know the thing you had todo is done and can remove the
843 TODO flag.
844
845 The nice part about todo tests, as opposed to simply commenting out a
846 block of tests, is it's like having a programmatic todo list. You know
847 how much work is left to be done, you're aware of what bugs there are,
848 and you'll know immediately when they're fixed.
849
850 Once a todo test starts succeeding, simply move it outside the block.
851 When the block is empty, delete it.
852
853
854 =item B<todo_skip>
855
856 TODO: {
857 todo_skip $why, $how_many if $condition;
858
859 ...normal testing code...
860 }
861
862 With todo tests, it's best to have the tests actually run. That way
863 you'll know when they start passing. Sometimes this isn't possible.
864 Often a failing test will cause the whole program to die or hang, even
865 inside an C<eval BLOCK> with and using C<alarm>. In these extreme
866 cases you have no choice but to skip over the broken tests entirely.
867
868 The syntax and behavior is similar to a C<SKIP: BLOCK> except the
869 tests will be marked as failing but todo. Test::Harness will
870 interpret them as passing.
871
872 =cut
873
874 sub todo_skip {
875 my($why, $how_many) = @_;
876
877 unless( defined $how_many ) {
878 # $how_many can only be avoided when no_plan is in use.
879 _carp "todo_skip() needs to know \$how_many tests are in the block"
880 unless $Test::Builder::No_Plan;
881 $how_many = 1;
882 }
883
884 for( 1..$how_many ) {
885 $Test->todo_skip($why);
886 }
887
888 local $^W = 0;
889 last TODO;
890 }
891
892 =item When do I use SKIP vs. TODO?
893
894 B<If it's something the user might not be able to do>, use SKIP.
895 This includes optional modules that aren't installed, running under
896 an OS that doesn't have some feature (like fork() or symlinks), or maybe
897 you need an Internet connection and one isn't available.
898
899 B<If it's something the programmer hasn't done yet>, use TODO. This
900 is for any code you haven't written yet, or bugs you have yet to fix,
901 but want to put tests in your testing script (always a good idea).
902
903
904 =back
905
906 =head2 Comparison functions
907
908 Not everything is a simple eq check or regex. There are times you
909 need to see if two arrays are equivalent, for instance. For these
910 instances, Test::More provides a handful of useful functions.
911
912 B<NOTE> These are NOT well-tested on circular references. Nor am I
913 quite sure what will happen with filehandles.
914
915 =over 4
916
917 =item B<is_deeply>
918
919 is_deeply( $this, $that, $test_name );
920
921 Similar to is(), except that if $this and $that are hash or array
922 references, it does a deep comparison walking each data structure to
923 see if they are equivalent. If the two structures are different, it
924 will display the place where they start differing.
925
926 Barrie Slaymaker's Test::Differences module provides more in-depth
927 functionality along these lines, and it plays well with Test::More.
928
929 B<NOTE> Display of scalar refs is not quite 100%
930
931 =cut
932
933 use vars qw(@Data_Stack);
934 my $DNE = bless [], 'Does::Not::Exist';
935 sub is_deeply {
936 my($this, $that, $name) = @_;
937
938 my $ok;
939 if( !ref $this || !ref $that ) {
940 $ok = $Test->is_eq($this, $that, $name);
941 }
942 else {
943 local @Data_Stack = ();
944 if( _deep_check($this, $that) ) {
945 $ok = $Test->ok(1, $name);
946 }
947 else {
948 $ok = $Test->ok(0, $name);
949 $ok = $Test->diag(_format_stack(@Data_Stack));
950 }
951 }
952
953 return $ok;
954 }
955
956 sub _format_stack {
957 my(@Stack) = @_;
958
959 my $var = '$FOO';
960 my $did_arrow = 0;
961 foreach my $entry (@Stack) {
962 my $type = $entry->{type} || '';
963 my $idx = $entry->{'idx'};
964 if( $type eq 'HASH' ) {
965 $var .= "->" unless $did_arrow++;
966 $var .= "{$idx}";
967 }
968 elsif( $type eq 'ARRAY' ) {
969 $var .= "->" unless $did_arrow++;
970 $var .= "[$idx]";
971 }
972 elsif( $type eq 'REF' ) {
973 $var = "\${$var}";
974 }
975 }
976
977 my @vals = @{$Stack[-1]{vals}}[0,1];
978 my @vars = ();
979 ($vars[0] = $var) =~ s/\$FOO/ \$got/;
980 ($vars[1] = $var) =~ s/\$FOO/\$expected/;
981
982 my $out = "Structures begin differing at:\n";
983 foreach my $idx (0..$#vals) {
984 my $val = $vals[$idx];
985 $vals[$idx] = !defined $val ? 'undef' :
986 $val eq $DNE ? "Does not exist"
987 : "'$val'";
988 }
989
990 $out .= "$vars[0] = $vals[0]\n";
991 $out .= "$vars[1] = $vals[1]\n";
992
993 $out =~ s/^/ /msg;
994 return $out;
995 }
996
997
998 =item B<eq_array>
999
1000 eq_array(\@this, \@that);
1001
1002 Checks if two arrays are equivalent. This is a deep check, so
1003 multi-level structures are handled correctly.
1004
1005 =cut
1006
1007 #'#
1008 sub eq_array {
1009 my($a1, $a2) = @_;
1010 return 1 if $a1 eq $a2;
1011
1012 my $ok = 1;
1013 my $max = $#$a1 > $#$a2 ? $#$a1 : $#$a2;
1014 for (0..$max) {
1015 my $e1 = $_ > $#$a1 ? $DNE : $a1->[$_];
1016 my $e2 = $_ > $#$a2 ? $DNE : $a2->[$_];
1017
1018 push @Data_Stack, { type => 'ARRAY', idx => $_, vals => [$e1, $e2] };
1019 $ok = _deep_check($e1,$e2);
1020 pop @Data_Stack if $ok;
1021
1022 last unless $ok;
1023 }
1024 return $ok;
1025 }
1026
1027 sub _deep_check {
1028 my($e1, $e2) = @_;
1029 my $ok = 0;
1030
1031 my $eq;
1032 {
1033 # Quiet uninitialized value warnings when comparing undefs.
1034 local $^W = 0;
1035
1036 if( $e1 eq $e2 ) {
1037 $ok = 1;
1038 }
1039 else {
1040 if( UNIVERSAL::isa($e1, 'ARRAY') and
1041 UNIVERSAL::isa($e2, 'ARRAY') )
1042 {
1043 $ok = eq_array($e1, $e2);
1044 }
1045 elsif( UNIVERSAL::isa($e1, 'HASH') and
1046 UNIVERSAL::isa($e2, 'HASH') )
1047 {
1048 $ok = eq_hash($e1, $e2);
1049 }
1050 elsif( UNIVERSAL::isa($e1, 'REF') and
1051 UNIVERSAL::isa($e2, 'REF') )
1052 {
1053 push @Data_Stack, { type => 'REF', vals => [$e1, $e2] };
1054 $ok = _deep_check($$e1, $$e2);
1055 pop @Data_Stack if $ok;
1056 }
1057 elsif( UNIVERSAL::isa($e1, 'SCALAR') and
1058 UNIVERSAL::isa($e2, 'SCALAR') )
1059 {
1060 push @Data_Stack, { type => 'REF', vals => [$e1, $e2] };
1061 $ok = _deep_check($$e1, $$e2);
1062 }
1063 else {
1064 push @Data_Stack, { vals => [$e1, $e2] };
1065 $ok = 0;
1066 }
1067 }
1068 }
1069
1070 return $ok;
1071 }
1072
1073
1074 =item B<eq_hash>
1075
1076 eq_hash(\%this, \%that);
1077
1078 Determines if the two hashes contain the same keys and values. This
1079 is a deep check.
1080
1081 =cut
1082
1083 sub eq_hash {
1084 my($a1, $a2) = @_;
1085 return 1 if $a1 eq $a2;
1086
1087 my $ok = 1;
1088 my $bigger = keys %$a1 > keys %$a2 ? $a1 : $a2;
1089 foreach my $k (keys %$bigger) {
1090 my $e1 = exists $a1->{$k} ? $a1->{$k} : $DNE;
1091 my $e2 = exists $a2->{$k} ? $a2->{$k} : $DNE;
1092
1093 push @Data_Stack, { type => 'HASH', idx => $k, vals => [$e1, $e2] };
1094 $ok = _deep_check($e1, $e2);
1095 pop @Data_Stack if $ok;
1096
1097 last unless $ok;
1098 }
1099
1100 return $ok;
1101 }
1102
1103 =item B<eq_set>
1104
1105 eq_set(\@this, \@that);
1106
1107 Similar to eq_array(), except the order of the elements is B<not>
1108 important. This is a deep check, but the irrelevancy of order only
1109 applies to the top level.
1110
1111 B<NOTE> By historical accident, this is not a true set comparision.
1112 While the order of elements does not matter, duplicate elements do.
1113
1114 =cut
1115
1116 # We must make sure that references are treated neutrally. It really
1117 # doesn't matter how we sort them, as long as both arrays are sorted
1118 # with the same algorithm.
1119 sub _bogus_sort { local $^W = 0; ref $a ? 0 : $a cmp $b }
1120
1121 sub eq_set {
1122 my($a1, $a2) = @_;
1123 return 0 unless @$a1 == @$a2;
1124
1125 # There's faster ways to do this, but this is easiest.
1126 return eq_array( [sort _bogus_sort @$a1], [sort _bogus_sort @$a2] );
1127 }
1128
1129 =back
1130
1131
1132 =head2 Extending and Embedding Test::More
1133
1134 Sometimes the Test::More interface isn't quite enough. Fortunately,
1135 Test::More is built on top of Test::Builder which provides a single,
1136 unified backend for any test library to use. This means two test
1137 libraries which both use Test::Builder B<can be used together in the
1138 same program>.
1139
1140 If you simply want to do a little tweaking of how the tests behave,
1141 you can access the underlying Test::Builder object like so:
1142
1143 =over 4
1144
1145 =item B<builder>
1146
1147 my $test_builder = Test::More->builder;
1148
1149 Returns the Test::Builder object underlying Test::More for you to play
1150 with.
1151
1152 =cut
1153
1154 sub builder {
1155 return Test::Builder->new;
1156 }
1157
1158 =back
1159
1160
1161 =head1 NOTES
1162
1163 Test::More is B<explicitly> tested all the way back to perl 5.004.
1164
1165 Test::More is thread-safe for perl 5.8.0 and up.
1166
1167 =head1 BUGS and CAVEATS
1168
1169 =over 4
1170
1171 =item Making your own ok()
1172
1173 If you are trying to extend Test::More, don't. Use Test::Builder
1174 instead.
1175
1176 =item The eq_* family has some caveats.
1177
1178 =item Test::Harness upgrades
1179
1180 no_plan and todo depend on new Test::Harness features and fixes. If
1181 you're going to distribute tests that use no_plan or todo your
1182 end-users will have to upgrade Test::Harness to the latest one on
1183 CPAN. If you avoid no_plan and TODO tests, the stock Test::Harness
1184 will work fine.
1185
1186 If you simply depend on Test::More, it's own dependencies will cause a
1187 Test::Harness upgrade.
1188
1189 =back
1190
1191
1192 =head1 HISTORY
1193
1194 This is a case of convergent evolution with Joshua Pritikin's Test
1195 module. I was largely unaware of its existence when I'd first
1196 written my own ok() routines. This module exists because I can't
1197 figure out how to easily wedge test names into Test's interface (along
1198 with a few other problems).
1199
1200 The goal here is to have a testing utility that's simple to learn,
1201 quick to use and difficult to trip yourself up with while still
1202 providing more flexibility than the existing Test.pm. As such, the
1203 names of the most common routines are kept tiny, special cases and
1204 magic side-effects are kept to a minimum. WYSIWYG.
1205
1206
1207 =head1 SEE ALSO
1208
1209 L<Test::Simple> if all this confuses you and you just want to write
1210 some tests. You can upgrade to Test::More later (it's forward
1211 compatible).
1212
1213 L<Test::Differences> for more ways to test complex data structures.
1214 And it plays well with Test::More.
1215
1216 L<Test> is the old testing module. Its main benefit is that it has
1217 been distributed with Perl since 5.004_05.
1218
1219 L<Test::Harness> for details on how your test results are interpreted
1220 by Perl.
1221
1222 L<Test::Unit> describes a very featureful unit testing interface.
1223
1224 L<Test::Inline> shows the idea of embedded testing.
1225
1226 L<SelfTest> is another approach to embedded testing.
1227
1228
1229 =head1 AUTHORS
1230
1231 Michael G Schwern E<lt>schwern@pobox.comE<gt> with much inspiration
1232 from Joshua Pritikin's Test module and lots of help from Barrie
1233 Slaymaker, Tony Bowden, chromatic and the perl-qa gang.
1234
1235
1236 =head1 COPYRIGHT
1237
1238 Copyright 2001 by Michael G Schwern E<lt>schwern@pobox.comE<gt>.
1239
1240 This program is free software; you can redistribute it and/or
1241 modify it under the same terms as Perl itself.
1242
1243 See F<http://www.perl.com/perl/misc/Artistic.html>
1244
1245 =cut
1246
1247 1;
0 # Before `make install' is performed this script should be runnable with
1 # `make test'. After `make install' it should work as `perl test.pl'
0 #!perl -w
1 use strict;
2 use Test::More tests => 15;
23
3 ######################### We start with some black magic to print on failure.
4
5 # Change 1..1 below to 1..last_test_to_print .
6 # (It may become useful if the test is moved to ./t subdirectory.)
7
8 BEGIN { $| = 1; print "1..2\n"; }
9 END {print "not ok 1\n" unless $loaded;}
10 use Imager;
11 #use Data::Dumper;
12 $loaded = 1;
13 print "ok 1\n";
14
15 init_log("testout/t00basic.log",1);
16
17 #list_formats();
18
19 #%hsh=%Imager::formats;
20 #print Dumper(\%hsh);
21
22 i_has_format("jpeg") && print "# has jpeg\n";
23 i_has_format("png") && print "# has png\n";
24
25 print "ok 2\n";
26
27 malloc_state();
4 use_ok('Imager');
5 use_ok('Imager::Font');
6 use_ok('Imager::Color');
7 use_ok('Imager::Color::Float');
8 use_ok('Imager::Color::Table');
9 use_ok('Imager::Matrix2d');
10 use_ok('Imager::ExtUtils');
11 use_ok('Imager::Expr');
12 use_ok('Imager::Expr::Assem');
13 use_ok('Imager::Font::BBox');
14 use_ok('Imager::Font::Wrap');
15 use_ok('Imager::Fountain');
16 use_ok('Imager::Regops');
17 use_ok('Imager::Test');
18 use_ok('Imager::Transform');
22 # to make sure we get expected values
33
44 use strict;
5 use lib 't';
65 use Test::More tests=>196;
76
87 BEGIN { use_ok(Imager => qw(:handy :all)) }
424423 my @plin_colors2 = ( $green, $red, $blue, $red );
425424 is($im->setscanline('y'=>2, 'x'=>3, pixels=>\@plin_colors2), 4,
426425 "setscanline - arrayref");
427 is_deeply([ ([ 0,0,0,0 ]) x 3, (map [ $_->rgba ], @plin_colors2),
428 ([ 0,0,0,0 ]) x 3 ],
426
427 # using map instead of x here due to a bug in some versions of Test::More
428 # fixed in the latest Test::More
429 is_deeply([ ( map [ 0,0,0,0 ], 1..3), (map [ $_->rgba ], @plin_colors2),
430 ( map [ 0,0,0,0 ], 1..3) ],
429431 [ map [ $_->rgba ], $im->getscanline('y'=>2) ],
430432 "check write to middle of line");
431433
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 85;
43
54 BEGIN { use_ok(Imager=>qw(:all :handy)) }
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 81;
43
54 BEGIN { use_ok(Imager => qw(:all :handy)) }
6160 # basic OO tests
6261 my $ooimg = Imager->new(xsize=>200, ysize=>201, bits=>'double');
6362 ok($ooimg, "couldn't make double image");
64 ok($ooimg->bits eq 'double', "oo didn't give double image");
63 is($ooimg->bits, 'double', "oo didn't give double image");
6564
6665 # check that the image is copied correctly
6766 my $oocopy = $ooimg->copy;
00 #!perl -w
11 # some of this is tested in t01introvert.t too
22 use strict;
3 use lib 't';
4 use Test::More tests => 83;
3 use Test::More tests => 90;
54 BEGIN { use_ok("Imager"); }
65
76 sub isbin($$$);
109
1110 ok($img, "paletted image created");
1211
13 ok($img->type eq 'paletted', "got a paletted image");
12 is($img->type, 'paletted', "got a paletted image");
1413
1514 my $black = Imager::Color->new(0,0,0);
1615 my $red = Imager::Color->new(255,0,0);
7978
8079 # draw on the image, make sure it stays paletted when it should
8180 ok($img->box(color=>$red, filled=>1), "fill with red");
82 ok($img->type eq 'paletted', "paletted after fill");
81 is($img->type, 'paletted', "paletted after fill");
8382 ok($img->box(color=>$green, filled=>1, xmin=>10, ymin=>10,
8483 xmax=>40, ymax=>40), "green box");
85 ok($img->type eq 'paletted', 'still paletted after box');
84 is($img->type, 'paletted', 'still paletted after box');
8685 # an AA line will almost certainly convert the image to RGB, don't use
8786 # an AA line here
8887 ok($img->line(color=>$blue, x1=>10, y1=>10, x2=>40, y2=>40),
8988 "draw a line");
90 ok($img->type eq 'paletted', 'still paletted after line');
89 is($img->type, 'paletted', 'still paletted after line');
9190
9291 # draw with white - should convert to direct
9392 ok($img->box(color=>$white, filled=>1, xmin=>20, ymin=>20,
9493 xmax=>30, ymax=>30), "white box");
95 ok($img->type eq 'direct', "now it should be direct");
94 is($img->type, 'direct', "now it should be direct");
9695
9796 # various attempted to make a paletted image from our now direct image
9897 my $palimg = $img->to_paletted;
267266 ok($@, "croak on setscanline() with pv to invalid index");
268267 }
269268
269 {
270 print "# make_colors => mono\n";
271 # test mono make_colors
272 my $imrgb = Imager->new(xsize => 10, ysize => 10);
273 $imrgb->setpixel(x => 0, 'y' => 0, color => '#FFF');
274 $imrgb->setpixel(x => 1, 'y' => 0, color => '#FF0');
275 $imrgb->setpixel(x => 2, 'y' => 0, color => '#000');
276 my $mono = $imrgb->to_paletted(make_colors => 'mono',
277 translate => 'closest');
278 is($mono->type, 'paletted', "check we get right image type");
279 is($mono->colorcount, 2, "only 2 colors");
280 my @colors = $mono->getcolors;
281 iscolor($colors[0], $black, "check first entry");
282 iscolor($colors[1], $white, "check second entry");
283 my @pixels = $mono->getscanline(x => 0, 'y' => 0, width => 3, type=>'index');
284 is($pixels[0], 1, "check white pixel");
285 is($pixels[1], 1, "check yellow pixel");
286 is($pixels[2], 0, "check black pixel");
287 }
288
270289 sub iscolor {
271290 my ($c1, $c2, $msg) = @_;
272291
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 68;
43 # for SEEK_SET etc, Fcntl doesn't provide these in 5.005_03
54 use IO::Seekable;
108107 ok(Imager::i_writeppm_wiol($im, $IO8), "write to cb");
109108 # I originally compared this to $data, but that doesn't include the
110109 # Imager header
111 ok($work eq $data2, "write image match");
110 is($work, $data2, "write image match");
112111 ok($did_close, "did close");
113112
114113 # with a short buffer, no closer
117116 $pos = 0;
118117 $work = '';
119118 ok(Imager::i_writeppm_wiol($im, $IO9), "write to short cb");
120 ok($work eq $data2, "short write image match");
119 is($work, $data2, "short write image match");
121120
122121 {
123122 my $buf_data = "Test data";
33 # the file format
44
55 use strict;
6 use lib 't';
76 use Test::More tests => 32;
87 use Imager;
98
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Imager qw(:all);
43 use Test::More tests => 86;
54
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 32;
43 # Before `make install' is performed this script should be runnable with
54 # `make test'. After `make install' it should work as `perl test.pl'
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 23;
43 use Imager qw(:all);
54 init_log("testout/t103raw.log",1);
00 #!perl -w
11 use Imager ':all';
2 use lib 't';
3 use Test::More tests => 64;
2 use Test::More tests => 143;
43 use strict;
4 use Imager::Test qw(test_image_raw test_image_16 is_color3 is_color1 is_image);
55
66 init_log("testout/t104ppm.log",1);
77
99 my $blue = i_color_new(0,0,255,255);
1010 my $red = i_color_new(255,0,0,255);
1111
12 my $img = Imager::ImgRaw::new(150,150,3);
13
14 i_box_filled($img,70,25,130,125,$green);
15 i_box_filled($img,20,25,80,125,$blue);
16 i_arc($img,75,75,30,0,361,$red);
17 i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]);
12 my $img = test_image_raw();
1813
1914 my $fh = openimage(">testout/t104.ppm");
2015 my $IO = Imager::io_new_fd(fileno($fh));
6560 my $ooim = Imager->new;
6661 ok($ooim->read(file=>"testimg/simple.pbm"), "read simple pbm, via OO");
6762
68 check_gray(Imager::i_get_pixel($ooim->{IMG}, 0, 0), 255);
69 check_gray(Imager::i_get_pixel($ooim->{IMG}, 0, 1), 0);
70 check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 0), 0);
71 check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 1), 255);
63 check_gray(Imager::i_get_pixel($ooim->{IMG}, 0, 0), 0);
64 check_gray(Imager::i_get_pixel($ooim->{IMG}, 0, 1), 255);
65 check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 0), 255);
66 check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 1), 0);
67 is($ooim->type, 'paletted', "check pbm read as paletted");
68 is($ooim->tags(name=>'pnm_type'), 1, "check pnm_type tag");
7269
7370 {
7471 # https://rt.cpan.org/Ticket/Display.html?id=7465
8784
8885 # check the pixels
8986 ok(my ($white, $grey, $green) = $maxval->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels");
90 check_color($white, 255, 255, 255, "white pixel");
91 check_color($grey, 130, 130, 130, "grey pixel");
92 check_color($green, 125, 125, 0, "green pixel");
87 is_color3($white, 255, 255, 255, "white pixel");
88 is_color3($grey, 130, 130, 130, "grey pixel");
89 is_color3($green, 125, 125, 0, "green pixel");
90 is($maxval->tags(name=>'pnm_type'), 6, "check pnm_type tag on maxval");
9391
9492 # and do the same for ASCII images
9593 my $maxval_asc = Imager->new;
103101 is($maxval_asc->getchannels, 3, "channel count");
104102 is($maxval_asc->getwidth, 3, "width");
105103 is($maxval_asc->getheight, 1, "height");
104
105 is($maxval->tags(name=>'pnm_type'), 6, "check pnm_type tag on maxval");
106106
107107 # check the pixels
108108 ok(my ($white_asc, $grey_asc, $green_asc) = $maxval_asc->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels");
109 check_color($white_asc, 255, 255, 255, "white asc pixel");
110 check_color($grey_asc, 130, 130, 130, "grey asc pixel");
111 check_color($green_asc, 125, 125, 0, "green asc pixel");
109 is_color3($white_asc, 255, 255, 255, "white asc pixel");
110 is_color3($grey_asc, 130, 130, 130, "grey asc pixel");
111 is_color3($green_asc, 125, 125, 0, "green asc pixel");
112112 }
113113
114114 { # previously we didn't validate maxval at all, make sure it's
127127 like($maxval65536->errstr, qr/maxval of 65536 is over 65535 - invalid pnm file/,
128128 "error expected from reading maxval_65536.ppm");
129129
130 # maxval of 256 is valid, but Imager can't handle it yet in binary files
130 # maxval of 256 is valid, and handled as of 0.56
131131 my $maxval256 = Imager->new;
132 ok(!$maxval256->read(file=>'testimg/maxval_256.ppm'),
133 "should fail reading maxval 256 image");
134 print "# ",$maxval256->errstr,"\n";
135 like($maxval256->errstr, qr/maxval of 256 is over 255 - not currently supported by Imager/,
136 "error expected from reading maxval_256.ppm");
132 ok($maxval256->read(file=>'testimg/maxval_256.ppm'),
133 "should succeed reading maxval 256 image");
134 is_color3($maxval256->getpixel(x => 0, 'y' => 0),
135 0, 0, 0, "check black in maxval_256");
136 is_color3($maxval256->getpixel(x => 0, 'y' => 1),
137 255, 255, 255, "check white in maxval_256");
138 is($maxval256->bits, 16, "check bits/sample on maxval 256");
137139
138140 # make sure we handle maxval > 255 for ascii
139141 my $maxval4095asc = Imager->new;
142144 is($maxval4095asc->getchannels, 3, "channels");
143145 is($maxval4095asc->getwidth, 3, "width");
144146 is($maxval4095asc->getheight, 1, "height");
147 is($maxval4095asc->bits, 16, "check bits/sample on maxval 4095");
145148
146149 ok(my ($white, $grey, $green) = $maxval4095asc->getpixel('x'=>[0,1,2], 'y'=>[0,0,0]), "fetch pixels");
147 check_color($white, 255, 255, 255, "white 4095 pixel");
148 check_color($grey, 128, 128, 128, "grey 4095 pixel");
149 check_color($green, 127, 127, 0, "green 4095 pixel");
150 is_color3($white, 255, 255, 255, "white 4095 pixel");
151 is_color3($grey, 128, 128, 128, "grey 4095 pixel");
152 is_color3($green, 127, 127, 0, "green 4095 pixel");
150153 }
151154
152155 { # check i_format is set when reading a pnm file
194197 Imager->set_file_limits(reset=>1);
195198 }
196199
200 {
201 # check we correctly sync with the data stream
202 my $im = Imager->new;
203 ok($im->read(file => 'testimg/pgm.pgm', type => 'pnm'),
204 "read pgm.pgm")
205 or print "# cannot read pgm.pgm: ", $im->errstr, "\n";
206 print "# ", $im->getsamples('y' => 0), "\n";
207 is_color1($im->getpixel(x=>0, 'y' => 0), 254, "check top left");
208 }
209
197210 { # check error messages set correctly
198211 my $im = Imager->new(xsize=>100, ysize=>100, channels=>4);
199212 ok(!$im->write(file=>"testout/t104_fail.ppm", type=>'pnm'),
206219 "check error message");
207220 }
208221
222 # various bad input files
223 print "# check error handling\n";
224 {
225 my $im = Imager->new;
226 ok(!$im->read(file => 'testimg/short_bin.ppm', type=>'pnm'),
227 "fail to read short bin ppm");
228 cmp_ok($im->errstr, '=~', 'short read - file truncated',
229 "check error message");
230 }
231
232 {
233 my $im = Imager->new;
234 ok(!$im->read(file => 'testimg/short_bin16.ppm', type=>'pnm'),
235 "fail to read short bin ppm (maxval 65535)");
236 cmp_ok($im->errstr, '=~', 'short read - file truncated',
237 "check error message");
238 }
239
240 {
241 my $im = Imager->new;
242 ok(!$im->read(file => 'testimg/short_bin.pgm', type=>'pnm'),
243 "fail to read short bin pgm");
244 cmp_ok($im->errstr, '=~', 'short read - file truncated',
245 "check error message");
246 }
247
248 {
249 my $im = Imager->new;
250 ok(!$im->read(file => 'testimg/short_bin16.pgm', type=>'pnm'),
251 "fail to read short bin pgm (maxval 65535)");
252 cmp_ok($im->errstr, '=~', 'short read - file truncated',
253 "check error message");
254 }
255
256 {
257 my $im = Imager->new;
258 ok(!$im->read(file => 'testimg/short_bin.pbm', type => 'pnm'),
259 "fail to read a short bin pbm");
260 cmp_ok($im->errstr, '=~', 'short read - file truncated',
261 "check error message");
262 }
263
264 {
265 my $im = Imager->new;
266 ok(!$im->read(file => 'testimg/short_asc.ppm', type => 'pnm'),
267 "fail to read a short asc ppm");
268 cmp_ok($im->errstr, '=~', 'short read - file truncated',
269 "check error message");
270 }
271
272 {
273 my $im = Imager->new;
274 ok(!$im->read(file => 'testimg/short_asc.pgm', type => 'pnm'),
275 "fail to read a short asc pgm");
276 cmp_ok($im->errstr, '=~', 'short read - file truncated',
277 "check error message");
278 }
279
280 {
281 my $im = Imager->new;
282 ok(!$im->read(file => 'testimg/short_asc.pbm', type => 'pnm'),
283 "fail to read a short asc pbm");
284 cmp_ok($im->errstr, '=~', 'short read - file truncated',
285 "check error message");
286 }
287
288 {
289 my $im = Imager->new;
290 ok(!$im->read(file => 'testimg/bad_asc.ppm', type => 'pnm'),
291 "fail to read a bad asc ppm");
292 cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm',
293 "check error message");
294 }
295
296 {
297 my $im = Imager->new;
298 ok(!$im->read(file => 'testimg/bad_asc.pgm', type => 'pnm'),
299 "fail to read a bad asc pgm");
300 cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm',
301 "check error message");
302 }
303
304 {
305 my $im = Imager->new;
306 ok(!$im->read(file => 'testimg/bad_asc.pbm', type => 'pnm'),
307 "fail to read a bad asc pbm");
308 cmp_ok($im->errstr, '=~', 'invalid data for ascii pnm',
309 "check error message");
310 }
311
312 {
313 my $im = Imager->new;
314 ok($im->read(file => 'testimg/short_bin.ppm', type => 'pnm',
315 allow_incomplete => 1),
316 "partial read bin ppm");
317 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
318 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
319 }
320
321 {
322 my $im = Imager->new;
323 ok($im->read(file => 'testimg/short_bin16.ppm', type => 'pnm',
324 allow_incomplete => 1),
325 "partial read bin16 ppm");
326 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
327 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
328 is($im->bits, 16, "check correct bits");
329 }
330
331 {
332 my $im = Imager->new;
333 ok($im->read(file => 'testimg/short_bin.pgm', type => 'pnm',
334 allow_incomplete => 1),
335 "partial read bin pgm");
336 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
337 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
338 }
339
340 {
341 my $im = Imager->new;
342 ok($im->read(file => 'testimg/short_bin16.pgm', type => 'pnm',
343 allow_incomplete => 1),
344 "partial read bin16 pgm");
345 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
346 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
347 }
348
349 {
350 my $im = Imager->new;
351 ok($im->read(file => 'testimg/short_bin.pbm', type => 'pnm',
352 allow_incomplete => 1),
353 "partial read bin pbm");
354 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
355 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
356 }
357
358 {
359 my $im = Imager->new;
360 ok($im->read(file => 'testimg/short_asc.ppm', type => 'pnm',
361 allow_incomplete => 1),
362 "partial read asc ppm");
363 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
364 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
365 }
366
367 {
368 my $im = Imager->new;
369 ok($im->read(file => 'testimg/short_asc.pgm', type => 'pnm',
370 allow_incomplete => 1),
371 "partial read asc pgm");
372 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
373 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
374 }
375
376 {
377 my $im = Imager->new;
378 ok($im->read(file => 'testimg/short_asc.pbm', type => 'pnm',
379 allow_incomplete => 1),
380 "partial read asc pbm");
381 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
382 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
383 }
384
385 {
386 my $im = Imager->new;
387 ok($im->read(file => 'testimg/bad_asc.ppm', type => 'pnm',
388 allow_incomplete => 1),
389 "partial read bad asc ppm");
390 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
391 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
392 }
393
394 {
395 my $im = Imager->new;
396 ok($im->read(file => 'testimg/bad_asc.pgm', type => 'pnm',
397 allow_incomplete => 1),
398 "partial read bad asc pgm");
399 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
400 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
401 }
402
403 {
404 my $im = Imager->new;
405 ok($im->read(file => 'testimg/bad_asc.pbm', type => 'pnm',
406 allow_incomplete => 1),
407 "partial read bad asc pbm");
408 is($im->tags(name => 'i_incomplete'), 1, "partial flag set");
409 is($im->tags(name => 'i_lines_read'), 1, "lines_read set");
410 }
411
412 {
413 print "# monochrome output\n";
414 my $im = Imager->new(xsize => 10, ysize => 10, type => 'paletted');
415 ok($im->addcolors(colors => [ '#000000', '#FFFFFF' ]),
416 "add black and white");
417 $im->box(filled => 1, xmax => 4, color => '#000000');
418 $im->box(filled => 1, xmin => 5, color => '#FFFFFF');
419 is($im->type, 'paletted', 'mono still paletted');
420 ok($im->write(file => 'testout/t104_mono.pbm', type => 'pnm'),
421 "save as pbm");
422
423 # check it
424 my $imread = Imager->new;
425 ok($imread->read(file => 'testout/t104_mono.pbm', type=>'pnm'),
426 "read it back in")
427 or print "# ", $imread->errstr, "\n";
428 is($imread->type, 'paletted', "check result is paletted");
429 is($imread->tags(name => 'pnm_type'), 4, "check type");
430 }
431
432 {
433 print "# 16-bit output\n";
434 my $data;
435 my $im = test_image_16();
436
437 # without tag, it should do 8-bit output
438 ok($im->write(data => \$data, type => 'pnm'),
439 "write 16-bit image as 8-bit/sample ppm");
440 my $im8 = Imager->new;
441 ok($im8->read(data => $data), "read it back");
442 is($im8->tags(name => 'pnm_maxval'), 255, "check maxval");
443 is_image($im, $im8, "check image matches");
444
445 # try 16-bit output
446 $im->settag(name => 'pnm_write_wide_data', value => 1);
447 $data = '';
448 ok($im->write(data => \$data, type => 'pnm'),
449 "write 16-bit image as 16-bit/sample ppm");
450 $im->write(file=>'testout/t104_16.ppm');
451 my $im16 = Imager->new;
452 ok($im16->read(data => $data), "read it back");
453 is($im16->tags(name => 'pnm_maxval'), 65535, "check maxval");
454 $im16->write(file=>'testout/t104_16b.ppm');
455 is_image($im, $im16, "check image matches");
456 }
457
209458 sub openimage {
210459 my $fname = shift;
211460 local(*FH);
229478 is($g, $gray, "compare gray");
230479 }
231480
232 sub check_color {
233 my ($c, $red, $green, $blue, $note) = @_;
234
235 my ($r, $g, $b) = $c->rgba;
236 is_deeply([ $r, $g, $b], [ $red, $green, $blue ],
237 "$note ($r, $g, $b) compared to ($red, $green, $blue)");
238 }
00 #!perl -w
1
12 =pod
23
34 IF THIS TEST CRASHES
1011
1112 use strict;
1213 $|=1;
13 use lib 't';
14 use Test::More tests => 113;
14 use Test::More tests => 125;
1515 use Imager qw(:all);
1616 BEGIN { require "t/testtools.pl"; }
1717 use Carp 'confess';
4747 $im = Imager->new(xsize=>2, ysize=>2);
4848 ok(!$im->write(file=>"testout/nogif.gif"), "should fail to write gif");
4949 is($im->errstr, 'format not supported', "check no gif message");
50 skip("no gif support", 109);
50 skip("no gif support", 121);
5151 }
5252 open(FH,">testout/t105.gif") || die "Cannot open testout/t105.gif\n";
5353 binmode(FH);
668668 is($im[0]->tags(name => 'gif_delay'), 50, "first delay read back");
669669 is($im[1]->tags(name => 'gif_delay'), 50, "second delay read back");
670670 }
671 SKIP:
672 { # check graphic control extension and ns loop tags are read correctly
673 print "# check GCE and netscape loop extension tag values\n";
674 my @im = Imager->read_multi(file => 'testimg/screen3.gif');
675 is(@im, 2, "read 2 images from screen3.gif")
676 or skip("Could not load testimg/screen3.gif:".Imager->errstr, 11);
677 is($im[0]->tags(name => 'gif_delay'), 50, "0 - gif_delay");
678 is($im[0]->tags(name => 'gif_disposal'), 2, "0 - gif_disposal");
679 is($im[0]->tags(name => 'gif_trans_index'), undef, "0 - gif_trans_index");
680 is($im[0]->tags(name => 'gif_user_input'), 0, "0 - gif_user_input");
681 is($im[0]->tags(name => 'gif_loop'), 0, "0 - gif_loop");
682 is($im[1]->tags(name => 'gif_delay'), 50, "1 - gif_delay");
683 is($im[1]->tags(name => 'gif_disposal'), 2, "1 - gif_disposal");
684 is($im[1]->tags(name => 'gif_trans_index'), 7, "1 - gif_trans_index");
685 is($im[1]->tags(name => 'gif_trans_color'), 'color(255,255,255,0)',
686 "1 - gif_trans_index");
687 is($im[1]->tags(name => 'gif_user_input'), 0, "1 - gif_user_input");
688 is($im[1]->tags(name => 'gif_loop'), 0, "1 - gif_loop");
689 }
671690 }
672691
673692 sub test_readgif_cb {
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 127;
43 use Imager qw(:all);
54 $^W=1; # warnings during command-line tests
141140 # paletted reads
142141 my $img4 = Imager->new;
143142 ok($img4->read(file=>'testimg/comp4.tif'), "reading 4-bit paletted");
144 ok($img4->type eq 'paletted', "image isn't paletted");
143 is($img4->type, 'paletted', "image isn't paletted");
145144 print "# colors: ", $img4->colorcount,"\n";
146 ok($img4->colorcount <= 16, "more than 16 colors!");
145 cmp_ok($img4->colorcount, '<=', 16, "more than 16 colors!");
147146 #ok($img4->write(file=>'testout/t106_was4.ppm'),
148147 # "Cannot write img4");
149148 # I know I'm using BMP before it's test, but comp4.tif started life
155154 ok($diff == 0, "image mismatch");
156155 my $img8 = Imager->new;
157156 ok($img8->read(file=>'testimg/comp8.tif'), "reading 8-bit paletted");
158 ok($img8->type eq 'paletted', "image isn't paletted");
157 is($img8->type, 'paletted', "image isn't paletted");
159158 print "# colors: ", $img8->colorcount,"\n";
160159 #ok($img8->write(file=>'testout/t106_was8.ppm'),
161160 # "Cannot write img8");
166165 print "# diff $diff\n";
167166 ok($diff == 0, "image mismatch");
168167 my $bad = Imager->new;
169 ok($bad->read(file=>'testimg/comp4bad.tif'), "bad image not returned");
168 ok($bad->read(file=>'testimg/comp4bad.tif',
169 allow_incomplete=>1), "bad image not returned");
170170 ok(scalar $bad->tags(name=>'i_incomplete'), "incomplete tag not set");
171171 ok($img8->write(file=>'testout/t106_pal8.tif'), "writing 8-bit paletted");
172172 my $cmp8 = Imager->new;
173173 ok($cmp8->read(file=>'testout/t106_pal8.tif'),
174174 "reading 8-bit paletted");
175175 #print "# ",$cmp8->errstr,"\n";
176 ok($cmp8->type eq 'paletted', "pal8 isn't paletted");
177 ok($cmp8->colorcount == 256, "pal8 bad colorcount");
176 is($cmp8->type, 'paletted', "pal8 isn't paletted");
177 is($cmp8->colorcount, 256, "pal8 bad colorcount");
178178 $diff = i_img_diff($img8->{IMG}, $cmp8->{IMG});
179179 print "# diff $diff\n";
180180 ok($diff == 0, "written image doesn't match read");
181181 ok($img4->write(file=>'testout/t106_pal4.tif'), "writing 4-bit paletted");
182182 ok(my $cmp4 = Imager->new->read(file=>'testout/t106_pal4.tif'),
183183 "reading 4-bit paletted");
184 ok($cmp4->type eq 'paletted', "pal4 isn't paletted");
185 ok($cmp4->colorcount == 16, "pal4 bad colorcount");
184 is($cmp4->type, 'paletted', "pal4 isn't paletted");
185 is($cmp4->colorcount, 16, "pal4 bad colorcount");
186186 $diff = i_img_diff($img4->{IMG}, $cmp4->{IMG});
187187 print "# diff $diff\n";
188188 ok($diff == 0, "written image doesn't match read");
259259 \&io_closer);
260260 ok($IO4, "new writecb obj");
261261 ok(i_writetiff_wiol($img, $IO4), "write to cb");
262 ok($work eq $odata, "write cb match");
262 is($work, $odata, "write cb match");
263263 ok($did_close, "write cb did close");
264264 open D1, ">testout/d1.tiff" or die;
265265 print D1 $work;
276276 \&io_closer, 1);
277277 ok($IO5, "new writecb obj 2");
278278 ok(i_writetiff_wiol($img, $IO5), "write to cb2");
279 ok($work eq $odata, "write cb2 match");
279 is($work, $odata, "write cb2 match");
280280 ok($did_close, "write cb2 did close");
281281
282282 open D3, ">testout/d3.tiff" or die;
298298 ok(i_img_diff($imgs[$i]{IMG}, $out[$i]{IMG}) == 0,
299299 "comparing image $i");
300300 my ($tag) = $out[$i]->tags(name=>'tiff_pagename');
301 ok($tag eq "Page ".($i+1),
301 is($tag, "Page ".($i+1),
302302 "tag doesn't match original image");
303303 }
304304
323323 "compare second fax image");
324324
325325 my ($format) = $imgs[0]->tags(name=>'i_format');
326 ok(defined $format && $format eq 'tiff', "check i_format tag");
326 is($format, 'tiff', "check i_format tag");
327327
328328 my $unit = $imgs[0]->tags(name=>'tiff_resolutionunit');
329329 ok(defined $unit && $unit == 2, "check tiff_resolutionunit tag");
330330 my $unitname = $imgs[0]->tags(name=>'tiff_resolutionunit_name');
331 ok(defined $unitname && $unitname eq 'inch',
332 "check tiff_resolutionunit_name tag");
331 is($unitname, 'inch', "check tiff_resolutionunit_name tag");
333332
334333 my $warned = Imager->new;
335334 ok($warned->read(file=>"testimg/tiffwarn.tif"), "read tiffwarn.tif");
00 #!perl -w
11 use strict;
2 use lib 't';
3 use Test::More tests => 89;
2 use Test::More tests => 191;
43 use Imager qw(:all);
4 use Imager::Test qw(test_image_raw is_image);
55 init_log("testout/t107bmp.log",1);
6 #BEGIN { require 't/testtools.pl'; } # BEGIN to apply prototypes
6
7 my $debug_writes = 0;
78
89 my $base_diff = 0;
910 # if you change this make sure you generate new compressed versions
1112 my $blue=i_color_new(0,0,255,255);
1213 my $red=i_color_new(255,0,0,255);
1314
14 my $img=Imager::ImgRaw::new(150,150,3);
15
16 i_box_filled($img,70,25,130,125,$green);
17 i_box_filled($img,20,25,80,125,$blue);
18 i_arc($img,75,75,30,0,361,$red);
19 i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]);
15 my $img = test_image_raw();
2016
2117 Imager::i_tags_add($img, 'i_xres', 0, '300', 0);
2218 Imager::i_tags_add($img, 'i_yres', 0, undef, 300);
182178 }
183179
184180 { # check file limits are checked
185 my $limit_file = "testout/t104.ppm";
181 my $limit_file = "testout/t107_24bit.bmp";
186182 ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
187183 my $im = Imager->new;
188184 ok(!$im->read(file=>$limit_file),
216212 "should succeed - just inside bytes limit");
217213 Imager->set_file_limits(reset=>1);
218214 }
219
215
216 { # various short read failure tests, each entry has:
217 # source filename, size, expected error
218 # these have been selected based on code coverage, to check each
219 # failure path is checked, where practical
220 my @tests =
221 (
222 [
223 "file truncated inside header",
224 "winrgb2.bmp",
225 20, "file too short to be a BMP file"
226 ],
227 [
228 "1-bit, truncated inside palette",
229 "winrgb2.bmp",
230 56, "reading BMP palette"
231 ],
232 [
233 "1-bit, truncated in offset region",
234 "winrgb2off.bmp", 64, "failed skipping to image data offset"
235 ],
236 [
237 "1-bit, truncated in image data",
238 "winrgb2.bmp", 96, "failed reading 1-bit bmp data"
239 ],
240 [
241 "4-bit, truncated inside palette",
242 "winrgb4.bmp",
243 56, "reading BMP palette"
244 ],
245 [
246 "4-bit, truncated in offset region",
247 "winrgb4off.bmp", 120, "failed skipping to image data offset",
248 ],
249 [
250 "4-bit, truncate in image data",
251 "winrgb4.bmp", 120, "failed reading 4-bit bmp data"
252 ],
253 [
254 "4-bit RLE, truncate in uncompressed data",
255 "comp4.bmp", 0x229, "missing data during decompression"
256 ],
257 [
258 "8-bit, truncated in palette",
259 "winrgb8.bmp", 1060, "reading BMP palette"
260 ],
261 [
262 "8-bit, truncated in offset region",
263 "winrgb8off.bmp", 1080, "failed skipping to image data offset"
264 ],
265 [
266 "8-bit, truncated in image data",
267 "winrgb8.bmp", 1080, "failed reading 8-bit bmp data"
268 ],
269 [
270 "8-bit RLE, truncate in uncompressed data",
271 "comp8.bmp", 0x68C, "missing data during decompression"
272 ],
273 [
274 "24-bit, truncate in offset region",
275 "winrgb24off.bmp", 56, "failed skipping to image data offset",
276 ],
277 [
278 "24-bit, truncate in image data",
279 "winrgb24.bmp", 100, "failed reading image data",
280 ],
281 );
282
283 my $test_index = 0;
284 for my $test (@tests) {
285 my ($desc, $srcfile, $size, $error) = @$test;
286 my $im = Imager->new;
287 open IMDATA, "< testimg/$srcfile"
288 or die "$test_index - $desc: Cannot open testimg/$srcfile: $!";
289 binmode IMDATA;
290 my $data;
291 read(IMDATA, $data, $size) == $size
292 or die "$test_index - $desc: Could not read $size data from $srcfile";
293 close IMDATA;
294 ok(!$im->read(data => $data, type =>'bmp'),
295 "$test_index - $desc: Should fail to read");
296 is($im->errstr, $error, "$test_index - $desc: check message");
297 ++$test_index;
298 }
299 }
300
301 { # various short read success tests, each entry has:
302 # source filename, size, expected tags
303 print "# allow_incomplete tests\n";
304 my @tests =
305 (
306 [
307 "1-bit",
308 "winrgb2.bmp", 96,
309 {
310 bmp_compression_name => 'BI_RGB',
311 bmp_compression => 0,
312 bmp_used_colors => 2,
313 i_lines_read => 8,
314 },
315 ],
316 [
317 "4-bit",
318 "winrgb4.bmp", 250,
319 {
320 bmp_compression_name => 'BI_RGB',
321 bmp_compression => 0,
322 bmp_used_colors => 16,
323 i_lines_read => 11,
324 },
325 ],
326 [
327 "4-bit RLE - uncompressed seq",
328 "comp4.bmp", 0x229,
329 {
330 bmp_compression_name => 'BI_RLE4',
331 bmp_compression => 2,
332 bmp_used_colors => 16,
333 i_lines_read => 44,
334 },
335 ],
336 [
337 "4-bit RLE - start seq",
338 "comp4.bmp", 0x97,
339 {
340 bmp_compression_name => 'BI_RLE4',
341 bmp_compression => 2,
342 bmp_used_colors => 16,
343 i_lines_read => 8,
344 },
345 ],
346 [
347 "8-bit",
348 "winrgb8.bmp", 1250,
349 {
350 bmp_compression_name => 'BI_RGB',
351 bmp_compression => 0,
352 bmp_used_colors => 256,
353 i_lines_read => 8,
354 },
355 ],
356 [
357 "8-bit RLE - uncompressed seq",
358 "comp8.bmp", 0x68C,
359 {
360 bmp_compression_name => 'BI_RLE8',
361 bmp_compression => 1,
362 bmp_used_colors => 256,
363 i_lines_read => 27,
364 },
365 ],
366 [
367 "8-bit RLE - initial seq",
368 "comp8.bmp", 0x487,
369 {
370 bmp_compression_name => 'BI_RLE8',
371 bmp_compression => 1,
372 bmp_used_colors => 256,
373 i_lines_read => 20,
374 },
375 ],
376 [
377 "24-bit",
378 "winrgb24.bmp", 800,
379 {
380 bmp_compression_name => 'BI_RGB',
381 bmp_compression => 0,
382 bmp_used_colors => 0,
383 i_lines_read => 12,
384 },
385 ],
386 );
387
388 my $test_index = 0;
389 for my $test (@tests) {
390 my ($desc, $srcfile, $size, $tags) = @$test;
391 my $im = Imager->new;
392 open IMDATA, "< testimg/$srcfile"
393 or die "$test_index - $desc: Cannot open testimg/$srcfile: $!";
394 binmode IMDATA;
395 my $data;
396 read(IMDATA, $data, $size) == $size
397 or die "$test_index - $desc: Could not read $size data from $srcfile";
398 close IMDATA;
399 ok($im->read(data => $data, type =>'bmp', allow_incomplete => 1),
400 "$test_index - $desc: Should read successfully");
401 # check standard tags are set
402 is($im->tags(name => 'i_format'), 'bmp',
403 "$test_index - $desc: i_format set");
404 is($im->tags(name => 'i_incomplete'), 1,
405 "$test_index - $desc: i_incomplete set");
406 my %check_tags;
407 for my $key (keys %$tags) {
408 $check_tags{$key} = $im->tags(name => $key);
409 }
410 is_deeply(\%check_tags, $tags, "$test_index - $desc: check tags");
411 ++$test_index;
412 }
413 }
414
415 { # check handling of reading images with negative height
416 # each entry is:
417 # source file, description
418 print "# check handling of negative height values\n";
419 my @tests =
420 (
421 [ "winrgb2.bmp", "1-bit, uncompressed" ],
422 [ "winrgb4.bmp", "4-bit, uncompressed" ],
423 [ "winrgb8.bmp", "8-bit, uncompressed" ],
424 [ "winrgb24.bmp", "24-bit, uncompressed" ],
425 [ "comp4.bmp", "4-bit, RLE" ],
426 [ "comp8.bmp", "8-bit, RLE" ],
427 );
428 my $test_index = 0;
429 for my $test (@tests) {
430 my ($file, $desc) = @$test;
431 open IMDATA, "< testimg/$file"
432 or die "$test_index - Cannot open $file: $!";
433 binmode IMDATA;
434 my $data = do { local $/; <IMDATA> };
435 close IMDATA;
436 my $im_orig = Imager->new;
437 $im_orig->read(data => $data)
438 or die "Cannot load original $file: ", $im_orig->errstr;
439
440 # now negate the height
441 my $orig_height = unpack("V", substr($data, 0x16, 4));
442 my $neg_height = 0xFFFFFFFF & ~($orig_height - 1);
443 substr($data, 0x16, 4) = pack("V", $neg_height);
444
445 # and read the modified image
446 my $im = Imager->new;
447 ok($im->read(data => $data),
448 "$test_index - $desc: read negated height image")
449 or print "# ", $im->errstr, "\n";
450
451 # flip orig to match what we should get
452 $im_orig->flip(dir => 'v');
453
454 # check it out
455 is_image($im, $im_orig, "$test_index - $desc: check image");
456
457 ++$test_index;
458 }
459 }
460
461 { print "# patched data read failure tests\n";
462 # like the "various invalid format" tests, these generate fail
463 # images from other images included with Imager without providing a
464 # full bmp source, saving on dist size and focusing on the changes needed
465 # to cause the failure
466 # each entry is: source file, patches, expected error, description
467
468 my @tests =
469 (
470 # low image data offsets
471 [
472 "winrgb2.bmp",
473 { 10 => "3d 00 00 00" },
474 "image data offset too small (61)",
475 "1-bit, small image offset"
476 ],
477 [
478 "winrgb4.bmp",
479 { 10 => "75 00 00 00" },
480 "image data offset too small (117)",
481 "4-bit, small image offset"
482 ],
483 [
484 "winrgb8.bmp",
485 { 10 => "35 04 00 00" },
486 "image data offset too small (1077)",
487 "8-bit, small image offset"
488 ],
489 [
490 "winrgb24.bmp",
491 { 10 => "35 00 00 00" },
492 "image data offset too small (53)",
493 "24-bit, small image offset"
494 ],
495 );
496 my $test_index = 0;
497 for my $test (@tests) {
498 my ($filename, $patches, $error, $desc) = @$test;
499
500 my $data = load_patched_file("testimg/$filename", $patches);
501 my $im = Imager->new;
502 ok(!$im->read(data => $data, type=>'bmp'),
503 "$test_index - $desc:should fail to read");
504 is($im->errstr, $error, "$test_index - $desc:check message");
505 ++$test_index;
506 }
507 }
508
509 { # various write failure tests
510 # each entry is:
511 # source, limit, expected error, description
512 my @tests =
513 (
514 [
515 "winrgb2.bmp", 1,
516 "cannot write bmp header: limit reached",
517 "1-bit, writing header"
518 ],
519 [
520 "winrgb4.bmp", 1,
521 "cannot write bmp header: limit reached",
522 "4-bit, writing header"
523 ],
524 [
525 "winrgb8.bmp", 1,
526 "cannot write bmp header: limit reached",
527 "8-bit, writing header"
528 ],
529 [
530 "winrgb24.bmp", 1,
531 "cannot write bmp header: limit reached",
532 "24-bit, writing header"
533 ],
534 [
535 "winrgb2.bmp", 0x38,
536 "cannot write palette entry: limit reached",
537 "1-bit, writing palette"
538 ],
539 [
540 "winrgb4.bmp", 0x38,
541 "cannot write palette entry: limit reached",
542 "4-bit, writing palette"
543 ],
544 [
545 "winrgb8.bmp", 0x38,
546 "cannot write palette entry: limit reached",
547 "8-bit, writing palette"
548 ],
549 [
550 "winrgb2.bmp", 0x40,
551 "writing 1 bit/pixel packed data: limit reached",
552 "1-bit, writing image data"
553 ],
554 [
555 "winrgb4.bmp", 0x80,
556 "writing 4 bit/pixel packed data: limit reached",
557 "4-bit, writing image data"
558 ],
559 [
560 "winrgb8.bmp", 0x440,
561 "writing 8 bit/pixel packed data: limit reached",
562 "8-bit, writing image data"
563 ],
564 [
565 "winrgb24.bmp", 0x39,
566 "writing image data: limit reached",
567 "24-bit, writing image data"
568 ],
569 );
570 print "# write failure tests\n";
571 my $test_index = 0;
572 for my $test (@tests) {
573 my ($file, $limit, $error, $desc) = @$test;
574
575 my $im = Imager->new;
576 $im->read(file => "testimg/$file")
577 or die "Cannot read $file: ", $im->errstr;
578
579 ok(!$im->write(type => 'bmp', callback => limited_write($limit),
580 maxbuffer => 1),
581 "$test_index - $desc: write should fail");
582 is($im->errstr, $error, "$test_index - $desc: check error message");
583
584 ++$test_index;
585 }
586 }
587
220588 sub write_test {
221589 my ($im, $filename) = @_;
222590 local *FH;
291659 }
292660 }
293661
662 sub limited_write {
663 my ($limit) = @_;
664
665 return
666 sub {
667 my ($data) = @_;
668 $limit -= length $data;
669 if ($limit >= 0) {
670 print "# write of ", length $data, " bytes successful ($limit left)\n" if $debug_writes;
671 return 1;
672 }
673 else {
674 print "# write of ", length $data, " bytes failed\n";
675 Imager::i_push_error(0, "limit reached");
676 return;
677 }
678 };
679 }
680
681 sub load_patched_file {
682 my ($filename, $patches) = @_;
683
684 open IMDATA, "< $filename"
685 or die "Cannot open $filename: $!";
686 binmode IMDATA;
687 my $data = do { local $/; <IMDATA> };
688 for my $offset (keys %$patches) {
689 (my $hdata = $patches->{$offset}) =~ tr/ //d;
690 my $pdata = pack("H*", $hdata);
691 substr($data, $offset, length $pdata) = $pdata;
692 }
693
694 return $data;
695 }
00 #!perl -w
11 use Imager qw(:all);
22 use strict;
3 use lib 't';
43 use Test::More tests=>38;
54 BEGIN { require "t/testtools.pl"; }
65 init_log("testout/t108tga.log",1);
66 # Change 1..1 below to 1..last_test_to_print .
77 # (It may become useful if the test is moved to ./t subdirectory.)
88
9 use lib 't';
109 use Test::More tests => 47;
1110
1211 BEGIN { use_ok('Imager'); };
13
14 require "t/testtools.pl";
1512
1613 init_log("testout/t15color.log",1);
1714
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 8;
43 use Imager;
54
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 56;
43
54 use Imager ':handy';
66 # Change 1..1 below to 1..last_test_to_print .
77 # (It may become useful if the test is moved to ./t subdirectory.)
88 use strict;
9 use lib 't';
109 use Test::More tests => 43;
1110 my $loaded;
1211
66 # Change 1..1 below to 1..last_test_to_print .
77 # (It may become useful if the test is moved to ./t subdirectory.)
88 use strict;
9 use lib 't';
10 use Test::More tests => 77;
9 use Test::More tests => 90;
1110 BEGIN { use_ok(Imager => ':all') }
11 use Imager::Test qw(diff_text_with_nul);
1212
1313 #$Imager::DEBUG=1;
1414
2222 SKIP:
2323 {
2424 if (!(i_has_format("t1")) ) {
25 skip("t1lib unavailable or disabled", 76);
25 skip("t1lib unavailable or disabled", 89);
2626 }
2727 elsif (! -f $fontname_pfb) {
28 skip("cannot find fontfile for type 1 test $fontname_pfb", 76);
28 skip("cannot find fontfile for type 1 test $fontname_pfb", 89);
2929 }
3030 elsif (! -f $fontname_afm) {
31 skip("cannot find fontfile for type 1 test $fontname_afm", 76);
31 skip("cannot find fontfile for type 1 test $fontname_afm", 89);
3232 }
3333
3434 print "# has t1\n";
178178 # names
179179 my $face_name = Imager::i_t1_face_name($font->{id});
180180 print "# face $face_name\n";
181 ok($face_name eq 'ExistenceTest', "face name");
181 is($face_name, 'ExistenceTest', "face name");
182182 $face_name = $font->face_name;
183 ok($face_name eq 'ExistenceTest', "face name");
183 is($face_name, 'ExistenceTest', "face name");
184184
185185 my @glyph_names = $font->glyph_names(string=>"!J/");
186186 is($glyph_names[0], 'exclam', "check exclam name OO");
307307 is($bbox_utf8->advance_width, $bbox_tran->advance_width,
308308 "advance widths should match");
309309 }
310 { # string output cut off at NUL ('\0')
311 # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd
312 my $font = Imager::Font->new(file => 'fontfiles/dcr10.pfb', type => 't1');
313 ok($font, "loaded dcr10.pfb");
314
315 diff_text_with_nul("a\\0b vs a", "a\0b", "a",
316 font => $font, color => '#FFFFFF');
317 diff_text_with_nul("a\\0b vs a", "a\0b", "a",
318 font => $font, channel => 1);
319
320 # UTF8 encoded \xBF
321 my $pound = pack("C*", 0xC2, 0xBF);
322 diff_text_with_nul("utf8 pound\0pound vs pound", "$pound\0$pound", $pound,
323 font => $font, color => '#FFFFFF', utf8 => 1);
324 diff_text_with_nul("utf8 dash\0dash vs dash", "$pound\0$pound", $pound,
325 font => $font, channel => 1, utf8 => 1);
326
327 }
310328 }
311329
312330 #malloc_state();
00 #!perl -w
11 use strict;
2 use lib 't';
3 use Test::More tests => 72;
2 use Test::More tests => 85;
3
4 $|=1;
45
56 BEGIN { use_ok(Imager => ':all') }
67 require "t/testtools.pl";
8 use Imager::Test qw(diff_text_with_nul);
79
810 init_log("testout/t35ttfont.log",2);
911
1012 SKIP:
1113 {
12 skip("freetype 1.x unavailable or disabled", 71)
14 skip("freetype 1.x unavailable or disabled", 84)
1315 unless i_has_format("tt");
1416 print "# has tt\n";
1517
1820
1921 if (!ok(-f $fontname, "check test font file exists")) {
2022 print "# cannot find fontfile for truetype test $fontname\n";
21 skip('Cannot load test font', 70);
23 skip('Cannot load test font', 83);
2224 }
2325
2426 i_init_fonts();
134136
135137 my $face_name = Imager::i_tt_face_name($hcfont->{id});
136138 print "# face $face_name\n";
137 ok($face_name eq 'ExistenceTest', "face name");
139 is($face_name, 'ExistenceTest', "face name (function)");
138140 $face_name = $hcfont->face_name;
139 ok($face_name eq 'ExistenceTest', "face name");
141 is($face_name, 'ExistenceTest', "face name (OO)");
140142
141143 # FT 1.x cheats and gives names even if the font doesn't have them
142144 my @glyph_names = $hcfont->glyph_names(string=>"!J/");
143 ok($glyph_names[0] eq 'exclam', "check exclam name OO");
145 is($glyph_names[0], 'exclam', "check exclam name OO");
144146 ok(!defined($glyph_names[1]), "check for no J name OO");
145 ok($glyph_names[2] eq 'slash', "check slash name OO");
147 is($glyph_names[2], 'slash', "check slash name OO");
146148
147149 print "# ** name table of the test font **\n";
148150 Imager::i_tt_dump_names($hcfont->{id});
257259 "outputting just a space was crashing");
258260 }
259261
262 { # string output cut off at NUL ('\0')
263 # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd
264 my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt');
265 ok($font, "loaded imugly");
266
267 diff_text_with_nul("a\\0b vs a", "a\0b", "a",
268 font => $font, color => '#FFFFFF');
269 diff_text_with_nul("a\\0b vs a", "a\0b", "a",
270 font => $font, channel => 1);
271
272 # UTF8 encoded \x{2010}
273 my $dash = pack("C*", 0xE2, 0x80, 0x90);
274 diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash,
275 font => $font, color => '#FFFFFF', utf8 => 1);
276 diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash,
277 font => $font, channel => 1, utf8 => 1);
278 }
279
260280 ok(1, "end of code");
261281 }
99
1010 # Change 1..1 below to 1..last_test_to_print .
1111 # (It may become useful if the test is moved to ./t subdirectory.)
12 use Test::More tests => 20;
1213
13 my $loaded;
14 BEGIN { $| = 1; print "1..20\n"; }
15 END {print "not ok 1\n" unless $loaded;}
16 use Imager;
17 BEGIN { require "t/testtools.pl"; }
18 $loaded=1;
19 okx(1, "loaded");
14 BEGIN { use_ok('Imager') };
2015
2116 init_log("testout/t36oofont.log", 1);
2217
2924 my $red=Imager::Color->new(205, 92, 92, 255);
3025 die $Imager::ERRSTR unless $red;
3126
32 if (i_has_format("t1") and -f $fontname_pfb) {
27 SKIP:
28 {
29 i_has_format("t1") && -f $fontname_pfb
30 or skip("T1lib missing or disabled", 8);
3331
3432 my $img=Imager->new(xsize=>300, ysize=>100) or die "$Imager::ERRSTR\n";
3533
3634 my $font=Imager::Font->new(file=>$fontname_pfb,size=>25)
3735 or die $img->{ERRSTR};
3836
39 okx(1, "created font");
37 ok(1, "created font");
4038
41 okx($img->string(font=>$font, text=>"XMCLH", 'x'=>100, 'y'=>100),
39 ok($img->string(font=>$font, text=>"XMCLH", 'x'=>100, 'y'=>100),
4240 "draw text");
4341 $img->line(x1=>0, x2=>300, y1=>50, y2=>50, color=>$green);
4442
4543 my $text="LLySja";
4644 my @bbox=$font->bounding_box(string=>$text, 'x'=>0, 'y'=>50);
4745
48 isx(@bbox, 8, "bounding box list length");
46 is(@bbox, 8, "bounding box list length");
4947
5048 $img->box(box=>\@bbox, color=>$green);
5149
5250 # "utf8" support
5351 $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41);
54 okx($img->string(font=>$font, text=>$text, 'x'=>100, 'y'=>50, utf8=>1,
52 ok($img->string(font=>$font, text=>$text, 'x'=>100, 'y'=>50, utf8=>1,
5553 overline=>1),
5654 "draw 'utf8' hand-encoded text");
5755
58 okx($img->string(font=>$font, text=>$text, 'x'=>140, 'y'=>50, utf8=>1,
56 ok($img->string(font=>$font, text=>$text, 'x'=>140, 'y'=>50, utf8=>1,
5957 underline=>1, channel=>2),
6058 "channel 'utf8' hand-encoded text");
6159
62 if($] >= 5.006) {
60 SKIP:
61 {
62 $] >= 5.006
63 or skip("perl too old for native utf8", 2);
6364 eval q{$text = "A\x{2010}A"};
64 okx($img->string(font=>$font, text=>$text, 'x'=>180, 'y'=>50,
65 ok($img->string(font=>$font, text=>$text, 'x'=>180, 'y'=>50,
6566 strikethrough=>1),
6667 "draw native UTF8 text");
67 okx($img->string(font=>$font, text=>$text, 'x'=>220, 'y'=>50, channel=>1),
68 ok($img->string(font=>$font, text=>$text, 'x'=>220, 'y'=>50, channel=>1),
6869 "channel native UTF8 text");
6970 }
70 else {
71 skipx(2, "perl too old for native utf8");
72 }
7371
74 okx($img->write(file=>"testout/t36oofont1.ppm", type=>'pnm'),
72 ok($img->write(file=>"testout/t36oofont1.ppm", type=>'pnm'),
7573 "write t36oofont1.ppm")
7674 or print "# ",$img->errstr,"\n";
7775
78 } else {
79 skipx(8, "T1lib missing or disabled");
8076 }
8177
82 if (i_has_format("tt") and -f $fontname_tt) {
78 SKIP:
79 {
80 i_has_format("tt") && -f $fontname_tt
81 or skip("FT1.x missing or disabled", 10);
8382
8483 my $img=Imager->new(xsize=>300, ysize=>100) or die "$Imager::ERRSTR\n";
8584
8685 my $font=Imager::Font->new(file=>$fontname_tt,size=>25)
8786 or die $img->{ERRSTR};
8887
89 okx(1, "create TT font object");
88 ok(1, "create TT font object");
9089
91 okx($img->string(font=>$font, text=>"XMCLH", 'x'=>100, 'y'=>100),
90 ok($img->string(font=>$font, text=>"XMCLH", 'x'=>100, 'y'=>100),
9291 "draw text");
9392
9493 $img->line(x1=>0, x2=>300, y1=>50, y2=>50, color=>$green);
9695 my $text="LLySja";
9796 my @bbox=$font->bounding_box(string=>$text, 'x'=>0, 'y'=>50);
9897
99 isx(@bbox, 8, "bbox list size");
98 is(@bbox, 8, "bbox list size");
10099
101100 $img->box(box=>\@bbox, color=>$green);
102101
103102 $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41);
104 okx($img->string(font=>$font, text=>$text, 'x'=>100, 'y'=>50, utf8=>1),
103 ok($img->string(font=>$font, text=>$text, 'x'=>100, 'y'=>50, utf8=>1),
105104 "draw hand-encoded UTF8 text");
106105
107 if($] >= 5.006) {
106 SKIP:
107 {
108 $] >= 5.006
109 or skip("perl too old for native utf8", 1);
108110 eval q{$text = "A\x{2010}A"};
109 okx($img->string(font=>$font, text=>$text, 'x'=>200, 'y'=>50),
111 ok($img->string(font=>$font, text=>$text, 'x'=>200, 'y'=>50),
110112 "draw native UTF8 text");
111113 }
112 else {
113 skipx(1, "perl too old for native utf8");
114 }
115114
116 okx($img->write(file=>"testout/t36oofont2.ppm", type=>'pnm'),
115 ok($img->write(file=>"testout/t36oofont2.ppm", type=>'pnm'),
117116 "write t36oofont2.ppm")
118117 or print "# ", $img->errstr,"\n";
119118
120 okx($font->utf8, "make sure utf8 method returns true");
119 ok($font->utf8, "make sure utf8 method returns true");
121120
122121 my $has_chars = $font->has_chars(string=>"\x01A");
123 okx($has_chars eq "\x00\x01", "has_chars scalar");
122 is($has_chars, "\x00\x01", "has_chars scalar");
124123 my @has_chars = $font->has_chars(string=>"\x01A");
125 okx(!$has_chars[0], "has_chars list 0");
126 okx($has_chars[1], "has_chars list 1");
127 } else {
128 skipx(10, "FT1.x missing or disabled");
124 ok(!$has_chars[0], "has_chars list 0");
125 ok($has_chars[1], "has_chars list 1");
129126 }
130127
131 okx(1, "end");
128 ok(1, "end");
00 #!perl -w
11 use strict;
2 use lib 't';
3 use Test::More tests => 32;
2 use Test::More tests => 54;
43 BEGIN { use_ok(Imager => ':all') }
4 use Imager::Test qw(diff_text_with_nul);
55 ++$|;
66
77 init_log("testout/t37w32font.log",1);
88
99 SKIP:
1010 {
11 i_has_format('w32') or skip("no MS Windows", 31);
11 i_has_format('w32') or skip("no MS Windows", 53);
1212 print "# has w32\n";
1313
1414 my $fontname=$ENV{'TTFONTTEST'} || 'Times New Roman Bold';
6565
6666 SKIP:
6767 {
68 $^O eq 'cygwin' and skip("Too hard to get correct directory for test font on cygwin", 11);
68 $^O eq 'cygwin' and skip("Too hard to get correct directory for test font on cygwin", 13);
6969 ok(Imager::i_wf_addfont("fontfiles/ExistenceTest.ttf"), "add test font")
7070 or print "# ",Imager::_error_as_msg(),"\n";
7171
8686 "check display width (roughly)");
8787
8888 my $im = Imager->new(xsize=>200, ysize=>200);
89 $im->string(font=>$namefont, text=>"/", x=>20, y=>100, color=>'white', size=>100);
89 $im->box(filled => 1, color => '#202020');
90 $im->box(box => [ 20 + $bbox->neg_width, 100-$bbox->ascent,
91 20+$bbox->advance_width-$bbox->right_bearing, 100-$bbox->descent ],
92 color => '#101010', filled => 1);
9093 $im->line(color=>'blue', x1=>20, y1=>0, x2=>20, y2=>199);
9194 my $right = 20 + $bbox->advance_width;
9295 $im->line(color=>'blue', x1=>$right, y1=>0, x2=>$right, y2=>199);
96 $im->line(color=>'blue', x1=>0, y1 => 100, x2=>199, y2 => 100);
97 ok($im->string(font=>$namefont, text=>"/", x=>20, y=>100, color=>'white', size=>100),
98 "draw / from ExistenceText")
99 or print "# ", $im->errstr, "\n";
100 $im->setpixel(x => 20+$bbox->neg_width, y => 100-$bbox->ascent, color => 'red');
101 $im->setpixel(x => 20+$bbox->advance_width - $bbox->right_bearing, y => 100-$bbox->descent, color => 'red');
93102 $im->write(file=>'testout/t37w32_slash.ppm');
94103
95104 # check with a char that fits inside the box
102111 cmp_ok($bbox->right_bearing, '>', 0, "right bearing positive");
103112 cmp_ok($bbox->display_width, '<', $bbox->advance_width,
104113 "display smaller than advance");
114
115 $im = Imager->new(xsize=>200, ysize=>200);
116 $im->box(filled => 1, color => '#202020');
117 $im->box(box => [ 20 + $bbox->neg_width, 100-$bbox->ascent,
118 20+$bbox->advance_width-$bbox->right_bearing, 100-$bbox->descent ],
119 color => '#101010', filled => 1);
120 $im->line(color=>'blue', x1=>20, y1=>0, x2=>20, y2=>199);
121 $right = 20 + $bbox->advance_width;
122 $im->line(color=>'blue', x1=>$right, y1=>0, x2=>$right, y2=>199);
123 $im->line(color=>'blue', x1=>0, y1 => 100, x2=>199, y2 => 100);
124 ok($im->string(font=>$namefont, text=>"!", x=>20, y=>100, color=>'white', size=>100),
125 "draw / from ExistenceText")
126 or print "# ", $im->errstr, "\n";
127 $im->setpixel(x => 20+$bbox->neg_width, y => 100-$bbox->ascent, color => 'red');
128 $im->setpixel(x => 20+$bbox->advance_width - $bbox->right_bearing, y => 100-$bbox->descent, color => 'red');
129 $im->write(file=>'testout/t37w32_bang.ppm');
105130 }
106131
107132 SKIP:
129154 }
130155 ok($im->write(file=>'testout/t37align.ppm'), "save align image");
131156 }
132
157 { print "# utf 8 support\n";
158 my $font = Imager::Font->new(face => "Arial");
159 ok($font, "created font");
160 my $im = Imager->new(xsize => 100, ysize => 100);
161 ok($im->string(string => "\xE2\x98\xBA", size => 80, aa => 1, utf8 => 1,
162 color => "white", font => $font, x => 5, y => 80),
163 "draw in utf8 (hand encoded)")
164 or print "# ", $im->errstr, "\n";
165 ok($im->write(file=>'testout/t37utf8.ppm'), "save utf8 image");
166
167 # native perl utf8
168 # Win32 only supported on 5.6+
169 # since this gets compiled even on older perls we need to be careful
170 # creating the string
171 my $text;
172 eval q{$text = "\x{263A}"}; # A, HYPHEN, A in our test font
173 my $im2 = Imager->new(xsize => 100, ysize => 100);
174 ok($im2->string(string => $text, size => 80, aa => 1,
175 color => 'white', font => $font, x => 5, y => 80),
176 "draw in utf8 (perl utf8)")
177 or print "# ", $im->errstr, "\n";
178 ok($im2->write(file=>'testout/t37utf8b.ppm'), "save utf8 image");
179 is(Imager::i_img_diff($im->{IMG}, $im2->{IMG}), 0,
180 "check result is the same");
181
182 # bounding box
183 cmp_ok($font->bounding_box(string=>$text, size => 80)->advance_width, '<', 100,
184 "check we only get width of single char rather than 3");
185 }
186
187 { # string output cut off at NUL ('\0')
188 # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd
189 my $font = Imager::Font->new(face=>'Arial', type=>'w32');
190 ok($font, "loaded Arial");
191
192 diff_text_with_nul("a\\0b vs a", "a\0b - color", "a",
193 font => $font, color => '#FFFFFF');
194 diff_text_with_nul("a\\0b vs a", "a\0b - channel", "a",
195 font => $font, channel => 1);
196
197 # UTF8 encoded \x{2010}
198 my $dash = pack("C*", 0xE2, 0x80, 0x90);
199 diff_text_with_nul("utf8 dash\0dash vs dash - color", "$dash\0$dash", $dash,
200 font => $font, color => '#FFFFFF', utf8 => 1);
201 diff_text_with_nul("utf8 dash\0dash vs dash - channel", "$dash\0$dash", $dash,
202 font => $font, channel => 1, utf8 => 1);
203 }
133204 }
00 #!perl -w
11 use strict;
2 use lib 't';
3 use Test::More tests => 160;
2 use Test::More tests => 182;
43 ++$|;
54 # Before `make install' is performed this script should be runnable with
65 # `make test'. After `make install' it should work as `perl test.pl'
1211
1312 BEGIN { use_ok(Imager => ':all') }
1413
14 use Imager::Test qw(diff_text_with_nul is_color3);
15
1516 init_log("testout/t38ft2font.log",2);
1617
1718 my @base_color = (64, 255, 64);
1819
1920 SKIP:
2021 {
21 i_has_format("ft2") or skip("no freetype2 library found", 159);
22 i_has_format("ft2") or skip("no freetype2 library found", 181);
2223
2324 print "# has ft2\n";
2425
2526 my $fontname=$ENV{'TTFONTTEST'}||'./fontfiles/dodge.ttf';
2627
27 -f $fontname or skip("cannot find fontfile $fontname", 159);
28 -f $fontname or skip("cannot find fontfile $fontname", 181);
2829
2930
3031 my $bgcolor=i_color_new(255,0,0,0);
181182 ok(@got == 2, "has_chars returned 2 items");
182183 ok(!$got[0], "have no chr(1)");
183184 ok($got[1], "have 'H'");
184 ok($oof->has_chars(string=>"H\x01") eq "\x01\x00",
185 is($oof->has_chars(string=>"H\x01"), "\x01\x00",
185186 "scalar has_chars()");
186187
187188 print "# OO bounding boxes\n";
253254 if (Imager::Font::FreeType2::i_ft2_can_face_name()) {
254255 my $facename = Imager::Font::FreeType2::i_ft2_face_name($exfont->{id});
255256 print "# face name '$facename'\n";
256 ok($facename eq 'ExistenceTest', "test face name");
257 is($facename, 'ExistenceTest', "test face name");
257258 $facename = $exfont->face_name;
258 ok($facename eq 'ExistenceTest', "test face name OO");
259 is($facename, 'ExistenceTest', "test face name OO");
259260 }
260261 else {
261262 # make sure we get the error we expect
411412 channel => 0, size => 8, font => $font),
412413 "draw space non-antialiased (channel)");
413414 }
415
416 { # cannot output "0"
417 # https://rt.cpan.org/Ticket/Display.html?id=21770
418 my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
419 ok($font, "loaded imugly");
420 my $imbase = Imager->new(xsize => 100, ysize => 100);
421 my $im = $imbase->copy;
422 ok($im->string(x => 10, y => 50, string => "0", aa => 0,
423 color => '#FFF', size => 20, font => $font),
424 "draw '0'");
425 ok(Imager::i_img_diff($im->{IMG}, $imbase->{IMG}),
426 "make sure we actually drew it");
427 $im = $imbase->copy;
428 ok($im->string(x => 10, y => 50, string => 0.0, aa => 0,
429 color => '#FFF', size => 20, font => $font),
430 "draw 0.0");
431 ok(Imager::i_img_diff($im->{IMG}, $imbase->{IMG}),
432 "make sure we actually drew it");
433 }
434 { # string output cut off at NUL ('\0')
435 # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd
436 my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
437 ok($font, "loaded imugly");
438
439 diff_text_with_nul("a\\0b vs a", "a\0b", "a",
440 font => $font, color => '#FFFFFF');
441 diff_text_with_nul("a\\0b vs a", "a\0b", "a",
442 font => $font, channel => 1);
443
444 # UTF8 encoded \x{2010}
445 my $dash = pack("C*", 0xE2, 0x80, 0x90);
446 diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash,
447 font => $font, color => '#FFFFFF', utf8 => 1);
448 diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash,
449 font => $font, channel => 1, utf8 => 1);
450 }
451
452 { # RT 11972
453 # when rendering to a transparent image the coverage should be
454 # expressed in terms of the alpha channel rather than the color
455 my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
456 my $im = Imager->new(xsize => 40, ysize => 20, channels => 4);
457 ok($im->string(string => "AB", size => 20, aa => 1, color => '#F00',
458 x => 0, y => 15, font => $font),
459 "draw to transparent image");
460 $im->write(file => "foo.png");
461 my $im_noalpha = $im->convert(preset => 'noalpha');
462 my $im_pal = $im->to_paletted(make_colors => 'mediancut');
463 my @colors = $im_pal->getcolors;
464 is(@colors, 2, "should be only 2 colors");
465 @colors = sort { ($a->rgba)[0] <=> ($b->rgba)[0] } @colors;
466 is_color3($colors[0], 0, 0, 0, "check we got black");
467 is_color3($colors[1], 255, 0, 0, "and red");
468 }
414469 }
415470
416471 sub align_test {
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 223;
43
54 BEGIN { use_ok(Imager=>':all') }
00 #!perl -w
1 BEGIN { $| = 1; print "1..16\n"; }
2 END {print "not ok 1\n" unless $loaded;}
3 use Imager;
4
5 sub ok($$);
6 sub is($$$);
7 my $num = 1;
8
9 $loaded = 1;
10 ok(1, "loaded");
11
12 #$Imager::DEBUG=1;
1 use strict;
2 use Test::More tests => 16;
3 BEGIN { use_ok('Imager'); }
134
145 Imager::init('log'=>'testout/t58trans2.log');
156
10394 ok(!$im7, "expected failure on accessing invalid image");
10495 print "# ", Imager->errstr, "\n";
10596 ok(Imager->errstr =~ /not enough images/, "didn't get expected error");
106
107
108 sub ok ($$) {
109 my ($test, $desc) = @_;
110
111 if ($test) {
112 print "ok $num # $desc\n";
113 }
114 else {
115 print "not ok $num # $desc\n";
116 }
117 ++$num;
118 $test;
119 }
120
121 sub is ($$$) {
122 my ($left, $right, $desc) = @_;
123
124 my $eq = $left == $right;
125 unless (ok($eq, $desc)) {
126 $left =~ s/\n/# \n/g;
127 $left =~ s/([^\n\x20-\x7E])/"\\x".sprintf("%02X", ord $1)/ge;
128 $right =~ s/\n/# \n/g;
129 $right =~ s/([^\n\x20-\x7E])/"\\x".sprintf("%02X", ord $1)/ge;
130 print "# not equal, left = '$left'\n";
131 print "# right = '$right'\n";
132 }
133 $eq;
134 }
00 #!perl -w
11 use strict;
22 use Imager qw(:handy);
3 use lib 't';
43 use Test::More tests => 66;
54 Imager::init_log("testout/t61filters.log", 1);
65 # meant for testing the filters themselves
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 61;
43 use Imager;
54
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 60;
43 require "t/testtools.pl";
54 use Imager;
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 23;
43
54 BEGIN { use_ok("Imager") }
00 #!perl -w
11 use strict;
22 use Imager qw(:all :handy);
3 use lib 't';
43 use Test::More tests=>19;
54
65 Imager::init("log"=>'testout/t67convert.log');
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More tests => 38;
43 BEGIN { use_ok(Imager => qw(:all :handy)); }
54
0 #!perl -w
01 use strict;
1 my $loaded;
2 BEGIN {
3 require "t/testtools.pl";
4 $| = 1; print "1..11\n";
5 }
6 END { okx(0, "loading") unless $loaded; }
7 use Imager;
8 $loaded = 1;
2 use Test::More tests => 11;
93
10 okx(1, "Loaded");
4 BEGIN { use_ok('Imager') }
115
12 requireokx("Imager/Font/Wrap.pm", "load basic wrapping");
6 require_ok('Imager::Font::Wrap');
137
148 my $img = Imager->new(xsize=>400, ysize=>400);
159
3933
4034 my $font = Imager::Font->new(file=>$fontfile);
4135
42 unless (Imager::i_has_format('tt') || Imager::i_has_format('ft2')) {
43 skipx(9, "Need Freetype 1.x or 2.x to test");
44 exit;
45 }
36 SKIP:
37 {
38 Imager::i_has_format('tt') || Imager::i_has_format('ft2')
39 or skip("Need Freetype 1.x or 2.x to test", 9);
4640
47 if (okx($font, "loading font")) {
41 ok($font, "loading font")
42 or skip("Could not load test font", 8);
43
4844 Imager::Font->priorities(qw(t1 ft2 tt));
49 okx(scalar Imager::Font::Wrap->wrap_text(string => $text,
45 ok(scalar Imager::Font::Wrap->wrap_text(string => $text,
5046 font=>$font,
5147 image=>$img,
5248 size=>13,
5551 justify=>'fill',
5652 color=>'FFFFFF'),
5753 "basic test");
58 okx($img->write(file=>'testout/t80wrapped.ppm'), "save to file");
59 okx(scalar Imager::Font::Wrap->wrap_text(string => $text,
54 ok($img->write(file=>'testout/t80wrapped.ppm'), "save to file");
55 ok(scalar Imager::Font::Wrap->wrap_text(string => $text,
6056 font=>$font,
6157 image=>undef,
6258 size=>13,
6662 color=>'FFFFFF'),
6763 "no image test");
6864 my $bbox = $font->bounding_box(string=>"Xx", size=>13);
69 okx($bbox, "get height for check");
65 ok($bbox, "get height for check");
7066
7167 my $used;
72 okx(scalar Imager::Font::Wrap->wrap_text
68 ok(scalar Imager::Font::Wrap->wrap_text
7369 (string=>$text, font=>$font, image=>undef, size=>13, width=>380,
7470 savepos=> \$used, height => $bbox->font_height), "savepos call");
75 okx($used > 20 && $used < length($text), "savepos value");
71 ok($used > 20 && $used < length($text), "savepos value");
7672 print "# $used\n";
7773 my @box = Imager::Font::Wrap->wrap_text
7874 (string=>substr($text, 0, $used), font=>$font, image=>undef, size=>13,
7975 width=>380);
8076
81 okx(@box == 4, "bounds list count");
77 ok(@box == 4, "bounds list count");
8278 print "# @box\n";
83 okx($box[3] == $bbox->font_height, "check height");
79 ok($box[3] == $bbox->font_height, "check height");
8480 }
85 else {
86 skipx(8, "Could not load test font");
87 }
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More;
43 use Imager;
54
11 #
22 # this tests both the Inline interface and the API
33 use strict;
4 use lib 't';
54 use Test::More;
65 eval "require Inline::C;";
76 plan skip_all => "Inline required for testing API" if $@;
109 plan skip_all => "Inline won't work in directories with spaces"
1110 if getcwd() =~ / /;
1211
13 plan tests => 8;
12 plan tests => 9;
1413 require Inline;
1514 Inline->import(with => 'Imager');
1615
244243 ok($im3, "do_lots()")
245244 or print "# ", Imager->_error_as_msg, "\n";
246245 ok($im3->write(file=>'testout/t82lots.ppm'), "write t82lots.ppm");
246
247 { # RT #24992
248 # the T_IMAGER_FULL_IMAGE typemap entry was returning a blessed
249 # hash with an extra ref, causing memory leaks
250
251 my $im = make_10x10();
252 my $im2 = Imager->new(xsize => 10, ysize => 10);
253 use B;
254 my $imb = B::svref_2object($im);
255 my $im2b = B::svref_2object($im2);
256 is ($imb->REFCNT, $im2b->REFCNT,
257 "check refcnt of imager object hash between normal and typemap generated");
258 }
00 #!perl -w
11 use strict;
2 use lib 't';
32 use Test::More;
43 use ExtUtils::Manifest qw(maniread);
54 eval "use Test::Pod 1.00;";
00 #!perl -w
11 # packaging test - make sure we included the samples in the MANIFEST <sigh>
2 use lib 't';
32 use Test::More;
43 use ExtUtils::Manifest qw(maniread);
54
00 #!perl -w
11 # this is intended for various kwalitee tests
2 use lib 't';
32 use strict;
43 use Test::More;
54 use ExtUtils::Manifest qw(maniread);
2828 $img;
2929 }
3030
31 sub skipn {
32 my ($testnum, $count, $why) = @_;
33
34 $why = '' unless defined $why;
35
36 print "ok $_ # skip $why\n" for $testnum ... $testnum+$count-1;
37 }
38
39 sub skipx {
40 my ($count, $why) = @_;
41
42 skipn($TESTNUM, $count, $why);
43 $TESTNUM += $count;
44 }
45
46 sub okx ($$) {
47 my ($ok, $comment) = @_;
48
49 return okn($TESTNUM++, $ok, $comment);
50 }
51
52 sub okn ($$$) {
53 my ($num, $ok, $comment) = @_;
54
55 defined $num or confess "No \$num supplied";
56 defined $comment or confess "No \$comment supplied";
57 if ($ok) {
58 print "ok $num # $comment\n";
59 }
60 else {
61 print "not ok $num # $comment\n";
62 }
63
64 return $ok;
65 }
66
67 sub requireokx {
68 my ($file, $comment) = @_;
69
70 eval {
71 require $file;
72 };
73 if ($@) {
74 my $msg = $@;
75 $msg =~ s/\n+$//;
76 $msg =~ s/\n/\n# /g;
77 okx(0, $comment);
78 print "# $msg\n";
79 }
80 else {
81 okx(1, $comment);
82 }
83 }
84
85 sub useokx {
86 my ($module, $comment, @imports) = @_;
87
88 my $pack = caller;
89 eval <<EOS;
90 package $pack;
91 require $module;
92 $module->import(\@imports);
93 EOS
94 unless (okx(!$@, $comment)) {
95 my $msg = $@;
96 $msg =~ s/\n+$//;
97 $msg =~ s/\n/\n# /g;
98 print "# $msg\n";
99 return 0;
100 }
101 else {
102 return 1;
103 }
104 }
105
106 sub matchn($$$$) {
107 my ($num, $str, $re, $comment) = @_;
108
109 my $match = defined($str) && $str =~ $re;
110 okn($num, $match, $comment);
111 unless ($match) {
112 print "# The value: ",_sv_str($str),"\n";
113 print "# did not match: qr/$re/\n";
114 }
115 return $match;
116 }
117
118 sub matchx($$$) {
119 my ($str, $re, $comment) = @_;
120
121 matchn($TESTNUM++, $str, $re, $comment);
122 }
123
124 sub isn ($$$$) {
125 my ($num, $left, $right, $comment) = @_;
126
127 my $match;
128 if (!defined $left && defined $right
129 || defined $left && !defined $right) {
130 $match = 0;
131 }
132 elsif (!defined $left && !defined $right) {
133 $match = 1;
134 }
135 # the right of the || produces a string of \0 if $left is a PV
136 # which is true
137 elsif (!length $left || ($left & ~$left) ||
138 !length $right || ($right & ~$right)) {
139 $match = $left eq $right;
140 }
141 else {
142 $match = $left == $right;
143 }
144 okn($num, $match, $comment);
145 unless ($match) {
146 print "# the following two values were not equal:\n";
147 print "# value: ",_sv_str($left),"\n";
148 print "# other: ",_sv_str($right),"\n";
149 }
150
151 $match;
152 }
153
154 sub isx ($$$) {
155 my ($left, $right, $comment) = @_;
156
157 isn($TESTNUM++, $left, $right, $comment);
158 }
15931
16032 sub _sv_str {
16133 my ($value) = @_;
11 # regression test for RT issue 18561
22 #
33 use strict;
4 use lib 't';
54 use Test::More tests => 1;
65 eval {
76 use Imager;
22 # the old _color() code could return floating colors in some cases
33 # but in most cases the caller couldn't handle it
44 use strict;
5 use lib 't';
65 use Test::More tests => 1;
76 eval {
87 use Imager;
0 P1
1 2 2
2 10
3 0x
0 P2
1 2 2
2 255
3 255 255
4 255 x
0 P3
1 2 2
2 255
3 255 255 255 255 255 255
4 255 255 x
Binary diff not shown
0 P5
1 # CREATOR: The GIMP's PNM Filter Version 1.0
2 2 2
3 255
4 şıüû
0 P1
1 2 2
2 01
3 1
0 P2
1 2 2
2 255
3 255 255
4 255
0 P3
1 2 2
2 255
3 255 255 255 255 255 255
4 255 255 255
0 P4
1 16 2
2 ú€þ
0 P5
1 # CREATOR: The GIMP's PNM Filter Version 1.0
2 2 2
3 255
4 ÿÿÿ
0 P6
1 # CREATOR: The GIMP's PNM Filter Version 1.0
2 2 2
3 255
4 ÿÿÿÿÿÿÿÿÿ
0 P5
1 # CREATOR: The GIMP's PNM Filter Version 1.0
2 2 2
3 65535
4 ÿÿÿÿÿÿ
0 P6
1 # CREATOR: The GIMP's PNM Filter Version 1.0
2 2 2
3 65535
4 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
731731 mapped = 0;
732732 channels = 1;
733733 break;
734 default:
735 i_push_error(0, "invalid or unsupported datatype code");
736 return NULL;
734737 }
735738
736739 if (!i_int_check_image_file_limits(width, height, channels,
150150 /* do nothing */
151151 }
152152
153 static i_img *read_one_tiff(TIFF *tif) {
153 static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
154154 i_img *im;
155155 uint32 width, height;
156156 uint16 channels;
295295 ++row;
296296 }
297297 if (row < height) {
298 if (allow_incomplete) {
299 i_tags_setn(&im->tags, "i_lines_read", row);
300 }
301 else {
302 i_img_destroy(im);
303 _TIFFfree(buffer);
304 return NULL;
305 }
298306 error = 1;
299307 }
300308 /* Ideally we'd optimize the palette, but that could be expensive
381389 uint32 newrows, i_row;
382390
383391 if (!TIFFReadRGBAStrip(tif, row, raster)) {
384 error++;
385 break;
392 if (allow_incomplete) {
393 i_tags_setn(&im->tags, "i_lines_read", row);
394 error++;
395 break;
396 }
397 else {
398 i_push_error(0, "could not read TIFF image strip");
399 _TIFFfree(raster);
400 i_img_destroy(im);
401 return NULL;
402 }
386403 }
387404
388405 newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
405422 }
406423 if (error) {
407424 mm_log((1, "i_readtiff_wiol: error during reading\n"));
408 i_tags_addn(&im->tags, "i_incomplete", 0, 1);
425 i_tags_setn(&im->tags, "i_incomplete", 1);
409426 }
410427 if (raster)
411428 _TIFFfree( raster );
419436 =cut
420437 */
421438 i_img*
422 i_readtiff_wiol(io_glue *ig, int length, int page) {
439 i_readtiff_wiol(io_glue *ig, int allow_incomplete, int page) {
423440 TIFF* tif;
424441 TIFFErrorHandler old_handler;
425442 TIFFErrorHandler old_warn_handler;
435452 /* Also add code to check for mmapped code */
436453
437454 io_glue_commit_types(ig);
438 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
455 mm_log((1, "i_readtiff_wiol(ig %p, allow_incomplete %d, page %d)\n", ig, allow_incomplete, page));
439456
440457 tif = TIFFClientOpen("(Iolayer)",
441458 "rm",
467484 }
468485 }
469486
470 im = read_one_tiff(tif);
487 im = read_one_tiff(tif, allow_incomplete);
471488
472489 if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
473490 TIFFSetErrorHandler(old_handler);
525542
526543 *count = 0;
527544 do {
528 i_img *im = read_one_tiff(tif);
545 i_img *im = read_one_tiff(tif, 0);
529546 if (!im)
530547 break;
531548 if (++*count > result_alloc) {
108108 if ($var) {
109109 SV *imobj = NEWSV(0, 0);
110110 HV *hv = newHV();
111 SV *hvref;
112 SV *imgref;
113111 sv_setref_pv(imobj, \"Imager::ImgRaw\", $var);
114112 hv_store(hv, "IMG", 3, imobj, 0);
115 $arg = sv_2mortal(sv_bless(newRV((SV*)hv), gv_stashpv("Imager", 1)));
113 $arg = sv_2mortal(sv_bless(newRV_noinc((SV*)hv), gv_stashpv("Imager", 1)));
116114 }
117115 else {
118116 $arg = &PL_sv_undef;
1313 if (i_wf_bbox(facename, size, text, text_len, bbox)) {
1414 // we have the bbox
1515 }
16 i_wf_text(face, im, tx, ty, cl, size, text, len, align, aa);
17 i_wf_cp(face, im, tx, ty, channel, size, text, len, align, aa)
16 i_wf_text(face, im, tx, ty, cl, size, text, len, align, aa, utf8);
17 i_wf_cp(face, im, tx, ty, channel, size, text, len, align, aa, utf8)
1818
1919 =head1 DESCRIPTION
2020
3030 static void set_logfont(const char *face, int size, LOGFONT *lf);
3131
3232 static LPVOID render_text(const char *face, int size, const char *text, int length, int aa,
33 HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm);
34
35 /*
36 =item i_wf_bbox(face, size, text, length, bbox)
33 HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm, int *bbox, int utf8);
34 static LPWSTR utf8_to_wide_string(char const *text, int text_len, int *wide_chars);
35
36 /*
37 =item i_wf_bbox(face, size, text, length, bbox, utf8)
3738
3839 Calculate a bounding box for the text.
3940
4041 =cut
4142 */
4243
43 int i_wf_bbox(const char *face, int size, const char *text, int length, int *bbox) {
44 int i_wf_bbox(const char *face, int size, const char *text, int length, int *bbox,
45 int utf8) {
4446 LOGFONT lf;
4547 HFONT font, oldFont;
4648 HDC dc;
4850 TEXTMETRIC tm;
4951 ABC first, last;
5052 GLYPHMETRICS gm;
51 int i;
5253 MAT2 mat;
5354 int ascent, descent, max_ascent = -size, min_descent = size;
54
55 mm_log((1, "i_wf_bbox(face %s, size %d, text %p, length %d, bbox %p)\n", face, size, text, length, bbox));
55 const char *workp;
56 int work_len;
57 int got_first_ch = 0;
58 unsigned long first_ch, last_ch;
59
60 mm_log((1, "i_wf_bbox(face %s, size %d, text %p, length %d, bbox %p, utf8 %d)\n", face, size, text, length, bbox, utf8));
5661
5762 set_logfont(face, size, &lf);
5863 font = CreateFontIndirect(&lf);
6873 }
6974 }
7075
71 for (i = 0; i < length; ++i) {
72 unsigned char c = text[i];
73 unsigned char cp = c > '~' ? '.' : c < ' ' ? '.' : c;
76 workp = text;
77 work_len = length;
78 while (work_len > 0) {
79 unsigned long c;
80 unsigned char cp;
81
82 if (utf8) {
83 c = i_utf8_advance(&workp, &work_len);
84 if (c == ~0UL) {
85 i_push_error(0, "invalid UTF8 character");
86 return 0;
87 }
88 }
89 else {
90 c = (unsigned char)*workp++;
91 --work_len;
92 }
93 if (!got_first_ch) {
94 first_ch = c;
95 ++got_first_ch;
96 }
97 last_ch = c;
98
99 cp = c > '~' ? '.' : c < ' ' ? '.' : c;
74100
75101 memset(&mat, 0, sizeof(mat));
76102 mat.eM11.value = 1;
77103 mat.eM22.value = 1;
78 if (GetGlyphOutline(dc, c, GGO_METRICS, &gm, 0, NULL, &mat) != GDI_ERROR) {
104 if (GetGlyphOutline(dc, (UINT)c, GGO_METRICS, &gm, 0, NULL, &mat) != GDI_ERROR) {
79105 mm_log((2, " glyph '%c' (%02x): bbx (%u,%u) org (%d,%d) inc(%d,%d)\n",
80106 cp, c, gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmptGlyphOrigin.x,
81107 gm.gmptGlyphOrigin.y, gm.gmCellIncX, gm.gmCellIncY));
90116 }
91117 }
92118
93 if (!GetTextExtentPoint32(dc, text, length, &sz)
94 || !GetTextMetrics(dc, &tm)) {
95 SelectObject(dc, oldFont);
96 ReleaseDC(NULL, dc);
97 DeleteObject(font);
98 return 0;
99 }
100 bbox[BBOX_GLOBAL_DESCENT] = tm.tmDescent;
101 bbox[BBOX_DESCENT] = min_descent == size ? tm.tmDescent : min_descent;
119 if (utf8) {
120 int wide_chars;
121 LPWSTR wide_text = utf8_to_wide_string(text, length, &wide_chars);
122
123 if (!wide_text)
124 return 0;
125
126 if (!GetTextExtentPoint32W(dc, wide_text, wide_chars, &sz)
127 || !GetTextMetrics(dc, &tm)) {
128 SelectObject(dc, oldFont);
129 ReleaseDC(NULL, dc);
130 DeleteObject(font);
131 return 0;
132 }
133
134 myfree(wide_text);
135 }
136 else {
137 if (!GetTextExtentPoint32(dc, text, length, &sz)
138 || !GetTextMetrics(dc, &tm)) {
139 SelectObject(dc, oldFont);
140 ReleaseDC(NULL, dc);
141 DeleteObject(font);
142 return 0;
143 }
144 }
145 bbox[BBOX_GLOBAL_DESCENT] = -tm.tmDescent;
146 bbox[BBOX_DESCENT] = min_descent == size ? -tm.tmDescent : min_descent;
102147 bbox[BBOX_POS_WIDTH] = sz.cx;
103148 bbox[BBOX_ADVANCE_WIDTH] = sz.cx;
104149 bbox[BBOX_GLOBAL_ASCENT] = tm.tmAscent;
105150 bbox[BBOX_ASCENT] = max_ascent == -size ? tm.tmAscent : max_ascent;
106151
107152 if (length
108 && GetCharABCWidths(dc, text[0], text[0], &first)
109 && GetCharABCWidths(dc, text[length-1], text[length-1], &last)) {
110 mm_log((1, "first: %d A: %d B: %d C: %d\n", text[0],
153 && GetCharABCWidths(dc, first_ch, first_ch, &first)
154 && GetCharABCWidths(dc, last_ch, last_ch, &last)) {
155 mm_log((1, "first: %d A: %d B: %d C: %d\n", first_ch,
111156 first.abcA, first.abcB, first.abcC));
112 mm_log((1, "last: %d A: %d B: %d C: %d\n", text[length-1],
157 mm_log((1, "last: %d A: %d B: %d C: %d\n", last_ch,
113158 last.abcA, last.abcB, last.abcC));
114159 bbox[BBOX_NEG_WIDTH] = first.abcA;
115160 bbox[BBOX_RIGHT_BEARING] = last.abcC;
140185
141186 int
142187 i_wf_text(const char *face, i_img *im, int tx, int ty, const i_color *cl, int size,
143 const char *text, int len, int align, int aa) {
188 const char *text, int len, int align, int aa, int utf8) {
144189 unsigned char *bits;
145190 HBITMAP bm;
146191 SIZE sz;
149194 int ch;
150195 TEXTMETRIC tm;
151196 int top;
152
153 bits = render_text(face, size, text, len, aa, &bm, &sz, &tm);
197 int bbox[BOUNDING_BOX_COUNT];
198
199 mm_log((1, "i_wf_text(face %s, im %p, tx %d, ty %d, cl %p, size %d, text %p, length %d, align %d, aa %d, utf8 %d)\n", face, im, tx, ty, cl, size, text, len, align, aa, aa, utf8));
200
201 if (!i_wf_bbox(face, size, text, len, bbox, utf8))
202 return 0;
203
204 bits = render_text(face, size, text, len, aa, &bm, &sz, &tm, bbox, utf8);
154205 if (!bits)
155206 return 0;
156207
208 tx += bbox[BBOX_NEG_WIDTH];
157209 line_width = sz.cx * 3;
158210 line_width = (line_width + 3) / 4 * 4;
159211 top = ty;
161213 top -= tm.tmAscent;
162214 }
163215 else {
164 int bbox[BOUNDING_BOX_COUNT];
165
166 i_wf_bbox(face, size, text, len, bbox);
167216 top -= tm.tmAscent - bbox[BBOX_ASCENT];
168217 }
169218
195244
196245 int
197246 i_wf_cp(const char *face, i_img *im, int tx, int ty, int channel, int size,
198 const char *text, int len, int align, int aa) {
247 const char *text, int len, int align, int aa, int utf8) {
199248 unsigned char *bits;
200249 HBITMAP bm;
201250 SIZE sz;
203252 int x, y;
204253 TEXTMETRIC tm;
205254 int top;
206
207 bits = render_text(face, size, text, len, aa, &bm, &sz, &tm);
255 int bbox[BOUNDING_BOX_COUNT];
256
257 mm_log((1, "i_wf_cp(face %s, im %p, tx %d, ty %d, channel %d, size %d, text %p, length %d, align %d, aa %d, utf8 %d)\n", face, im, tx, ty, channel, size, text, len, align, aa, aa, utf8));
258
259 if (!i_wf_bbox(face, size, text, len, bbox, utf8))
260 return 0;
261
262 bits = render_text(face, size, text, len, aa, &bm, &sz, &tm, bbox, utf8);
208263 if (!bits)
209264 return 0;
210265
215270 top -= tm.tmAscent;
216271 }
217272 else {
218 int bbox[BOUNDING_BOX_COUNT];
219
220 i_wf_bbox(face, size, text, len, bbox);
221273 top -= tm.tmAscent - bbox[BBOX_ASCENT];
222274 }
223275
295347 =cut
296348 */
297349 static LPVOID render_text(const char *face, int size, const char *text, int length, int aa,
298 HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm) {
350 HBITMAP *pbm, SIZE *psz, TEXTMETRIC *tm, int *bbox, int utf8) {
299351 BITMAPINFO bmi;
300352 BITMAPINFOHEADER *bmih = &bmi.bmiHeader;
301353 HDC dc, bmpDc;
304356 SIZE sz;
305357 HBITMAP bm, oldBm;
306358 LPVOID bits;
307
359 int wide_count;
360 LPWSTR wide_text;
361
308362 dc = GetDC(NULL);
309363 set_logfont(face, size, &lf);
310364
315369 lf.lfQuality = aa ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY;
316370 #endif
317371
372 if (utf8) {
373 wide_text = utf8_to_wide_string(text, length, &wide_count);
374 }
375 else {
376 wide_text = NULL;
377 }
378
318379 bmpDc = CreateCompatibleDC(dc);
319380 if (bmpDc) {
320381 font = CreateFontIndirect(&lf);
321382 if (font) {
322383 oldFont = SelectObject(bmpDc, font);
323 GetTextExtentPoint32(bmpDc, text, length, &sz);
384
324385 GetTextMetrics(bmpDc, tm);
386 sz.cx = bbox[BBOX_ADVANCE_WIDTH] - bbox[BBOX_NEG_WIDTH] + bbox[BBOX_POS_WIDTH];
387 sz.cy = bbox[BBOX_GLOBAL_ASCENT] - bbox[BBOX_GLOBAL_DESCENT];
325388
326389 memset(&bmi, 0, sizeof(bmi));
327390 bmih->biSize = sizeof(*bmih);
342405 oldBm = SelectObject(bmpDc, bm);
343406 SetTextColor(bmpDc, RGB(255, 255, 255));
344407 SetBkColor(bmpDc, RGB(0, 0, 0));
345 TextOut(bmpDc, 0, 0, text, length);
408 if (utf8) {
409 TextOutW(bmpDc, -bbox[BBOX_NEG_WIDTH], 0, wide_text, wide_count);
410 }
411 else {
412 TextOut(bmpDc, -bbox[BBOX_NEG_WIDTH], 0, text, length);
413 }
346414 SelectObject(bmpDc, oldBm);
347415 }
348416 else {
352420 DeleteObject(font);
353421 DeleteDC(bmpDc);
354422 ReleaseDC(NULL, dc);
423 if (wide_text)
424 myfree(wide_text);
355425 return NULL;
356426 }
357427 SelectObject(bmpDc, oldFont);
358428 DeleteObject(font);
359429 }
360430 else {
431 if (wide_text)
432 myfree(wide_text);
361433 i_push_errorf(0, "Could not create logical font: %ld",
362434 GetLastError());
363435 DeleteDC(bmpDc);
367439 DeleteDC(bmpDc);
368440 }
369441 else {
442 if (wide_text)
443 myfree(wide_text);
370444 i_push_errorf(0, "Could not create rendering DC: %ld", GetLastError());
371445 ReleaseDC(NULL, dc);
372446 return NULL;
373447 }
374448
449 if (wide_text)
450 myfree(wide_text);
451
375452 ReleaseDC(NULL, dc);
376453
377454 *pbm = bm;
381458 }
382459
383460 /*
461 =item utf8_to_wide_string(text, text_len, wide_chars)
462
463 =cut
464 */
465
466 static
467 LPWSTR
468 utf8_to_wide_string(char const *text, int text_len, int *wide_chars) {
469 int wide_count = MultiByteToWideChar(CP_UTF8, 0, text, text_len, NULL, 0);
470 LPWSTR result;
471
472 if (wide_count < 0) {
473 i_push_errorf(0, "Could not convert utf8: %ld", GetLastError());
474 return NULL;
475 }
476 ++wide_count;
477 result = mymalloc(sizeof(WCHAR) * wide_count);
478 if (MultiByteToWideChar(CP_UTF8, 0, text, text_len, result, wide_count) < 0) {
479 i_push_errorf(0, "Could not convert utf8: %ld", GetLastError());
480 return NULL;
481 }
482
483 result[wide_count-1] = (WCHAR)'\0';
484 *wide_chars = wide_count - 1;
485
486 return result;
487 }
488
489
490 /*
491 =back
492
384493 =head1 BUGS
385494
386495 Should really use a structure so we can set more attributes.