| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Imager::Font; | 
| 2 | 58 |  |  | 58 |  | 914 | use 5.006; | 
|  | 58 |  |  |  |  | 161 |  | 
| 3 | 58 |  |  | 58 |  | 263 | use Imager::Color; | 
|  | 58 |  |  |  |  | 91 |  | 
|  | 58 |  |  |  |  | 969 |  | 
| 4 | 58 |  |  | 58 |  | 234 | use strict; | 
|  | 58 |  |  |  |  | 79 |  | 
|  | 58 |  |  |  |  | 98740 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | our $VERSION = "1.039"; | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | # the aim here is that we can: | 
| 9 |  |  |  |  |  |  | #  - add file based types in one place: here | 
| 10 |  |  |  |  |  |  | #  - make sure we only attempt to create types that exist | 
| 11 |  |  |  |  |  |  | #  - give reasonable defaults | 
| 12 |  |  |  |  |  |  | #  - give the user some control over which types get used | 
| 13 |  |  |  |  |  |  | my %drivers = | 
| 14 |  |  |  |  |  |  | ( | 
| 15 |  |  |  |  |  |  | tt=>{ | 
| 16 |  |  |  |  |  |  | class=>'Imager::Font::Truetype', | 
| 17 |  |  |  |  |  |  | module=>'Imager/Font/Truetype.pm', | 
| 18 |  |  |  |  |  |  | files=>'.*\.ttf$', | 
| 19 |  |  |  |  |  |  | description => 'FreeType 1.x', | 
| 20 |  |  |  |  |  |  | checktype => 1, | 
| 21 |  |  |  |  |  |  | }, | 
| 22 |  |  |  |  |  |  | t1=>{ | 
| 23 |  |  |  |  |  |  | class=>'Imager::Font::T1', | 
| 24 |  |  |  |  |  |  | module=>'Imager/Font/T1.pm', | 
| 25 |  |  |  |  |  |  | files=>'.*\.pfb$', | 
| 26 |  |  |  |  |  |  | description => 'T1Lib', | 
| 27 |  |  |  |  |  |  | }, | 
| 28 |  |  |  |  |  |  | ft2=>{ | 
| 29 |  |  |  |  |  |  | class=>'Imager::Font::FT2', | 
| 30 |  |  |  |  |  |  | module=>'Imager/Font/FT2.pm', | 
| 31 |  |  |  |  |  |  | files=>'.*\.(pfa|pfb|otf|ttf|fon|fnt|dfont|pcf(\.gz)?)$', | 
| 32 |  |  |  |  |  |  | description => 'FreeType 2.x', | 
| 33 |  |  |  |  |  |  | }, | 
| 34 |  |  |  |  |  |  | ifs=>{ | 
| 35 |  |  |  |  |  |  | class=>'Imager::Font::Image', | 
| 36 |  |  |  |  |  |  | module=>'Imager/Font/Image.pm', | 
| 37 |  |  |  |  |  |  | files=>'.*\.ifs$', | 
| 38 |  |  |  |  |  |  | }, | 
| 39 |  |  |  |  |  |  | w32=>{ | 
| 40 |  |  |  |  |  |  | class=>'Imager::Font::W32', | 
| 41 |  |  |  |  |  |  | module=>'Imager/Font/W32.pm', | 
| 42 |  |  |  |  |  |  | description => 'Win32 GDI Fonts', | 
| 43 |  |  |  |  |  |  | }, | 
| 44 |  |  |  |  |  |  | ); | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | # this currently should only contain file based types, don't add w32 | 
| 47 |  |  |  |  |  |  | my @priority = qw(ft2 ifs); | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | sub new { | 
| 50 | 2 |  |  | 2 | 1 | 20 | my $class = shift; | 
| 51 | 2 |  |  |  |  | 4 | my $self = {}; | 
| 52 | 2 |  |  |  |  | 5 | my ($file, $type, $id); | 
| 53 | 2 |  |  |  |  | 14 | my %hsh=(color => Imager::Color->new(255,0,0,255), | 
| 54 |  |  |  |  |  |  | size => 15, | 
| 55 |  |  |  |  |  |  | @_); | 
| 56 |  |  |  |  |  |  |  | 
| 57 | 2 |  |  |  |  | 7 | bless $self,$class; | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 2 | 50 |  |  |  | 7 | if ($hsh{'file'}) { | 
|  |  | 0 |  |  |  |  |  | 
| 60 | 2 |  |  |  |  | 4 | $file = $hsh{'file'}; | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 2 |  |  |  |  | 4 | $type = $hsh{'type'}; | 
| 63 | 2 | 50 |  |  |  | 7 | if (defined $type) { | 
| 64 | 0 | 0 |  |  |  | 0 | unless ($drivers{$type}) { | 
| 65 | 0 |  |  |  |  | 0 | Imager->_set_error("Unknown font type $type"); | 
| 66 | 0 |  |  |  |  | 0 | return; | 
| 67 |  |  |  |  |  |  | } | 
| 68 |  |  |  |  |  |  |  | 
| 69 | 0 | 0 |  |  |  | 0 | unless ($Imager::formats{$type}) { | 
| 70 | 0 |  |  |  |  | 0 | Imager->_set_error("The $type {$drivers{$type}) font driver is not installed"); | 
| 71 | 0 |  |  |  |  | 0 | return; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  | else { | 
| 75 | 2 |  |  |  |  | 5 | for my $drv (@priority) { | 
| 76 | 4 |  |  |  |  | 9 | undef $type; | 
| 77 | 4 | 50 |  |  |  | 14 | my $re = $drivers{$drv}{files} or next; | 
| 78 | 4 | 100 |  |  |  | 64 | if ($file =~ /$re/i) { | 
| 79 | 3 | 100 | 33 |  |  | 23 | if (eval { require $drivers{$drv}{module}; 1 } and !( $drivers{$drv}{checktype} && !$Imager::formats{$drv} )) { | 
|  | 3 |  | 66 |  |  | 649 |  | 
|  | 1 |  |  |  |  | 133 |  | 
| 80 | 1 |  |  |  |  | 4 | $type = $drv; | 
| 81 | 1 |  |  |  |  | 2 | last; | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  | } | 
| 86 | 2 | 100 |  |  |  | 21 | if (!defined($type)) { | 
| 87 |  |  |  |  |  |  | # some types we can support, but the driver isn't available | 
| 88 |  |  |  |  |  |  | # work out which drivers support it, so we can provide the user | 
| 89 |  |  |  |  |  |  | # some useful information on how to get it working | 
| 90 | 1 |  |  |  |  | 2 | my @not_here; | 
| 91 | 1 |  |  |  |  | 4 | for my $driver_name (keys %drivers) { | 
| 92 | 5 |  |  |  |  | 8 | my $driver = $drivers{$driver_name}; | 
| 93 |  |  |  |  |  |  | push @not_here, "$driver_name ($driver->{description})" | 
| 94 | 5 | 100 | 100 |  |  | 71 | if $driver->{files} && $file =~ /$driver->{files}/i; | 
| 95 |  |  |  |  |  |  | } | 
| 96 | 1 | 50 |  |  |  | 4 | if (@not_here) { | 
| 97 | 1 |  |  |  |  | 5 | $Imager::ERRSTR = "No font drivers enabled that can support this file, rebuild Imager with any of ".join(", ", @not_here)." to use this font file"; | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  | else { | 
| 100 | 0 |  |  |  |  | 0 | $Imager::ERRSTR = "No font type found for $hsh{'file'}"; | 
| 101 |  |  |  |  |  |  | } | 
| 102 | 1 |  |  |  |  | 13 | return; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  | } elsif ($hsh{face}) { | 
| 105 | 0 |  |  |  |  | 0 | $type = "w32"; | 
| 106 |  |  |  |  |  |  | } else { | 
| 107 | 0 |  |  |  |  | 0 | $Imager::ERRSTR="No font file specified"; | 
| 108 | 0 |  |  |  |  | 0 | return; | 
| 109 |  |  |  |  |  |  | } | 
| 110 |  |  |  |  |  |  |  | 
| 111 | 1 | 50 | 33 |  |  | 5 | if ($drivers{$type}{checktype} && !$Imager::formats{$type}) { | 
| 112 | 0 |  |  |  |  | 0 | $Imager::ERRSTR = "`$type' not enabled"; | 
| 113 | 0 |  |  |  |  | 0 | return; | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | # here we should have the font type or be dead already. | 
| 117 |  |  |  |  |  |  |  | 
| 118 | 1 |  |  |  |  | 5 | require $drivers{$type}{module}; | 
| 119 | 1 |  |  |  |  | 8 | return $drivers{$type}{class}->new(%hsh); | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | # returns first defined parameter | 
| 123 |  |  |  |  |  |  | sub _first { | 
| 124 | 0 |  |  | 0 |  | 0 | for (@_) { | 
| 125 | 0 | 0 |  |  |  | 0 | return $_ if defined $_; | 
| 126 |  |  |  |  |  |  | } | 
| 127 | 0 |  |  |  |  | 0 | return undef; | 
| 128 |  |  |  |  |  |  | } | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | sub draw { | 
| 131 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 132 | 0 |  |  |  |  | 0 | my %input = ('x' => 0, 'y' => 0, @_); | 
| 133 | 0 | 0 |  |  |  | 0 | unless ($input{image}) { | 
| 134 | 0 |  |  |  |  | 0 | $Imager::ERRSTR = 'No image supplied to $font->draw()'; | 
| 135 | 0 |  |  |  |  | 0 | return; | 
| 136 |  |  |  |  |  |  | } | 
| 137 | 0 |  |  |  |  | 0 | my $image = $input{image}; | 
| 138 | 0 |  |  |  |  | 0 | $input{string} = _first($input{string}, $input{text}); | 
| 139 | 0 | 0 |  |  |  | 0 | unless (defined $input{string}) { | 
| 140 | 0 |  |  |  |  | 0 | $image->_set_error("Missing required parameter 'string'"); | 
| 141 | 0 |  |  |  |  | 0 | return; | 
| 142 |  |  |  |  |  |  | } | 
| 143 | 0 |  |  |  |  | 0 | $input{aa} = _first($input{aa}, $input{antialias}, $self->{aa}, 1); | 
| 144 |  |  |  |  |  |  | # the original draw code worked this out but didn't use it | 
| 145 | 0 |  |  |  |  | 0 | $input{align} = _first($input{align}, $self->{align}); | 
| 146 | 0 |  |  |  |  | 0 | $input{color} = _first($input{color}, $self->{color}); | 
| 147 | 0 |  |  |  |  | 0 | $input{color} = Imager::_color($input{'color'}); | 
| 148 |  |  |  |  |  |  |  | 
| 149 | 0 |  |  |  |  | 0 | $input{size} = _first($input{size}, $self->{size}); | 
| 150 | 0 | 0 |  |  |  | 0 | unless (defined $input{size}) { | 
| 151 | 0 |  |  |  |  | 0 | $image->_set_error("No font size provided"); | 
| 152 | 0 |  |  |  |  | 0 | return undef; | 
| 153 |  |  |  |  |  |  | } | 
| 154 | 0 |  |  |  |  | 0 | $input{align} = _first($input{align}, 1); | 
| 155 | 0 |  |  |  |  | 0 | $input{utf8} = _first($input{utf8}, $self->{utf8}, 0); | 
| 156 | 0 |  |  |  |  | 0 | $input{vlayout} = _first($input{vlayout}, $self->{vlayout}, 0); | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 0 |  |  |  |  | 0 | my $result = $self->_draw(%input); | 
| 159 | 0 | 0 |  |  |  | 0 | unless ($result) { | 
| 160 | 0 |  |  |  |  | 0 | $image->_set_error($image->_error_as_msg()); | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 0 |  |  |  |  | 0 | return $result; | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | sub align { | 
| 167 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 168 | 0 |  |  |  |  | 0 | my %input = ( halign => 'left', valign => 'baseline', | 
| 169 |  |  |  |  |  |  | 'x' => 0, 'y' => 0, @_ ); | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | # image needs to be supplied, but can be supplied as undef | 
| 172 | 0 | 0 |  |  |  | 0 | unless (exists $input{image}) { | 
| 173 | 0 |  |  |  |  | 0 | Imager->_set_error("Missing required parameter 'image'"); | 
| 174 | 0 |  |  |  |  | 0 | return; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  |  | 
| 177 | 0 |  | 0 |  |  | 0 | my $errors_to = $input{image} || 'Imager'; | 
| 178 |  |  |  |  |  |  |  | 
| 179 | 0 |  |  |  |  | 0 | my $text = _first($input{string}, $input{text}); | 
| 180 | 0 | 0 |  |  |  | 0 | unless (defined $text) { | 
| 181 | 0 |  |  |  |  | 0 | $errors_to->_set_error("Missing required parameter 'string'"); | 
| 182 | 0 |  |  |  |  | 0 | return; | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  |  | 
| 185 | 0 |  |  |  |  | 0 | my $size = _first($input{size}, $self->{size}); | 
| 186 | 0 |  |  |  |  | 0 | my $utf8 = _first($input{utf8}, 0); | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 0 |  |  |  |  | 0 | my $bbox = $self->bounding_box(string=>$text, size=>$size, utf8=>$utf8); | 
| 189 | 0 |  |  |  |  | 0 | my $valign = $input{valign}; | 
| 190 | 0 | 0 | 0 |  |  | 0 | $valign = 'baseline' | 
| 191 |  |  |  |  |  |  | unless $valign && $valign =~ /^(?:top|center|bottom|baseline)$/; | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 0 |  |  |  |  | 0 | my $halign = $input{halign}; | 
| 194 | 0 | 0 | 0 |  |  | 0 | $halign = 'start' | 
| 195 |  |  |  |  |  |  | unless $halign && $halign =~ /^(?:left|start|center|end|right)$/; | 
| 196 |  |  |  |  |  |  |  | 
| 197 | 0 |  |  |  |  | 0 | my $x = $input{'x'}; | 
| 198 | 0 |  |  |  |  | 0 | my $y = $input{'y'}; | 
| 199 |  |  |  |  |  |  |  | 
| 200 | 0 | 0 |  |  |  | 0 | if ($valign eq 'top') { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 201 | 0 |  |  |  |  | 0 | $y += $bbox->ascent; | 
| 202 |  |  |  |  |  |  | } | 
| 203 |  |  |  |  |  |  | elsif ($valign eq 'center') { | 
| 204 | 0 |  |  |  |  | 0 | $y += $bbox->ascent - $bbox->text_height / 2; | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  | elsif ($valign eq 'bottom') { | 
| 207 | 0 |  |  |  |  | 0 | $y += $bbox->descent; | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  | # else baseline is the default | 
| 210 |  |  |  |  |  |  |  | 
| 211 | 0 | 0 |  |  |  | 0 | if ($halign eq 'left') { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 212 | 0 |  |  |  |  | 0 | $x -= $bbox->start_offset; | 
| 213 |  |  |  |  |  |  | } | 
| 214 |  |  |  |  |  |  | elsif ($halign eq 'start') { | 
| 215 |  |  |  |  |  |  | # nothing to do | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  | elsif ($halign eq 'center') { | 
| 218 | 0 |  |  |  |  | 0 | $x -= $bbox->start_offset + $bbox->total_width / 2; | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  | elsif ($halign eq 'end') { | 
| 221 | 0 |  |  |  |  | 0 | $x -= $bbox->advance_width; | 
| 222 |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  | elsif ($halign eq 'right') { | 
| 224 | 0 |  |  |  |  | 0 | $x -= $bbox->advance_width - $bbox->right_bearing; | 
| 225 |  |  |  |  |  |  | } | 
| 226 | 0 |  |  |  |  | 0 | $x = int($x); | 
| 227 | 0 |  |  |  |  | 0 | $y = int($y); | 
| 228 |  |  |  |  |  |  |  | 
| 229 | 0 | 0 |  |  |  | 0 | if ($input{image}) { | 
| 230 | 0 |  |  |  |  | 0 | delete @input{qw/x y/}; | 
| 231 | 0 | 0 |  |  |  | 0 | $self->draw(%input, 'x' => $x, 'y' => $y, align=>1) | 
| 232 |  |  |  |  |  |  | or return; | 
| 233 |  |  |  |  |  |  | } | 
| 234 |  |  |  |  |  |  |  | 
| 235 | 0 |  |  |  |  | 0 | return ($x+$bbox->start_offset, $y-$bbox->ascent, | 
| 236 |  |  |  |  |  |  | $x+$bbox->end_offset, $y-$bbox->descent+1); | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | sub bounding_box { | 
| 240 | 0 |  |  | 0 | 1 | 0 | my $self=shift; | 
| 241 | 0 |  |  |  |  | 0 | my %input=@_; | 
| 242 |  |  |  |  |  |  |  | 
| 243 | 0 | 0 |  |  |  | 0 | if (!exists $input{'string'}) { | 
| 244 | 0 |  |  |  |  | 0 | $Imager::ERRSTR='string parameter missing'; | 
| 245 | 0 |  |  |  |  | 0 | return; | 
| 246 |  |  |  |  |  |  | } | 
| 247 | 0 |  | 0 |  |  | 0 | $input{size} ||= $self->{size}; | 
| 248 | 0 |  |  |  |  | 0 | $input{sizew} = _first($input{sizew}, $self->{sizew}, 0); | 
| 249 | 0 |  |  |  |  | 0 | $input{utf8} = _first($input{utf8}, $self->{utf8}, 0); | 
| 250 |  |  |  |  |  |  |  | 
| 251 | 0 | 0 |  |  |  | 0 | my @box = $self->_bounding_box(%input) | 
| 252 |  |  |  |  |  |  | or return; | 
| 253 |  |  |  |  |  |  |  | 
| 254 | 0 | 0 |  |  |  | 0 | if (wantarray) { | 
| 255 | 0 | 0 | 0 |  |  | 0 | if(@box && exists $input{'x'} and exists $input{'y'}) { | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 256 | 0 |  |  |  |  | 0 | my($gdescent, $gascent)=@box[1,3]; | 
| 257 | 0 |  |  |  |  | 0 | $box[1]=$input{'y'}-$gascent;      # top = base - ascent (Y is down) | 
| 258 | 0 |  |  |  |  | 0 | $box[3]=$input{'y'}-$gdescent;     # bottom = base - descent (Y is down, descent is negative) | 
| 259 | 0 |  |  |  |  | 0 | $box[0]+=$input{'x'}; | 
| 260 | 0 |  |  |  |  | 0 | $box[2]+=$input{'x'}; | 
| 261 |  |  |  |  |  |  | } elsif (@box && $input{'canon'}) { | 
| 262 | 0 |  |  |  |  | 0 | $box[3]-=$box[1];    # make it canonical (ie (0,0) - (width, height)) | 
| 263 | 0 |  |  |  |  | 0 | $box[2]-=$box[0]; | 
| 264 |  |  |  |  |  |  | } | 
| 265 | 0 |  |  |  |  | 0 | return @box; | 
| 266 |  |  |  |  |  |  | } | 
| 267 |  |  |  |  |  |  | else { | 
| 268 | 0 |  |  |  |  | 0 | require Imager::Font::BBox; | 
| 269 |  |  |  |  |  |  |  | 
| 270 | 0 |  |  |  |  | 0 | return Imager::Font::BBox->new(@box); | 
| 271 |  |  |  |  |  |  | } | 
| 272 |  |  |  |  |  |  | } | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | sub dpi { | 
| 275 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | # I'm assuming a default of 72 dpi | 
| 278 | 0 |  |  |  |  | 0 | my @old = (72, 72); | 
| 279 | 0 | 0 |  |  |  | 0 | if (@_) { | 
| 280 | 0 |  |  |  |  | 0 | $Imager::ERRSTR = "Setting dpi not implemented for this font type"; | 
| 281 | 0 |  |  |  |  | 0 | return; | 
| 282 |  |  |  |  |  |  | } | 
| 283 |  |  |  |  |  |  |  | 
| 284 | 0 |  |  |  |  | 0 | return @old; | 
| 285 |  |  |  |  |  |  | } | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | sub transform { | 
| 288 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 289 |  |  |  |  |  |  |  | 
| 290 | 0 |  |  |  |  | 0 | my %hsh = @_; | 
| 291 |  |  |  |  |  |  |  | 
| 292 |  |  |  |  |  |  | # this is split into transform() and _transform() so we can | 
| 293 |  |  |  |  |  |  | # implement other tags like: degrees=>12, which would build a | 
| 294 |  |  |  |  |  |  | # 12 degree rotation matrix | 
| 295 |  |  |  |  |  |  | # but I'll do that later | 
| 296 | 0 | 0 |  |  |  | 0 | unless ($hsh{matrix}) { | 
| 297 | 0 |  |  |  |  | 0 | $Imager::ERRSTR = "You need to supply a matrix"; | 
| 298 | 0 |  |  |  |  | 0 | return; | 
| 299 |  |  |  |  |  |  | } | 
| 300 |  |  |  |  |  |  |  | 
| 301 | 0 |  |  |  |  | 0 | return $self->_transform(%hsh); | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | sub _transform { | 
| 305 | 0 |  |  | 0 |  | 0 | $Imager::ERRSTR = "This type of font cannot be transformed"; | 
| 306 | 0 |  |  |  |  | 0 | return; | 
| 307 |  |  |  |  |  |  | } | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | sub utf8 { | 
| 310 | 0 |  |  | 0 | 1 | 0 | return 0; | 
| 311 |  |  |  |  |  |  | } | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | sub priorities { | 
| 314 | 1 |  |  | 1 | 1 | 2 | my $self = shift; | 
| 315 | 1 |  |  |  |  | 3 | my @old = @priority; | 
| 316 |  |  |  |  |  |  |  | 
| 317 | 1 | 50 |  |  |  | 4 | if (@_) { | 
| 318 | 1 |  |  |  |  | 3 | @priority = @_; | 
| 319 |  |  |  |  |  |  | } | 
| 320 | 1 |  |  |  |  | 3 | return @old; | 
| 321 |  |  |  |  |  |  | } | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | sub register { | 
| 324 | 5 |  |  | 5 | 1 | 88 | my ($self, %opts) = @_; | 
| 325 |  |  |  |  |  |  |  | 
| 326 | 5 |  |  |  |  | 10 | my $type = delete $opts{type}; | 
| 327 | 5 |  |  |  |  | 8 | my $class = delete $opts{class}; | 
| 328 | 5 |  |  |  |  | 8 | my $files = delete $opts{files}; | 
| 329 | 5 |  | 66 |  |  | 20 | my $description = delete $opts{description} || $class; | 
| 330 |  |  |  |  |  |  |  | 
| 331 | 5 | 100 |  |  |  | 14 | defined $type | 
| 332 |  |  |  |  |  |  | or return Imager->_set_error("No type parameter supplied to Imager::Font->regster"); | 
| 333 |  |  |  |  |  |  |  | 
| 334 | 4 | 100 |  |  |  | 8 | defined $class | 
| 335 |  |  |  |  |  |  | or return Imager->_set_error("No class parameter supplied to Imager::Font->register"); | 
| 336 |  |  |  |  |  |  |  | 
| 337 | 3 | 50 |  |  |  | 8 | if ($files) { | 
| 338 | 3 | 100 |  |  |  | 3 | eval { qr/$files/ } | 
|  | 3 |  |  |  |  | 32 |  | 
| 339 |  |  |  |  |  |  | or return Imager->_set_error("files isn't a valid regexp"); | 
| 340 |  |  |  |  |  |  | } | 
| 341 |  |  |  |  |  |  |  | 
| 342 | 2 | 50 | 33 |  |  | 10 | if ($drivers{$type} && $drivers{$type}{class} ne $class) { | 
| 343 | 0 |  |  |  |  | 0 | Imager->_set_error("Font type $type already registered as $drivers{$type}{class}"); | 
| 344 | 0 |  |  |  |  | 0 | return; | 
| 345 |  |  |  |  |  |  | } | 
| 346 |  |  |  |  |  |  |  | 
| 347 | 2 |  |  |  |  | 6 | (my $module = $class . ".pm") =~ s(::)(/)g; | 
| 348 |  |  |  |  |  |  |  | 
| 349 | 2 |  |  |  |  | 6 | my $driver = | 
| 350 |  |  |  |  |  |  | { | 
| 351 |  |  |  |  |  |  | class => $class, | 
| 352 |  |  |  |  |  |  | module => $module, | 
| 353 |  |  |  |  |  |  | description => $description, | 
| 354 |  |  |  |  |  |  | }; | 
| 355 | 2 | 50 |  |  |  | 5 | $files and $driver->{files} = $files; | 
| 356 |  |  |  |  |  |  |  | 
| 357 | 2 |  |  |  |  | 4 | $drivers{$type} = $driver; | 
| 358 |  |  |  |  |  |  |  | 
| 359 | 2 |  |  |  |  | 9 | 1; | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | 1; | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | __END__ |