Commit | Line | Data |
---|---|---|
50c75381 TC |
1 | package Imager::Font::FT2; |
2 | use strict; | |
3 | use Imager; | |
17f8d455 | 4 | use Scalar::Util (); |
50c75381 TC |
5 | use vars qw($VERSION @ISA); |
6 | @ISA = qw(Imager::Font); | |
7 | ||
8 | BEGIN { | |
17f8d455 | 9 | $VERSION = "0.86"; |
50c75381 | 10 | |
a5919365 TC |
11 | require XSLoader; |
12 | XSLoader::load('Imager::Font::FT2', $VERSION); | |
50c75381 TC |
13 | } |
14 | ||
15 | *_first = \&Imager::Font::_first; | |
16 | ||
17 | sub new { | |
18 | my $class = shift; | |
61e5a61a | 19 | my %hsh=(color=>Imager::Color->new(255,0,0,255), |
50c75381 TC |
20 | size=>15, |
21 | @_); | |
22 | ||
23 | unless ($hsh{file}) { | |
24 | $Imager::ERRSTR = "No font file specified"; | |
25 | return; | |
26 | } | |
27 | unless (-e $hsh{file}) { | |
28 | $Imager::ERRSTR = "Font file $hsh{file} not found"; | |
29 | return; | |
30 | } | |
31 | unless ($Imager::formats{ft2}) { | |
32 | $Imager::ERRSTR = "Freetype2 not supported in this build"; | |
33 | return; | |
34 | } | |
35 | my $id = i_ft2_new($hsh{file}, $hsh{'index'} || 0); | |
36 | unless ($id) { # the low-level code may miss some error handling | |
37 | $Imager::ERRSTR = Imager::_error_as_msg(); | |
38 | return; | |
39 | } | |
40 | return bless { | |
41 | id => $id, | |
42 | aa => $hsh{aa} || 0, | |
43 | file => $hsh{file}, | |
44 | type => 't1', | |
45 | size => $hsh{size}, | |
46 | color => $hsh{color}, | |
47 | utf8 => $hsh{utf8}, | |
48 | vlayout => $hsh{vlayout}, | |
49 | }, $class; | |
50 | } | |
51 | ||
52 | sub _draw { | |
53 | my $self = shift; | |
17f8d455 TC |
54 | |
55 | $self->_valid | |
56 | or return; | |
57 | ||
50c75381 TC |
58 | my %input = @_; |
59 | if (exists $input{channel}) { | |
60 | i_ft2_cp($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'}, | |
61 | $input{channel}, $input{size}, $input{sizew} || 0, | |
62 | $input{string}, , $input{align}, $input{aa}, $input{vlayout}, | |
63 | $input{utf8}); | |
64 | } else { | |
65 | i_ft2_text($self->{id}, $input{image}{IMG}, | |
66 | $input{'x'}, $input{'y'}, | |
67 | $input{color}, $input{size}, $input{sizew} || 0, | |
68 | $input{string}, $input{align}, $input{aa}, $input{vlayout}, | |
69 | $input{utf8}); | |
70 | } | |
71 | } | |
72 | ||
73 | sub _bounding_box { | |
74 | my $self = shift; | |
75 | my %input = @_; | |
76 | ||
17f8d455 TC |
77 | $self->_valid |
78 | or return; | |
79 | ||
50c75381 TC |
80 | return i_ft2_bbox($self->{id}, $input{size}, $input{sizew}, $input{string}, |
81 | $input{utf8}); | |
82 | } | |
83 | ||
84 | sub dpi { | |
85 | my $self = shift; | |
17f8d455 TC |
86 | |
87 | $self->_valid | |
88 | or return; | |
89 | ||
50c75381 TC |
90 | my @old = i_ft2_getdpi($self->{id}); |
91 | if (@_) { | |
92 | my %hsh = @_; | |
93 | my $result; | |
94 | unless ($hsh{xdpi} && $hsh{ydpi}) { | |
95 | if ($hsh{dpi}) { | |
96 | $hsh{xdpi} = $hsh{ydpi} = $hsh{dpi}; | |
97 | } | |
98 | else { | |
99 | $Imager::ERRSTR = "dpi method requires xdpi and ydpi or just dpi"; | |
100 | return; | |
101 | } | |
102 | i_ft2_setdpi($self->{id}, $hsh{xdpi}, $hsh{ydpi}) or return; | |
103 | } | |
104 | } | |
105 | ||
106 | return @old; | |
107 | } | |
108 | ||
109 | sub hinting { | |
110 | my ($self, %opts) = @_; | |
111 | ||
17f8d455 TC |
112 | $self->_valid |
113 | or return; | |
114 | ||
50c75381 TC |
115 | i_ft2_sethinting($self->{id}, $opts{hinting} || 0); |
116 | } | |
117 | ||
118 | sub _transform { | |
119 | my $self = shift; | |
120 | ||
17f8d455 TC |
121 | $self->_valid |
122 | or return; | |
123 | ||
50c75381 TC |
124 | my %hsh = @_; |
125 | my $matrix = $hsh{matrix} or return undef; | |
126 | ||
127 | return i_ft2_settransform($self->{id}, $matrix) | |
128 | } | |
129 | ||
130 | sub utf8 { | |
131 | return 1; | |
132 | } | |
133 | ||
134 | # check if the font has the characters in the given string | |
135 | sub has_chars { | |
136 | my ($self, %hsh) = @_; | |
137 | ||
17f8d455 TC |
138 | $self->_valid |
139 | or return; | |
140 | ||
50c75381 TC |
141 | unless (defined $hsh{string} && length $hsh{string}) { |
142 | $Imager::ERRSTR = "No string supplied to \$font->has_chars()"; | |
143 | return; | |
144 | } | |
145 | return i_ft2_has_chars($self->{id}, $hsh{string}, | |
146 | _first($hsh{'utf8'}, $self->{utf8}, 0)); | |
147 | } | |
148 | ||
149 | sub face_name { | |
150 | my ($self) = @_; | |
151 | ||
17f8d455 TC |
152 | $self->_valid |
153 | or return; | |
154 | ||
50c75381 TC |
155 | i_ft2_face_name($self->{id}); |
156 | } | |
157 | ||
158 | sub can_glyph_names { | |
159 | i_ft2_can_do_glyph_names(); | |
160 | } | |
161 | ||
162 | sub glyph_names { | |
163 | my ($self, %input) = @_; | |
164 | ||
17f8d455 TC |
165 | $self->_valid |
166 | or return; | |
167 | ||
50c75381 TC |
168 | my $string = $input{string}; |
169 | defined $string | |
170 | or return Imager->_set_error("no string parameter passed to glyph_names"); | |
171 | my $utf8 = _first($input{utf8}, 0); | |
172 | my $reliable_only = _first($input{reliable_only}, 1); | |
173 | ||
174 | my @names = i_ft2_glyph_name($self->{id}, $string, $utf8, $reliable_only); | |
175 | @names or return Imager->_set_error(Imager->_error_as_msg); | |
176 | ||
177 | return @names if wantarray; | |
178 | return pop @names; | |
179 | } | |
180 | ||
181 | sub is_mm { | |
182 | my ($self) = @_; | |
183 | ||
17f8d455 TC |
184 | $self->_valid |
185 | or return; | |
186 | ||
50c75381 TC |
187 | i_ft2_is_multiple_master($self->{id}); |
188 | } | |
189 | ||
190 | sub mm_axes { | |
191 | my ($self) = @_; | |
192 | ||
17f8d455 TC |
193 | $self->_valid |
194 | or return; | |
195 | ||
50c75381 TC |
196 | my ($num_axis, $num_design, @axes) = |
197 | i_ft2_get_multiple_masters($self->{id}) | |
198 | or return Imager->_set_error(Imager->_error_as_msg); | |
199 | ||
200 | return @axes; | |
201 | } | |
202 | ||
203 | sub set_mm_coords { | |
204 | my ($self, %opts) = @_; | |
205 | ||
17f8d455 TC |
206 | $self->_valid |
207 | or return; | |
208 | ||
50c75381 TC |
209 | $opts{coords} |
210 | or return Imager->_set_error("Missing coords parameter"); | |
211 | ref($opts{coords}) && $opts{coords} =~ /ARRAY\(0x[\da-f]+\)$/ | |
212 | or return Imager->_set_error("coords parameter must be an ARRAY ref"); | |
213 | ||
214 | i_ft2_set_mm_coords($self->{id}, @{$opts{coords}}) | |
215 | or return Imager->_set_error(Imager->_error_as_msg); | |
216 | ||
217 | return 1; | |
218 | } | |
17f8d455 TC |
219 | |
220 | # objects may be invalidated on thread creation (or Win32 fork emulation) | |
221 | sub _valid { | |
222 | my $self = shift; | |
223 | ||
224 | unless ($self->{id} && Scalar::Util::blessed($self->{id})) { | |
225 | Imager->_set_error("font object was created in another thread"); | |
226 | return; | |
227 | } | |
228 | ||
229 | return 1; | |
230 | } | |
231 | ||
50c75381 TC |
232 | 1; |
233 | ||
234 | __END__ | |
235 | ||
236 | =head1 NAME | |
237 | ||
238 | Imager::Font::FT2 - font support using FreeType 2 | |
239 | ||
240 | =head1 SYNOPSIS | |
241 | ||
242 | use Imager; | |
243 | ||
244 | my $img = Imager->new; | |
245 | my $font = Imager::Font->new(file => "foo.ttf", type => "ft2"); | |
246 | ||
247 | $img->string(... font => $font); | |
248 | ||
249 | =head1 DESCRIPTION | |
250 | ||
251 | This provides font support on FreeType 2. | |
252 | ||
253 | =head1 CAVEATS | |
254 | ||
255 | Unfortunately, older versions of Imager would install | |
256 | C<Imager::Font::FreeType2> even if FreeType 2 wasn't available, and if | |
257 | no font was created would succeed in loading the module. This means | |
258 | that an existing C<FreeType2.pm> could cause a probe success for | |
259 | supported font files, so I've renamed it. | |
260 | ||
261 | =head1 AUTHOR | |
262 | ||
5b480b14 | 263 | Tony Cook <tonyc@cpan.org> |
50c75381 TC |
264 | |
265 | =head1 SEE ALSO | |
266 | ||
267 | Imager, Imager::Font. | |
268 | ||
269 | =cut |