Imager is moving to github
[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 use Scalar::Util ();
7
8 BEGIN {
9   $VERSION = "1.027";
10
11   require XSLoader;
12   XSLoader::load('Imager::Font::T1', $VERSION);
13 }
14
15
16 *_first = \&Imager::Font::_first;
17
18 my $t1aa = 2;
19
20 sub new {
21   my $class = shift;
22   my %hsh=(color=>Imager::Color->new(255,0,0,255),
23            size=>15,
24            @_);
25
26   unless ($hsh{file}) {
27     $Imager::ERRSTR = "No font file specified";
28     return;
29   }
30   unless (-e $hsh{file}) {
31     $Imager::ERRSTR = "Font file $hsh{file} not found";
32     return;
33   }
34   unless ($Imager::formats{t1}) {
35     $Imager::ERRSTR = "Type 1 fonts not supported in this build";
36     return;
37   }
38   # we want to avoid T1Lib's file search mechanism
39   unless ($hsh{file} =~ m!^/!
40           || $hsh{file} =~ m!^\.\/?/!
41           || $^O =~ /^(MSWin32|cygwin)$/ && $hsh{file} =~ /^[a-z]:/i) {
42     $hsh{file} = './' . $hsh{file};
43   }
44
45   if($hsh{afm}) {
46           unless (-e $hsh{afm}) {
47             $Imager::ERRSTR = "Afm file $hsh{afm} not found";
48             return;
49           }
50           unless ($hsh{afm} =~ m!^/!
51                   || $hsh{afm} =~ m!^\./!
52                   || $^O =~ /^(MSWin32|cygwin)$/ && $hsh{file} =~ /^[a-z]:/i) {
53             $hsh{file} = './' . $hsh{file};
54           }
55   } else {
56           $hsh{afm} = 0;
57   }
58
59   my $font = Imager::Font::T1xs->new($hsh{file},$hsh{afm});
60   unless ($font) { # the low-level code may miss some error handling
61     Imager->_set_error(Imager->_error_as_msg);
62     return;
63   }
64   return bless {
65                 t1font    => $font,
66                 aa    => $hsh{aa} || 0,
67                 file  => $hsh{file},
68                 type  => 't1',
69                 size  => $hsh{size},
70                 color => $hsh{color},
71                 t1aa  => $t1aa,
72                }, $class;
73 }
74
75 sub _draw {
76   my $self = shift;
77
78   $self->_valid
79     or return;
80
81   my %input = @_;
82   my $flags = '';
83   $flags .= 'u' if $input{underline};
84   $flags .= 's' if $input{strikethrough};
85   $flags .= 'o' if $input{overline};
86   my $aa = $input{aa} ? $self->{t1aa} : 0;
87   if (exists $input{channel}) {
88     $self->{t1font}->cp($input{image}{IMG}, $input{'x'}, $input{'y'},
89                     $input{channel}, $input{size},
90                     $input{string}, $input{align},
91                     $input{utf8}, $flags, $aa)
92       or return;
93   } else {
94     $self->{t1font}->text($input{image}{IMG}, $input{'x'}, $input{'y'}, 
95                       $input{color}, $input{size}, 
96                       $input{string}, $input{align}, $input{utf8}, $flags, $aa)
97       or return;
98   }
99
100   return $self;
101 }
102
103 sub _bounding_box {
104   my $self = shift;
105
106   $self->_valid
107     or return;
108
109   my %input = @_;
110   my $flags = '';
111   $flags .= 'u' if $input{underline};
112   $flags .= 's' if $input{strikethrough};
113   $flags .= 'o' if $input{overline};
114   my @bbox =  $self->{t1font}->bbox($input{size}, $input{string},
115                                     $input{utf8}, $flags);
116   unless (@bbox) {
117     Imager->_set_error(Imager->_error_as_msg);
118     return;
119   }
120
121   return @bbox;
122 }
123
124 # check if the font has the characters in the given string
125 sub has_chars {
126   my ($self, %hsh) = @_;
127
128   $self->_valid
129     or return;
130
131   unless (defined $hsh{string}) {
132     $Imager::ERRSTR = "No string supplied to \$font->has_chars()";
133     return;
134   }
135   if (wantarray) {
136     my @result = $self->{t1font}
137       ->has_chars($hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0));
138     unless (@result) {
139       Imager->_set_error(Imager->_error_as_msg);
140       return;
141     }
142
143     return @result;
144   }
145   else {
146     my $result = $self->{t1font}
147       ->has_chars($hsh{string}, _first($hsh{'utf8'}, $self->{utf8}, 0));
148     unless (defined $result) {
149       Imager->_set_error(Imager->_error_as_msg);
150       return;
151     }
152     return $result;
153   }
154 }
155
156 sub utf8 {
157   1;
158 }
159
160 sub can_glyph_names {
161   1;
162 }
163
164 sub face_name {
165   my ($self) = @_;
166
167   $self->_valid
168     or return;
169
170   return $self->{t1font}->face_name();
171 }
172
173 sub glyph_names {
174   my ($self, %input) = @_;
175
176   $self->_valid
177     or return;
178
179   my $string = $input{string};
180   defined $string
181     or return Imager->_set_error("no string parameter passed to glyph_names");
182   my $utf8 = _first($input{utf8} || 0);
183
184   my @result = $self->{t1font}->glyph_names($string, $utf8);
185   unless (@result) {
186     Imager->_set_error(Imager->_error_as_msg);
187     return;
188   }
189
190   return @result;
191 }
192
193 sub set_aa_level {
194   my ($self, $new_t1aa) = @_;
195
196   if (!defined $new_t1aa ||
197       ($new_t1aa != 1 && $new_t1aa != 2)) {
198     Imager->_set_error("set_aa_level: parameter must be 1 or 2");
199     return;
200   }
201
202   if (ref $self) {
203     $self->_valid
204       or return;
205
206     $self->{t1aa} = $new_t1aa;
207   }
208   else {
209     $t1aa = $new_t1aa;
210   }
211
212   return 1;
213 }
214
215 sub _valid {
216   my $self = shift;
217
218   unless ($self->{t1font} && Scalar::Util::blessed($self->{t1font})) {
219     Imager->_set_error("font object was created in another thread");
220     return;
221   }
222
223   return 1;
224 }
225
226 1;
227
228 __END__
229
230 =head1 NAME
231
232   Imager::Font::Type1 - low-level functions for Type1 fonts
233
234 =head1 DESCRIPTION
235
236 Imager::Font::T1 is deprecated.
237
238 F<T1Lib> is unmaintained and has serious bugs when built on 64-bit
239 systems.  Freetype 2 has Type 1 font support and is supported by
240 Imager via Imager::Font::FT2.
241
242 Imager::Font creates a Imager::Font::Type1 object when asked to create
243 a font object based on a C<.pfb> file.
244
245 See Imager::Font to see how to use this type.
246
247 This class provides low-level functions that require the caller to
248 perform data validation
249
250 By default Imager no longer creates the F<t1lib.log> log file.  You
251 can re-enable that by calling Imager::init() with the C<t1log> option:
252
253   Imager::init(t1log=>1);
254
255 This must be called before creating any fonts.
256
257 Currently specific to Imager::Font::Type1, you can use the following
258 flags when drawing text or calculating a bounding box:
259
260 =for stopwords overline strikethrough
261
262 =over
263
264 =item *
265
266 C<underline> - Draw the text with an underline.
267
268 =item *
269
270 C<overline> - Draw the text with an overline.
271
272 =item *
273
274 C<strikethrough> - Draw the text with a strikethrough.
275
276 =back
277
278 Obviously, if you're calculating the bounding box the size of the line
279 is included in the box, and the line isn't drawn :)
280
281 =head2 Anti-aliasing
282
283 T1Lib supports multiple levels of anti-aliasing, by default, if you
284 request anti-aliased output, Imager::Font::T1 will use the maximum
285 level.
286
287 You can override this with the set_t1_aa() method:
288
289 =over
290
291 =item set_aa_level()
292
293 Usage:
294
295   $font->set_aa_level(1);
296   Imager::Font::T1->set_aa_level(2);
297
298 Sets the T1Lib anti-aliasing level either for the specified font, or
299 for new font objects.
300
301 The only parameter must be 1 or 2.
302
303 Returns true on success.
304
305 =back
306
307 =head1 AUTHOR
308
309 Addi, Tony
310
311 =cut