]> git.imager.perl.org - imager.git/blob - lib/Imager/Font.pm
Misc fixes.
[imager.git] / lib / Imager / Font.pm
1 package Imager::Font;
2
3 use Imager::Color;
4 use strict;
5 use File::Spec;
6
7 # This class is a container
8 # and works for both truetype and t1 fonts.
9
10
11 # search method
12 # 1. start by checking if file is the parameter
13 # 1a. if so qualify path and compare to the cache.
14 # 2a. if in cache - take it's id from there and increment count.
15 #
16
17 sub new {
18   my $class = shift;
19   my $self ={};
20   my ($file,$type,$id);
21   my %hsh=(color=>Imager::Color->new(255,0,0,0),
22            size=>15,
23            @_);
24
25   bless $self,$class;
26
27   if ($hsh{'file'}) { 
28     $file=$hsh{'file'};
29     if ( $file !~ m/^\// ) {
30       $file='./'.$file;
31       if (! -e $file) {
32         $Imager::ERRSTR="Font $file not found";
33         return();
34       }
35     }
36
37     $type=$hsh{'type'};
38     if (!defined($type) or $type !~ m/^(t1|tt)/) {
39       $type='tt' if $file =~ m/\.ttf$/i;
40       $type='t1' if $file =~ m/\.pfb$/i;
41     }
42     if (!defined($type)) {
43       $Imager::ERRSTR="Font type not found";
44       return;
45     }
46   } else {
47     $Imager::ERRSTR="No font file specified";
48     return;
49   }
50
51   if (!$Imager::formats{$type}) { 
52     $Imager::ERRSTR="`$type' not enabled";
53     return;
54   }
55
56   # here we should have the font type or be dead already.
57
58   if ($type eq 't1') {
59     require 'Imager/Font/Type1.pm';
60     return Imager::Font::Type1->new(%hsh);
61   }
62
63   if ($type eq 'tt') {
64     require 'Imager/Font/Truetype.pm';
65     return Imager::Font::Truetype->new(%hsh);
66   }
67   # it would be nice to have some generic mechanism to select the
68   # class
69   
70   return undef;
71 }
72
73 # returns first defined parameter
74 sub _first {
75   for (@_) {
76     return $_ if defined $_;
77   }
78   return undef;
79 }
80
81 sub draw {
82   my $self = shift;
83   my %input = (x => 0, 'y' => 0, @_);
84   unless ($input{image}) {
85     $Imager::ERRSTR = 'No image supplied to $font->draw()';
86     return;
87   }
88   $input{string} = _first($input{string}, $input{text});
89   unless (defined $input{string}) {
90     $Imager::ERRSTR = "Missing require parameter 'string'";
91     return;
92   }
93   $input{aa} = _first($input{aa}, $input{antialias}, $self->{aa}, 1);
94   # the original draw code worked this out but didn't use it
95   $input{align} = _first($input{align}, $self->{align});
96   $input{color} = _first($input{color}, $self->{color});
97   $input{size} = _first($input{size}, $self->{size});
98   unless (defined $input{size}) {
99     $input{image}{ERRSTR} = "No font size provided";
100     return undef;
101   }
102   $input{align} = _first($input{align}, 1);
103   $self->_draw(%input);
104 }
105
106 sub bounding_box {
107   my $self=shift;
108   my %input=@_;
109
110   if (!exists $input{'string'}) { 
111     $Imager::ERRSTR='string parameter missing'; 
112     return;
113   }
114   $input{size} ||= $self->{size};
115
116   my @box = $self->_bounding_box(%input);
117
118   if(exists $input{'x'} and exists $input{'y'}) {
119     my($gdescent, $gascent)=@box[1,3];
120     $box[1]=$input{'y'}-$gascent;      # top = base - ascent (Y is down)
121     $box[3]=$input{'y'}-$gdescent;     # bottom = base - descent (Y is down, descent is negative)
122     $box[0]+=$input{'x'};
123     $box[2]+=$input{'x'};
124   } elsif (exists $input{'canon'}) {
125     $box[3]-=$box[1];    # make it cannoical (ie (0,0) - (width, height))
126     $box[2]-=$box[0];
127   }
128   return @box;
129 }
130
131 1;
132
133 __END__
134
135 =head1 NAME
136
137 Imager::Font - Font handling for Imager.
138
139 =head1 SYNOPSIS
140
141   $t1font = Imager::Font->new(file => 'pathtofont.pfb');
142   $ttfont = Imager::Font->new(file => 'pathtofont.ttf');
143
144   $blue = Imager::Color->new("#0000FF");
145   $font = Imager::Font->new(file  => 'pathtofont.ttf',
146                             color => $blue,
147                             size  => 30);
148
149   ($neg_width,
150    $global_descent,
151    $pos_width,
152    $global_ascent,
153    $descent,
154    $ascent) = $font->bounding_box(string=>"Foo");
155
156   $logo = $font->logo(text   => "Slartibartfast Enterprises",
157                       size   => 40,
158                       border => 5,
159                       color  => $green);
160   # logo is proposed - doesn't exist yet
161
162
163   $img->string(font  => $font,
164              text  => "Model-XYZ",
165              x     => 15,
166              y     => 40,
167              size  => 40,
168              color => $red,
169              aa    => 1);
170
171   # Documentation in Imager.pm
172
173 =head1 DESCRIPTION
174
175 This module handles creating Font objects used by imager.  The module
176 also handles querying fonts for sizes and such.  If both T1lib and
177 freetype were avaliable at the time of compilation then Imager should
178 be able to work with both truetype fonts and t1 postscript fonts.  To
179 check if Imager is t1 or truetype capable you can use something like
180 this:
181
182   use Imager;
183   print "Has truetype"      if $Imager::formats{tt};
184   print "Has t1 postscript" if $Imager::formats{t1};
185
186
187 =over 4
188
189 =item new
190
191 This creates a font object to pass to functions that take a font argument.
192
193   $font = Imager::Font->new(file  => 'denmark.ttf',
194                             color => $blue,
195                             size  => 30,
196                             aa    => 1);
197
198 This creates a font which is the truetype font denmark.ttf.  It's
199 default color is $blue, default size is 30 pixels and it's rendered
200 antialised by default.  Imager can see which type of font a file is by
201 looking at the suffix of the filename for the font.  A suffix of 'ttf'
202 is taken to mean a truetype font while a suffix of 'pfb' is taken to
203 mean a t1 postscript font.  If Imager cannot tell which type a font is
204 you can tell it explicitly by using the C<type> parameter:
205
206   $t1font = Imager::Font->new(file => 'fruitcase', type => 't1');
207   $ttfont = Imager::Font->new(file => 'arglebarf', type => 'tt');
208
209 If any of the C<color>, C<size> or C<aa> parameters are omitted when
210 calling C<Imager::Font->new()> the they take the following values:
211
212
213   color => Imager::Color->new(255, 0, 0, 0);  # this default should be changed
214   size  => 15
215   aa    => 0
216
217 =item bounding_box
218 Returns the bounding box for the specified string.  Example:
219
220   ($neg_width,
221    $global_descent,
222    $pos_width,
223    $global_ascent,
224    $descent,
225    $ascent) = $font->bounding_box(string => "A Fool");
226
227 The C<$neg_width> is the relative start of a the string.  In some
228 cases this can be a negative number, in that case the first letter
229 stretches to the left of the starting position that is specified in
230 the string method of the Imager class.  <$global_descent> is the how
231 far down the lowest letter of the entire font reaches below the
232 baseline (this is often j).  C<$pos_width> is how wide the string from
233 from the starting position is.  The total width of the string is
234 C<$pos_width-$neg_width>.  C<$descent> and C<$ascent> are the as
235 <$global_descent> and <$global_ascent> except that they are only for
236 the characters that appear in the string.  Obviously we can stuff all
237 the results into an array just as well:
238
239   @metrics = $font->bounding_box(string => "testing 123");
240
241 Note that extra values may be added, so $metrics[-1] isn't supported.
242 It's possible to translate the output by a passing coordinate to the
243 bounding box method:
244
245   @metrics = $font->bounding_box(string => "testing 123", x=>45, y=>34);
246
247 This gives the bounding box as if the string had been put down at C<(x,y)>
248 By giving bounding_box 'canon' as a true value it's possible to measure
249 the space needed for the string:
250
251   @metrics = $font->bounding_box(string=>"testing",size=>15,canon=>1);
252
253 This returns tha same values in $metrics[0] and $metrics[1],
254 but:
255
256  $bbox[2] - horizontal space taken by glyphs
257  $bbox[3] - vertical space taken by glyphs
258
259
260
261 =item string
262
263 This is a method of the Imager class but because it's described in
264 here since it belongs to the font routines.  Example:
265
266   $img=Imager->new();
267   $img->read(file=>"test.jpg");
268   $img->string(font=>$t1font,
269                text=>"Model-XYZ",
270                x=>0,
271                y=>40,
272                size=>40,
273                color=>$red);
274   $img->write(file=>"testout.jpg");
275
276 This would put a 40 pixel high text in the top left corner of an
277 image.  If you measure the actuall pixels it varies since the fonts
278 usually do not use their full height.  It seems that the color and
279 size can be specified twice.  When a font is created only the actual
280 font specified matters.  It his however convenient to store default
281 values in a font, such as color and size.  If parameters are passed to
282 the string function they are used instead of the defaults stored in
283 the font.
284
285 If string() is called with the C<channel> parameter then the color
286 isn't used and the font is drawn in only one channel of the image.
287 This can be quite handy to create overlays.  See the examples for tips
288 about this.
289
290 Sometimes it is necessary to know how much space a string takes before
291 rendering it.  The bounding_box() method described earlier can be used
292 for that.
293
294
295 =item logo
296
297 This method doesn't exist yet but is under consideration.  It would mostly
298 be helpful for generating small tests and such.  Its proposed interface is:
299
300   $img = $font->logo(string=>"Plan XYZ", color=>$blue, border=>7);
301
302 This would be nice for writing (admittedly multiline) one liners like:
303
304 Imager::Font->new(file=>"arial.ttf", color=>$blue, aa=>1)
305             ->string(text=>"Plan XYZ", border=>5)
306             ->write(file=>"xyz.png");
307
308
309
310 =back
311
312 =head1 AUTHOR
313
314 Arnar M. Hrafnkelsson, addi@umich.edu
315 And a great deal of help from others - see the README for a complete
316 list.
317
318 =head1 BUGS
319
320 You need to modify this class to add new font types.
321
322 =head1 SEE ALSO
323
324 Imager(3)
325 http://www.eecs.umich.edu/~addi/perl/Imager/
326
327 =cut
328
329