thread-safe T1lib interface
[imager.git] / T1 / T1.pm
1 package Imager::Font::T1;
2 use strict;
3 use Imager::Color;
4 use vars qw(@ISA $VERSION);
5 @ISA = qw(Imager::Font);
6
7 BEGIN {
8   $VERSION = "1.018";
9
10   require XSLoader;
11   XSLoader::load('Imager::Font::T1', $VERSION);
12 }
13
14
15 *_first = \&Imager::Font::_first;
16
17 my $t1aa;
18
19 # $T1AA is in there because for some reason (probably cache related) antialiasing
20 # is a system wide setting in t1 lib.
21
22 sub new {
23   my $class = shift;
24   my %hsh=(color=>Imager::Color->new(255,0,0,255),
25            size=>15,
26            @_);
27
28   unless ($hsh{file}) {
29     $Imager::ERRSTR = "No font file specified";
30     return;
31   }
32   unless (-e $hsh{file}) {
33     $Imager::ERRSTR = "Font file $hsh{file} not found";
34     return;
35   }
36   unless ($Imager::formats{t1}) {
37     $Imager::ERRSTR = "Type 1 fonts not supported in this build";
38     return;
39   }
40   # we want to avoid T1Lib's file search mechanism
41   unless ($hsh{file} =~ m!^/!
42           || $hsh{file} =~ m!^\.\/?/!
43           || $^O =~ /^(MSWin32|cygwin)$/ && $hsh{file} =~ /^[a-z]:/i) {
44     $hsh{file} = './' . $hsh{file};
45   }
46
47   if($hsh{afm}) {
48           unless (-e $hsh{afm}) {
49             $Imager::ERRSTR = "Afm file $hsh{afm} not found";
50             return;
51           }
52           unless ($hsh{afm} =~ m!^/!
53                   || $hsh{afm} =~ m!^\./!
54                   || $^O =~ /^(MSWin32|cygwin)$/ && $hsh{file} =~ /^[a-z]:/i) {
55             $hsh{file} = './' . $hsh{file};
56           }
57   } else {
58           $hsh{afm} = 0;
59   }
60
61   my $font = Imager::Font::T1xs->new($hsh{file},$hsh{afm});
62   unless ($font) { # the low-level code may miss some error handling
63     Imager->_set_error(Imager->_error_as_msg);
64     return;
65   }
66   return bless {
67                 t1font    => $font,
68                 aa    => $hsh{aa} || 0,
69                 file  => $hsh{file},
70                 type  => 't1',
71                 size  => $hsh{size},
72                 color => $hsh{color},
73                }, $class;
74 }
75
76 sub _draw {
77   my $self = shift;
78   my %input = @_;
79   my $flags = '';
80   $flags .= 'u' if $input{underline};
81   $flags .= 's' if $input{strikethrough};
82   $flags .= 'o' if $input{overline};
83   if (exists $input{channel}) {
84     $self->{t1font}->cp($input{image}{IMG}, $input{'x'}, $input{'y'},
85                     $input{channel}, $input{size},
86                     $input{string}, length($input{string}), $input{align},
87                     $input{utf8}, $flags, $input{aa});
88   } else {
89     $self->{t1font}->text($input{image}{IMG}, $input{'x'}, $input{'y'}, 
90                       $input{color}, $input{size}, 
91                       $input{string}, length($input{string}), 
92                       $input{align}, $input{utf8}, $flags, $input{aa});
93   }
94
95   return $self;
96 }
97
98 sub _bounding_box {
99   my $self = shift;
100   my %input = @_;
101   my $flags = '';
102   $flags .= 'u' if $input{underline};
103   $flags .= 's' if $input{strikethrough};
104   $flags .= 'o' if $input{overline};
105   return $self->{t1font}->bbox($input{size}, $input{string},
106                            length($input{string}), $input{utf8}, $flags);
107 }
108
109 # check if the font has the characters in the given string
110 sub has_chars {
111   my ($self, %hsh) = @_;
112
113   unless (defined $hsh{string} && length $hsh{string}) {
114     $Imager::ERRSTR = "No string supplied to \$font->has_chars()";
115     return;
116   }
117   return $self->{t1font}->has_chars($hsh{string}, 
118                                     _first($hsh{'utf8'}, $self->{utf8}, 0));
119 }
120
121 sub utf8 {
122   1;
123 }
124
125 sub face_name {
126   my ($self) = @_;
127
128   return $self->{t1font}->face_name();
129 }
130
131 sub glyph_names {
132   my ($self, %input) = @_;
133
134   my $string = $input{string};
135   defined $string
136     or return Imager->_set_error("no string parameter passed to glyph_names");
137   my $utf8 = _first($input{utf8} || 0);
138
139   return $self->{t1font}->glyph_name($string, $utf8);
140 }
141
142
143 1;
144
145 __END__
146
147 =head1 NAME
148
149   Imager::Font::Type1 - low-level functions for Type1 fonts
150
151 =head1 DESCRIPTION
152
153 Imager::Font creates a Imager::Font::Type1 object when asked to create
154 a font object based on a C<.pfb> file.
155
156 See Imager::Font to see how to use this type.
157
158 This class provides low-level functions that require the caller to
159 perform data validation
160
161 By default Imager no longer creates the F<t1lib.log> log file.  You
162 can re-enable that by calling Imager::init() with the C<t1log> option:
163
164   Imager::init(t1log=>1);
165
166 This must be called before creating any fonts.
167
168 Currently specific to Imager::Font::Type1, you can use the following
169 flags when drawing text or calculating a bounding box:
170
171 =for stopwords overline strikethrough
172
173 =over
174
175 =item *
176
177 C<underline> - Draw the text with an underline.
178
179 =item *
180
181 C<overline> - Draw the text with an overline.
182
183 =item *
184
185 C<strikethrough> - Draw the text with a strikethrough.
186
187 =back
188
189 Obviously, if you're calculating the bounding box the size of the line
190 is included in the box, and the line isn't drawn :)
191
192 =head1 AUTHOR
193
194 Addi, Tony
195
196 =cut