]> git.imager.perl.org - imager.git/blob - t/t35ttfont.t
fix formatting and spelling to match the rest
[imager.git] / t / t35ttfont.t
1 #!perl -w
2 use strict;
3 use Test::More tests => 92;
4
5 $|=1;
6
7 BEGIN { use_ok(Imager => ':all') }
8 use Imager::Test qw(diff_text_with_nul is_color3);
9
10 init_log("testout/t35ttfont.log",2);
11
12 SKIP:
13 {
14   skip("freetype 1.x unavailable or disabled", 91) 
15     unless i_has_format("tt");
16   print "# has tt\n";
17   
18   my $deffont = './fontfiles/dodge.ttf';
19   my $fontname=$ENV{'TTFONTTEST'} || $deffont;
20
21   if (!ok(-f $fontname, "check test font file exists")) {
22     print "# cannot find fontfile for truetype test $fontname\n";
23     skip('Cannot load test font', 89);
24   }
25
26   #i_init_fonts();
27   #     i_tt_set_aa(1);
28   
29   my $bgcolor = i_color_new(255,0,0,0);
30   my $overlay = Imager::ImgRaw::new(320,140,3);
31   i_box_filled($overlay, 0, 0, 319, 139, i_color_new(128, 128, 128));
32   
33   my $ttraw = Imager::i_tt_new($fontname);
34   ok($ttraw, "create font");
35
36   my @bbox = i_tt_bbox($ttraw,50.0,'XMCLH',6,0);
37   is(@bbox, 8, "bounding box");
38   print "#bbox: ($bbox[0], $bbox[1]) - ($bbox[2], $bbox[3])\n";
39
40   ok(i_tt_cp($ttraw,$overlay,5,50,1,50.0,'XM CLH',6,1,0), "cp output");
41   ok(i_tt_cp($ttraw,$overlay,5,120,1,50.0,'XM CLH',6,0,0), "cp output (non AA)");
42   i_line($overlay,0,50,100,50,$bgcolor,1);
43
44   open(FH,">testout/t35ttfont.ppm") || die "cannot open testout/t35ttfont.ppm\n";
45   binmode(FH);
46   my $IO = Imager::io_new_fd( fileno(FH) );
47   ok(i_writeppm_wiol($overlay, $IO), "save t35ttfont.ppm");
48   close(FH);
49
50   $bgcolor=i_color_set($bgcolor,200,200,200,0);
51   my $backgr=Imager::ImgRaw::new(500,300,3);
52   
53   #     i_tt_set_aa(2);
54   
55   ok(i_tt_text($ttraw,$backgr,100,120,$bgcolor,50.0,'te st',5,1,0),
56       "normal output");
57   ok(i_tt_text($ttraw,$backgr,100,200,$bgcolor,50.0,'te st',5,0,0),
58       "normal output (non AA)");
59
60   my $ugly = Imager::i_tt_new("./fontfiles/ImUgly.ttf");
61   ok($ugly, "create ugly font");
62   # older versions were dropping the bottom of g and the right of a
63   ok(i_tt_text($ugly, $backgr,100, 80, $bgcolor, 14, 'g%g', 3, 1, 0), 
64      "draw g%g");
65   ok(i_tt_text($ugly, $backgr,150, 80, $bgcolor, 14, 'delta', 6, 1, 0),
66       "draw delta");
67   i_line($backgr,0,20,499,20,i_color_new(0,127,0,0),1);
68   ok(i_tt_text($ttraw, $backgr, 20, 20, $bgcolor, 14, 'abcdefghijklmnopqrstuvwxyz{|}', 29, 1, 0), "alphabet");
69   ok(i_tt_text($ttraw, $backgr, 20, 50, $bgcolor, 14, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 26, 1, 0), "ALPHABET");
70   
71   # UTF8 tests
72   # for perl < 5.6 we can hand-encode text
73   # the following is "A\x{2010}A"
74   # 
75   my $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41);
76   my $alttext = "A-A";
77   
78   my @utf8box = i_tt_bbox($ttraw, 50.0, $text, length($text), 1);
79   is(@utf8box, 8, "utf8 bbox element count");
80   my @base = i_tt_bbox($ttraw, 50.0, $alttext, length($alttext), 0);
81   is(@base, 8, "alt bbox element count");
82   my $maxdiff = $fontname eq $deffont ? 0 : $base[2] / 3;
83   print "# (@utf8box vs @base)\n";
84   ok(abs($utf8box[2] - $base[2]) <= $maxdiff, 
85      "compare box sizes $utf8box[2] vs $base[2] (maxerror $maxdiff)");
86   
87   # hand-encoded UTF8 drawing
88   ok(i_tt_text($ttraw, $backgr, 200, 80, $bgcolor, 14, $text, length($text), 1, 1), "draw hand-encoded UTF8");
89
90   ok(i_tt_cp($ttraw, $backgr, 250, 80, 1, 14, $text, length($text), 1, 1), 
91       "cp hand-encoded UTF8");
92
93   # ok, try native perl UTF8 if available
94  SKIP:
95   {
96     skip("perl too old to test native UTF8 support", 5) unless $] >= 5.006;
97
98     my $text;
99     # we need to do this in eval to prevent compile time errors in older
100     # versions
101     eval q{$text = "A\x{2010}A"}; # A, HYPHEN, A in our test font
102     #$text = "A".chr(0x2010)."A"; # this one works too
103     ok(i_tt_text($ttraw, $backgr, 300, 80, $bgcolor, 14, $text, 0, 1, 0),
104        "draw UTF8");
105     ok(i_tt_cp($ttraw, $backgr, 350, 80, 0, 14, $text, 0, 1, 0),
106        "cp UTF8");
107     @utf8box = i_tt_bbox($ttraw, 50.0, $text, length($text), 0);
108     is(@utf8box, 8, "native utf8 bbox element count");
109     ok(abs($utf8box[2] - $base[2]) <= $maxdiff, 
110        "compare box sizes native $utf8box[2] vs $base[2] (maxerror $maxdiff)");
111     eval q{$text = "A\x{0905}\x{0906}\x{0103}A"}; # Devanagari
112     ok(i_tt_text($ugly, $backgr, 100, 160, $bgcolor, 36, $text, 0, 1, 0),
113        "more complex output");
114   }
115
116   open(FH,">testout/t35ttfont2.ppm") || die "cannot open testout/t35ttfont.ppm\n";
117   binmode(FH);
118   $IO = Imager::io_new_fd( fileno(FH) );
119   ok(i_writeppm_wiol($backgr, $IO), "save t35ttfont2.ppm");
120   close(FH);
121   
122   my $exists_font = "fontfiles/ExistenceTest.ttf";
123   my $hcfont = Imager::Font->new(file=>$exists_font, type=>'tt');
124  SKIP:
125   {
126     ok($hcfont, "loading existence test font")
127       or skip("could not load test font", 20);
128
129     # list interface
130     my @exists = $hcfont->has_chars(string=>'!A');
131     ok(@exists == 2, "check return count");
132     ok($exists[0], "we have an exclamation mark");
133     ok(!$exists[1], "we have no exclamation mark");
134     
135     # scalar interface
136     my $exists = $hcfont->has_chars(string=>'!A');
137     ok(length($exists) == 2, "check return length");
138     ok(ord(substr($exists, 0, 1)), "we have an exclamation mark");
139     ok(!ord(substr($exists, 1, 1)), "we have no upper-case A");
140     
141     my $face_name = Imager::i_tt_face_name($hcfont->{id});
142     print "# face $face_name\n";
143     is($face_name, 'ExistenceTest', "face name (function)");
144     $face_name = $hcfont->face_name;
145     is($face_name, 'ExistenceTest', "face name (OO)");
146     
147     # FT 1.x cheats and gives names even if the font doesn't have them
148     my @glyph_names = $hcfont->glyph_names(string=>"!J/");
149     is($glyph_names[0], 'exclam', "check exclam name OO");
150     ok(!defined($glyph_names[1]), "check for no J name OO");
151     is($glyph_names[2], 'slash', "check slash name OO");
152     
153     print "# ** name table of the test font **\n";
154     Imager::i_tt_dump_names($hcfont->{id});
155
156     # the test font is known to have a shorter advance width for that char
157     my @bbox = $hcfont->bounding_box(string=>"/", size=>100);
158     is(@bbox, 8, "should be 8 entries");
159     isnt($bbox[6], $bbox[2], "different advance width from pos width");
160     print "# @bbox\n";
161     my $bbox = $hcfont->bounding_box(string=>"/", size=>100);
162     isnt($bbox->pos_width, $bbox->advance_width, "OO check");
163
164     cmp_ok($bbox->right_bearing, '<', 0, "check right bearing");
165
166     cmp_ok($bbox->display_width, '>', $bbox->advance_width,
167            "check display width (roughly)");
168
169     # check with a char that fits inside the box
170     $bbox = $hcfont->bounding_box(string=>"!", size=>100);
171     print "# @$bbox\n";
172     print "# pos width ", $bbox->pos_width, "\n";
173     is($bbox->pos_width, $bbox->advance_width, 
174        "check backwards compatibility");
175     cmp_ok($bbox->left_bearing, '>', 0, "left bearing positive");
176     cmp_ok($bbox->right_bearing, '>', 0, "right bearing positive");
177     cmp_ok($bbox->display_width, '<', $bbox->advance_width,
178            "display smaller than advance");
179   }
180   undef $hcfont;
181   
182   my $name_font = "fontfiles/NameTest.ttf";
183   $hcfont = Imager::Font->new(file=>$name_font, type=>'tt');
184  SKIP:
185   {
186     ok($hcfont, "loading name font")
187       or skip("could not load name font $name_font", 3);
188     # make sure a missing string parameter is handled correctly
189     eval {
190       $hcfont->glyph_names();
191     };
192     is($@, "", "correct error handling");
193     cmp_ok(Imager->errstr, '=~', qr/no string parameter/, "error message");
194     
195     my $text = pack("C*", 0xE2, 0x80, 0x90); # "\x{2010}" as utf-8
196     my @names = $hcfont->glyph_names(string=>$text, utf8=>1);
197     is($names[0], "hyphentwo", "check utf8 glyph name");
198   }
199
200   undef $hcfont;
201   
202  SKIP:
203   { print "# alignment tests\n";
204     my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt');
205     ok($font, "loaded deffont OO")
206       or skip("could not load font:".Imager->errstr, 4);
207     my $im = Imager->new(xsize=>140, ysize=>150);
208     my %common = 
209       (
210        font=>$font, 
211        size=>40, 
212        aa=>1,
213       );
214     $im->line(x1=>0, y1=>40, x2=>139, y2=>40, color=>'blue');
215     $im->line(x1=>0, y1=>90, x2=>139, y2=>90, color=>'blue');
216     $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue');
217     for my $args ([ x=>5,   text=>"A", color=>"white" ],
218                   [ x=>40,  text=>"y", color=>"white" ],
219                   [ x=>75,  text=>"A", channel=>1 ],
220                   [ x=>110, text=>"y", channel=>1 ]) {
221       ok($im->string(%common, @$args, 'y'=>40), "A no alignment");
222       ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1");
223       ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0");
224     }
225     ok($im->write(file=>'testout/t35align.ppm'), "save align image");
226   }
227
228   { # Ticket #14804 Imager::Font->new() doesn't report error details
229     # when using freetype 1
230     # make sure we're using C locale for messages
231     use POSIX qw(setlocale LC_ALL);
232     setlocale(LC_ALL, "C");
233
234     my $font = Imager::Font->new(file=>'t/t35ttfont.t', type=>'tt');
235     ok(!$font, "font creation should have failed for invalid file");
236     cmp_ok(Imager->errstr, 'eq', 'Invalid file format.',
237           "test error message");
238
239     setlocale(LC_ALL, "");
240   }
241
242   { # check errstr set correctly
243     my $font = Imager::Font->new(file=>$fontname, type=>'tt',
244                                 size => undef);
245     ok($font, "made size error test font");
246     my $im = Imager->new(xsize=>100, ysize=>100);
247     ok($im, "made size error test image");
248     ok(!$im->string(font=>$font, x=>10, 'y'=>50, string=>"Hello"),
249        "drawing should fail with no size");
250     is($im->errstr, "No font size provided", "check error message");
251
252     # try no string
253     ok(!$im->string(font=>$font, x=>10, 'y'=>50, size=>15),
254        "drawing should fail with no string");
255     is($im->errstr, "missing required parameter 'string'",
256        "check error message");
257   }
258
259   { # introduced in 0.46 - outputting just space crashes
260     my $im = Imager->new(xsize=>100, ysize=>100);
261     my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', size=>14);
262     ok($im->string(font=>$font, x=> 5, 'y' => 50, string=>' '),
263       "outputting just a space was crashing");
264   }
265
266   { # string output cut off at NUL ('\0')
267     # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd
268     my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt');
269     ok($font, "loaded imugly");
270
271     diff_text_with_nul("a\\0b vs a", "a\0b", "a", 
272                        font => $font, color => '#FFFFFF');
273     diff_text_with_nul("a\\0b vs a", "a\0b", "a", 
274                        font => $font, channel => 1);
275
276     # UTF8 encoded \x{2010}
277     my $dash = pack("C*", 0xE2, 0x80, 0x90);
278     diff_text_with_nul("utf8 dash\\0dash vs dash", "$dash\0$dash", $dash,
279                        font => $font, color => '#FFFFFF', utf8 => 1);
280     diff_text_with_nul("utf8 dash\\0dash vs dash", "$dash\0$dash", $dash,
281                        font => $font, channel => 1, utf8 => 1);
282   }
283
284  SKIP:
285   { # RT 11972
286     # when rendering to a transparent image the coverage should be
287     # expressed in terms of the alpha channel rather than the color
288     my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'tt');
289     ok($font, "loaded fontfiles/ImUgly.ttf")
290       or skip("Could not load test font: ".Imager->errstr, 4);
291     my $im = Imager->new(xsize => 40, ysize => 20, channels => 4);
292     ok($im->string(string => "AB", size => 20, aa => 1, color => '#F00',
293                    x => 0, y => 15, font => $font),
294        "draw to transparent image");
295     #$im->write(file => "foo.png");
296     my $im_noalpha = $im->convert(preset => 'noalpha');
297     my $im_pal = $im->to_paletted(make_colors => 'mediancut');
298     my @colors = $im_pal->getcolors;
299     is(@colors, 2, "should be only 2 colors");
300     @colors = sort { ($a->rgba)[0] <=> ($b->rgba)[0] } @colors;
301     is_color3($colors[0], 0, 0, 0, "check we got black");
302     is_color3($colors[1], 255, 0, 0, "and red");
303   }
304
305   ok(1, "end of code");
306 }