6 use constant PI => 4 * atan2(1,1);
8 # this sample requires Freetype 2.x
9 $Imager::formats{"ft2"}
10 or die "This sample require Freetype 2.x to be configured in Imager\n";
12 Getopt::Long::Configure("bundling");
19 GetOptions('angle|a=f' => \$angle,
21 'foreground|fg|f=s' => \$fg,
22 'background|bg|b=s' => \$bg,
23 'rotate|r' => \$rotate)
27 if ($angle < -45 or $angle > 45) {
28 # while values outside this range are valid, the text would be hard
30 die "--angle is limited to the range -45 through +45\n";
33 die "--size must be 10 or greater\n";
42 my $angle_rads = $angle * (PI / 180);
45 # this is the only difference between rotation and shearing: the
46 # transformation matrix
48 $trans = Imager::Matrix2d->rotate(radians => $angle_rads);
51 $trans = Imager::Matrix2d->shear(x=>sin($angle_rads)/cos($angle_rads));
54 # only the Freetype 2.x driver supports transformations for now
55 my $font = Imager::Font->new(file=>$fontfile, type=>'ft2')
56 or die "Cannot load font $fontfile: ", Imager->errstr, "\n";
58 $font->transform(matrix=>$trans);
60 my $bbox = $font->bounding_box(string=>$text, size=>$size);
62 # these are in font co-ordinates, so y is flipped
63 my ($left, $miny, $right, $maxy) =
64 transformed_bounds($bbox, $trans);
66 # convert to image relative co-ordinates
67 my ($top, $bottom) = (-$maxy, -$miny);
69 my ($width, $height) = ($right - $left, $bottom - $top);
71 my $img = Imager->new(xsize=>$width, ysize=>$height);
73 # fill with the background
74 $img->box(filled=>1, color=>$bg);
76 # and draw our string in the right place
77 $img->string(text => $text,
78 color => Imager::Color->new('white'),
85 $img->write(file=>$outfile)
86 or die "Cannot save $outfile: ",$img->errstr,"\n";
88 sub transformed_bounds {
89 my ($bbox, $matrix) = @_;
92 for my $point ([ $bbox->start_offset, $bbox->ascent ],
93 [ $bbox->start_offset, $bbox->descent ],
94 [ $bbox->end_offset, $bbox->ascent ],
95 [ $bbox->end_offset, $bbox->descent ]) {
96 $bounds = add_bound($bounds, transform_point(@$point, $matrix));
102 sub transform_point {
103 my ($x, $y, $matrix) = @_;
107 $x * $matrix->[0] + $y * $matrix->[1] + $matrix->[2],
108 $x * $matrix->[3] + $y * $matrix->[4] + $matrix->[5]
113 my ($bounds, $x, $y) = @_;
115 $bounds or return [ $x, $y, $x, $y ];
117 $x < $bounds->[0] and $bounds->[0] = $x;
118 $y < $bounds->[1] and $bounds->[1] = $y;
119 $x > $bounds->[2] and $bounds->[2] = $x;
120 $y > $bounds->[3] and $bounds->[3] = $y;
127 Usage: $0 [options] fontfile outfile text...
129 --angle <angle> | -a <angle>
130 Set the slant angle in degrees, limited to -45 to +45. Default 30.
131 --size <pixels> | -s <angle>
132 Set the text size in pixels. Must be 10 or greater. Default: 20.
133 --foreground <color> | --fg <color> | -f <color>
134 Set the text foreground color. Default: white.
135 --background <color> | --bg <color> | -b <color>
136 Set the image background color. Default: black
138 Rotate instead of shearing. Default: shear
142 $0 -a 45 fontfiles/ImUgly.ttf output.ppm "something to say"
143 # rotate at 100 pixel font size, blue foregroune, white background
144 $0 -rs 100 -b white -f blue fontfiles/ImUgly.ttf output.ppm Imager
151 slant_text.pl - sample for drawing transformed text
155 perl slant_text.pl [options] fontfile output text
157 Run without arguments for option details.
161 This is a sample for drawing transformed text.
163 It's complicated by the need to create an image to put the text into,
164 if you have text, a font, and a good idea where it belongs, it's
165 simple to create the transformation matrix:
167 use Imager::Matrix2d;
168 # or call another method for shearing, etc
169 my $matrix = Imager::Matrix2d->rotate(radians=>$some_angle);
171 Feed the transformation matrix to the font:
173 $font->transform(matrix=>$font);
175 then draw the text as normal:
177 $image->string(string=>$some_text,
183 But if you do need the bounds, the code above does show you how to do
190 =item transformed_bounds
192 Returns a list of bounds:
193 (minx, miny, maxx, maxy)
195 These are offsets from the text's starting point in font co-ordinates
196 - so positive y is I<up>.
198 Note: this returns the bounds of the transformed bounding box, in most
199 cases the actual text will not be touching these boundaries.
207 Tony Cook <tony@imager.perl.org>
215 Imager(1), Imager::Cookbook, Imager::Matrix2d