use Imager::Color;
use strict;
+use vars qw($VERSION);
+
+$VERSION = "1.033";
# the aim here is that we can:
# - add file based types in one place: here
ft2=>{
class=>'Imager::Font::FreeType2',
module=>'Imager/Font/FreeType2.pm',
- files=>'.*\.(pfa|pfb|otf|ttf|fon|fnt)$',
+ files=>'.*\.(pfa|pfb|otf|ttf|fon|fnt|dfont|pcf(\.gz)?)$',
+ },
+ ifs=>{
+ class=>'Imager::Font::Image',
+ module=>'Imager/Font/Image.pm',
+ files=>'.*\.ifs$',
},
w32=>{
class=>'Imager::Font::Win32',
);
# this currently should only contain file based types, don't add w32
-my @priority = qw(t1 tt ft2);
+my @priority = qw(t1 tt ft2 ifs);
# when Imager::Font is loaded, Imager.xs has not been bootstrapped yet
# this function is called from Imager.pm to finish initialization
sub new {
my $class = shift;
- my $self ={};
- my ($file,$type,$id);
- my %hsh=(color=>Imager::Color->new(255,0,0,0),
- size=>15,
+ my $self = {};
+ my ($file, $type, $id);
+ my %hsh=(color => Imager::Color->new(255,0,0,0),
+ size => 15,
@_);
bless $self,$class;
- if ($hsh{'file'}) {
- $file=$hsh{'file'};
+ if ($hsh{'file'}) {
+ $file = $hsh{'file'};
if ( $file !~ m/^\// ) {
- $file='./'.$file;
+ $file = './'.$file;
if (! -e $file) {
- $Imager::ERRSTR="Font $file not found";
+ $Imager::ERRSTR = "Font $file not found";
return();
}
}
- $type=$hsh{'type'};
+ $type = $hsh{'type'};
if (!defined($type) or !$drivers{$type}) {
for my $drv (@priority) {
undef $type;
}
}
if (!defined($type)) {
- $Imager::ERRSTR="Font type not found";
+ $Imager::ERRSTR = "Font type not found";
return;
}
} elsif ($hsh{face}) {
return;
}
- if (!$Imager::formats{$type}) {
- $Imager::ERRSTR="`$type' not enabled";
+ if (!$Imager::formats{$type}) {
+ $Imager::ERRSTR = "`$type' not enabled";
return;
}
$Imager::ERRSTR = 'No image supplied to $font->draw()';
return;
}
+ my $image = $input{image};
$input{string} = _first($input{string}, $input{text});
unless (defined $input{string}) {
- $Imager::ERRSTR = "Missing required parameter 'string'";
+ $image->_set_error("Missing required parameter 'string'");
return;
}
$input{aa} = _first($input{aa}, $input{antialias}, $self->{aa}, 1);
$input{size} = _first($input{size}, $self->{size});
unless (defined $input{size}) {
- $input{image}{ERRSTR} = "No font size provided";
+ $image->_set_error("No font size provided");
return undef;
}
$input{align} = _first($input{align}, 1);
$input{utf8} = _first($input{utf8}, $self->{utf8}, 0);
$input{vlayout} = _first($input{vlayout}, $self->{vlayout}, 0);
- $self->_draw(%input);
+ my $result = $self->_draw(%input);
+ unless ($result) {
+ $image->_set_error($image->_error_as_msg());
+ }
+
+ return $result;
}
sub align {
my %input = ( halign => 'left', valign => 'baseline',
'x' => 0, 'y' => 0, @_ );
- my $text = _first($input{string}, $input{text});
- unless (defined $text) {
- Imager->_set_error("Missing required parameter 'string'");
- return;
- }
-
# image needs to be supplied, but can be supplied as undef
unless (exists $input{image}) {
Imager->_set_error("Missing required parameter 'image'");
return;
}
+
+ my $errors_to = $input{image} || 'Imager';
+
+ my $text = _first($input{string}, $input{text});
+ unless (defined $text) {
+ $errors_to->_set_error("Missing required parameter 'string'");
+ return;
+ }
+
my $size = _first($input{size}, $self->{size});
my $utf8 = _first($input{utf8}, 0);
-
+
my $bbox = $self->bounding_box(string=>$text, size=>$size, utf8=>$utf8);
my $valign = $input{valign};
$valign = 'baseline'
unless $valign && $valign =~ /^(?:top|center|bottom|baseline)$/;
-
+
my $halign = $input{halign};
$halign = 'start'
unless $halign && $halign =~ /^(?:left|start|center|end|right)$/;
my $x = $input{'x'};
my $y = $input{'y'};
-
+
if ($valign eq 'top') {
$y += $bbox->ascent;
}
elsif ($halign eq 'center') {
$x -= $bbox->start_offset + $bbox->total_width / 2;
}
- elsif ($halign eq 'end' || $halign eq 'right') {
- $x -= $bbox->start_offset + $bbox->total_width - 1;
+ elsif ($halign eq 'end') {
+ $x -= $bbox->advance_width;
+ }
+ elsif ($halign eq 'right') {
+ $x -= $bbox->advance_width - $bbox->right_bearing;
}
$x = int($x);
$y = int($y);
delete @input{qw/x y/};
$self->draw(%input, 'x' => $x, 'y' => $y, align=>1)
or return;
-# for my $i (1 .. length $text) {
-# my $work = substr($text, 0, $i);
-# my $bbox = $self->bounding_box(string=>$work, size=>$size, utf8=>$utf8);
-# my $nx = $x + $bbox->end_offset;
-# $input{image}->setpixel(x=>[ ($nx) x 5 ],
-# 'y'=>[ $y-2, $y-1, $y, $y+1, $y+2 ],
-# color=>'FF0000');
-# }
}
return ($x+$bbox->start_offset, $y-$bbox->ascent,
$Imager::ERRSTR = "You need to supply a matrix";
return;
}
-
+
return $self->_transform(%hsh);
}
$pos_width,
$global_ascent,
$descent,
- $ascent) = $font->bounding_box(string=>"Foo");
-
- $logo = $font->logo(text => "Slartibartfast Enterprises",
- size => 40,
- border => 5,
- color => $green);
- # logo is proposed - doesn't exist yet
+ $ascent,
+ $advance_width,
+ $right_bearing) = $font->bounding_box(string=>"Foo");
+ my $bbox_object = $font->bounding_box(string=>"Foo");
+ # documented in Imager::Draw
$img->string(font => $font,
text => "Model-XYZ",
x => 15,
color => $red,
aa => 1);
- # Documentation in Imager.pm
-
=head1 DESCRIPTION
This module handles creating Font objects used by imager. The module
This creates a font object to pass to functions that take a font argument.
$font = Imager::Font->new(file => 'denmark.ttf',
+ index => 0,
color => $blue,
size => 30,
aa => 1);
$t1font = Imager::Font->new(file => 'fruitcase', type => 't1');
$ttfont = Imager::Font->new(file => 'arglebarf', type => 'tt');
+The C<index> parameter is used to select a single face from a font
+file containing more than one face, for example, from a Macintosh font
+suitcase or a .dfont file.
+
If any of the C<color>, C<size> or C<aa> parameters are omitted when
calling C<Imager::Font->new()> the they take the following values:
-
color => Imager::Color->new(255, 0, 0, 0); # this default should be changed
size => 15
aa => 0
+ index => 0
To use Win32 fonts supply the facename of the font:
Other logical font attributes may be added if there is sufficient demand.
+Parameters:
+
+=over
+
+=item *
+
+file - name of the file to load the font from.
+
+=item *
+
+face - face name. This is used only under Win32 to create a GDI based
+font. This is ignored if the C<file> parameter is supplied.
+
+=item *
+
+type - font driver to use. Currently the permitted values for this are:
+
+=over
+
+=item *
+
+tt - Freetype 1.x driver. Supports TTF fonts.
+
+=item *
+
+t1 - T1 Lib driver. Supports Postscript Type 1 fonts. Allows for
+synthesis of underline, strikethrough and overline.
+
+=item *
+
+ft2 - Freetype 2.x driver. Supports many different font formats.
+Also supports the transform() method.
+
+=back
+
+=item *
+
+color - the default color used with this font. Default: red.
+
+=item *
+
+size - the default size used with this font. Default: 15.
+
+=item *
+
+utf8 - if non-zero then text supplied to $img->string(...) and
+$font->bounding_box(...) is assumed to be UTF 8 encoded by default.
+
+=item *
+
+align - the default value for the $img->string(...) C<align>
+parameter. Default: 1.
+
+=item *
+
+vlayout - the default value for the $img->string(...) C<vlayout>
+parameter. Default: 0.
+
+=item *
+
+aa - the default value for the $im->string(...) C<aa> parameter.
+Default: 0.
+
+=item *
+
+index - for font file containing multiple fonts this selects which
+font to use. This is useful for Macintosh DFON (.dfont) and suitcase
+font files.
+
+If you want to use a suitcase font you will need to tell Imager to use
+the FreeType 2.x driver by setting C<type> to C<'ft2'>:
+
+ my $font = Imager::Font->new(file=>$file, index => 1, type=>'ft2')
+ or die Imager->errstr;
+
+=back
+
+
+
=item bounding_box
Returns the bounding box for the specified string. Example:
$global_ascent,
$descent,
$ascent,
- $advance_width) = $font->bounding_box(string => "A Fool");
+ $advance_width,
+ $right_bearing) = $font->bounding_box(string => "A Fool");
my $bbox_object = $font->bounding_box(string => "A Fool");
different if the final character overlaps the right side of its
character cell.
+=item C<$right_bearing>
+
+The distance from the right side of the final glyph to the end of the
+advance width. If the final glyph overflows the advance width this
+value is negative.
+
=back
Obviously we can stuff all the results into an array just as well:
avoid all those confusing indices. This has methods as named above,
with some extra convenience methods.
-=item string
-
-This is a method of the Imager class but because it's described in
-here since it belongs to the font routines. Example:
-
- $img=Imager->new();
- $img->read(file=>"test.jpg");
- $img->string(font=>$t1font,
- text=>"Model-XYZ",
- x=>0,
- y=>40,
- size=>40,
- color=>$red);
- $img->write(file=>"testout.jpg");
-
-This would put a 40 pixel high text in the top left corner of an
-image. If you measure the actuall pixels it varies since the fonts
-usually do not use their full height. It seems that the color and
-size can be specified twice. When a font is created only the actual
-font specified matters. It his however convenient to store default
-values in a font, such as color and size. If parameters are passed to
-the string function they are used instead of the defaults stored in
-the font.
-
-The following parameters can be supplied to the string() method:
+Parameters are:
=over
-=item string
-
-The text to be rendered. If this isn't present the 'text' parameter
-is used. If neither is present the call will fail.
-
-=item aa
-
-If non-zero the output will be anti-aliased.
-
-=item x
-
-=item y
-
-The start point for rendering the text. See the align parameter.
-
-=item align
-
-If non-zero the point supplied in (x,y) will be on the base-line, if
-zero then (x,y) will be at the top-left of the first character.
-
-=item channel
+=item *
-If present, the text will be written to the specified channel of the
-image and the color parameter will be ignore.
+string - the string to calculate the bounding box for. Required.
-=item color
+=item *
-The color to draw the text in.
+size - the font size to use. Default: value set in
+Imager::Font->new(), or 15.
-=item size
+=item *
-The point-size to draw the text at.
+sizew - the font width to use. Default to the value of the C<size>
+parameter.
-=item sizew
+=item *
-For drivers that support it, the width to draw the text at. Defaults
-to be value of the 'size' parameter.
+utf8 - For drivers that support it, treat the string as UTF8 encoded.
+For versions of perl that support Unicode (5.6 and later), this will
+be enabled automatically if the 'string' parameter is already a UTF8
+string. See L<UTF8> for more information. Default: the C<utf8> value
+passed to Imager::Font->new(...) or 0.
-=item utf8
+=item *
-For drivers that support it, treat the string as UTF8 encoded. For
-versions of perl that support Unicode (5.6 and later), this will be
-enabled automatically if the 'string' parameter is already a UTF8
-string. See L<UTF8> for more information.
+x, y - offsets applied to @box[0..3] to give you a adjusted bounding
+box. Ignored in scalar context.
-=item vlayout
+=item *
-For drivers that support it, draw the text vertically. Note: I
-haven't found a font that has the appropriate metrics yet.
+canon - if non-zero and the C<x>, C<y> parameters are not supplied,
+then $pos_width and $global_ascent values will returned as the width
+and height of the text instead.
=back
-If string() is called with the C<channel> parameter then the color
-isn't used and the font is drawn in only one channel of the image.
-This can be quite handy to create overlays. See the examples for tips
-about this.
+=item string
-Sometimes it is necessary to know how much space a string takes before
-rendering it. The bounding_box() method described earlier can be used
-for that.
+The $img->string(...) method is now documented in
+L<Imager::Draw/string>
=item align(string=>$text, size=>$size, x=>..., y=>..., valign => ..., halign=>...)
around the given point (x,y).
# "Hello" centered at 100, 100 in the image.
- my ($left, $top, $bottom, $right) =
+ my ($left, $top, $right, $bottom) =
$font->align(string=>"Hello",
x=>100, y=>100,
halign=>'center', valign=>'center',
=item end
-The point is at the right end of the text. This will change to the
-end point of the text (once the proper bounding box interfaces are
-available).
+The point is at the end point of the text.
=back
=item dpi(dpi=>$dpi)
-Set retrieve the spatial resolution of the image in dots per inch.
+Set or retrieve the spatial resolution of the image in dots per inch.
The default is 72 dpi.
This isn't implemented for all font types yet.
+Possible parameters are:
+
+=over
+
+=item *
+
+xdpi, ydpi - set the horizontal and vertical resolution in dots per
+inch.
+
+=item *
+
+dpi - set both horizontal and vertical resolution to this value.
+
+=back
+
+Returns a list containing the previous xdpi, ydpi values.
+
=item transform(matrix=>$matrix)
Applies a transformation to the font, where matrix is an array ref of
Currently only the ft2 (Freetype 2.x) driver supports the transform()
method.
+See samples/slant_text.pl for a sample using this function.
+
+Note that the transformation is done in font co-ordinates where y
+increases as you move up, not image co-ordinates where y decreases as
+you move up.
+
=item has_chars(string=>$text)
Checks if the characters in $text are defined by the font.
Not all fonts support this method (use $font->can("has_chars") to
check.)
-=item logo
+=over
+
+=item *
-This method doesn't exist yet but is under consideration. It would mostly
-be helpful for generating small tests and such. Its proposed interface is:
+string - string of characters to check for. Required. Must contain
+at least one character.
- $img = $font->logo(string=>"Plan XYZ", color=>$blue, border=>7);
+=item *
-This would be nice for writing (admittedly multiline) one liners like:
+utf8 - For drivers that support it, treat the string as UTF8 encoded.
+For versions of perl that support Unicode (5.6 and later), this will
+be enabled automatically if the 'string' parameter is already a UTF8
+string. See L<UTF8> for more information. Default: the C<utf8> value
+passed to Imager::Font->new(...) or 0.
-Imager::Font->new(file=>"arial.ttf", color=>$blue, aa=>1)
- ->string(text=>"Plan XYZ", border=>5)
- ->write(file=>"xyz.png");
+=back
=item face_name()
Returns the internal name of the face. Not all font types support
this method yet.
-=item glyph_names(string=>$string [, utf8=>$utf8 ] );
+=item glyph_names(string=>$string [, utf8=>$utf8 ][, reliable_only=>0 ] );
Returns a list of glyph names for each of the characters in the
string. If the character has no name then C<undef> is returned for
will not return any names. Freetype 1 can return standard names even
if there are no glyph names in the font.
+Freetype 2 has an API function that returns true only if the font has
+"reliable glyph names", unfortunately this always returns false for
+TTF fonts. This can avoid the check of this API by supplying
+C<reliable_only> as 0. The consequences of using this on an unknown
+font may be unpredictable, since the Freetype documentation doesn't
+say how those name tables are unreliable, or how FT2 handles them.
+
Both Freetype 1.x and 2.x allow support for glyph names to not be
included.
+=item draw
+
+This is used by Imager's string() method to implement drawing text.
+See L<Imager::Draw/string>.
+
=back
+=head1 MULTIPLE MASTER FONTS
+
+The Freetype 2 driver supports multiple master fonts:
+
+=over
+
+=item is_mm()
+
+Test if the font is a multiple master font.
+
+=item mm_axes()
+
+Returns a list of the axes that can be changes in the font. Each
+entry is an array reference which contains:
+
+=over
+
+=item 1.
+
+Name of the axis.
+
+=item 2.
+
+minimum value for this axis.
+
+=item 3.
+
+maximum value for this axis
+
+=back
+
+=item set_mm_coords(coords=>\@values)
+
+Blends an interpolated design from the master fonts. @values must
+contain as many values as there are axes in the font.
+
+=back
+
+For example, to select the minimum value in each axis:
+
+ my @axes = $font->mm_axes;
+ my @coords = map $_->[1], @axes;
+ $font->set_mm_coords(coords=>\@coords);
+
+It's possible other drivers will support multiple master fonts in the
+future, check if your selected font object supports the is_mm() method
+using the can() method.
+
=head1 UTF8
There are 2 ways of rendering Unicode characters with Imager:
your font doesn't support it, Imager will I<not> build it from 0041
"LATIN CAPITAL LETTER A" and 0308 "COMBINING DIAERESIS".
+To check if a driver supports UTF8 call the utf8 method:
+
+=over
+
+=item utf8
+
+Return true if the font supports UTF8.
+
+=back
+
=head2 Native UTF8 Support
If your version of perl supports UTF8 and the driver supports UTF8,
list is used to choose which one should be used, if a given format can
be handled by more than one driver.
-The current priority can be retrieved with:
+=over
+
+=item priorities
+
+The current priorities can be retrieved with:
@drivers = Imager::Font->priorities();
@old = Imager::Font->priorities(@drivers);
+=back
+
If you supply driver names that are not currently supported, they will
be ignored.
You need to modify this class to add new font types.
+The $pos_width member returned by the bounding_box() method has
+historically returned different values from different drivers. The
+Freetype 1.x and 2.x, and the Win32 drivers return the max of the
+advance width and the right edge of the right-most glyph. The Type 1
+driver always returns the right edge of the right-most glyph.
+
+The newer advance_width and right_bearing values allow access to any
+of the above.
+
+=head1 REVISION
+
+$Revision$
+
=head1 SEE ALSO
Imager(3), Imager::Font::FreeType2(3), Imager::Font::Type1(3),
Imager::Font::Win32(3), Imager::Font::Truetype(3), Imager::Font::BBox(3)
-
-http://www.eecs.umich.edu/~addi/perl/Imager/
+ http://imager.perl.org/
=cut