File Coverage

blib/lib/PDF/API3/Compat/API2/Resource/Font/SynFont.pm
Criterion Covered Total %
statement 29 139 20.8
branch 0 48 0.0
condition 0 34 0.0
subroutine 10 12 83.3
pod 2 2 100.0
total 41 235 17.4


line stmt bran cond sub pod time code
1             #=======================================================================
2             # ____ ____ _____ _ ____ ___ ____
3             # | _ \| _ \| ___| _ _ / \ | _ \_ _| |___ \
4             # | |_) | | | | |_ (_) (_) / _ \ | |_) | | __) |
5             # | __/| |_| | _| _ _ / ___ \| __/| | / __/
6             # |_| |____/|_| (_) (_) /_/ \_\_| |___| |_____|
7             #
8             # A Perl Module Chain to faciliate the Creation and Modification
9             # of High-Quality "Portable Document Format (PDF)" Files.
10             #
11             # Copyright 1999-2005 Alfred Reibenschuh .
12             #
13             #=======================================================================
14             #
15             # This library is free software; you can redistribute it and/or
16             # modify it under the terms of the GNU Lesser General Public
17             # License as published by the Free Software Foundation; either
18             # version 2 of the License, or (at your option) any later version.
19             #
20             # This library is distributed in the hope that it will be useful,
21             # but WITHOUT ANY WARRANTY; without even the implied warranty of
22             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23             # Lesser General Public License for more details.
24             #
25             # You should have received a copy of the GNU Lesser General Public
26             # License along with this library; if not, write to the
27             # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28             # Boston, MA 02111-1307, USA.
29             #
30             # $Id: SynFont.pm,v 2.2 2008/08/10 14:43:08 areibens Exp $
31             #
32             #=======================================================================
33             package PDF::API3::Compat::API2::Resource::Font::SynFont;
34            
35             BEGIN {
36            
37 1     1   8 use utf8;
  1         2  
  1         11  
38 1     1   36 use Encode qw(:all);
  1         2  
  1         382  
39            
40 1     1   6 use vars qw( @ISA $VERSION );
  1         3  
  1         54  
41 1     1   5 use PDF::API3::Compat::API2::Resource::Font;
  1         3  
  1         34  
42 1     1   6 use PDF::API3::Compat::API2::Util;
  1         2  
  1         232  
43 1     1   7 use PDF::API3::Compat::API2::Basic::PDF::Utils;
  1         2  
  1         129  
44 1     1   7 use Math::Trig;
  1         2  
  1         268  
45 1     1   7 use Unicode::UCD 'charinfo';
  1         3  
  1         104  
46            
47 1     1   21 @ISA=qw(PDF::API3::Compat::API2::Resource::Font);
48            
49 1         31 ( $VERSION ) = sprintf '%i.%03i', split(/\./,('$Revision: 2.2 $' =~ /Revision: (\S+)\s/)[0]); # $Date: 2008/08/10 14:43:08 $
50            
51             }
52 1     1   5 no warnings qw[ deprecated recursion uninitialized ];
  1         2  
  1         2084  
53            
54             =head1 NAME
55            
56             PDF::API3::Compat::API2::Resource::Font::SynFont - Module for using synthetic Fonts.
57            
58             =head1 SYNOPSIS
59            
60             #
61             use PDF::API3::Compat::API2;
62             #
63             $pdf = PDF::API3::Compat::API2->new;
64             $sft = $pdf->synfont($cft);
65             #
66            
67             =head1 METHODS
68            
69             =over 4
70            
71             =cut
72            
73             =item $font = PDF::API3::Compat::API2::Resource::Font::SynFont->new $pdf, $fontobj, %options
74            
75             Returns a synfont object.
76            
77             =cut
78            
79             =pod
80            
81             Valid %options are:
82            
83             I<-encode>
84             ... changes the encoding of the font from its default.
85             See I for the supported values.
86            
87             I<-pdfname>
88             ... changes the reference-name of the font from its default.
89             The reference-name is normally generated automatically and can be
90             retrived via $pdfname=$font->name.
91            
92             I<-slant>
93             ... slant/expansion factor (0.1-0.9 = slant, 1.1+ = expansion).
94            
95             I<-oblique>
96             ... italic angle (+/-)
97            
98             I<-bold>
99             ... embolding factor (0.1+, bold=1, heavy=2, ...).
100            
101             I<-space>
102             ... additional charspacing in em (0-1000).
103            
104             I<-caps>
105             ... create synthetic small-caps.
106            
107             =cut
108            
109             sub new
110             {
111 0     0 1   my ($class,$pdf,$font,@opts) = @_;
112 0           my ($self,$data);
113 0           my %opts=@opts;
114 0           my $first=1;
115 0           my $last=255;
116 0   0       my $slant=$opts{-slant}||1;
117 0   0       my $oblique=$opts{-oblique}||0;
118 0   0       my $space=$opts{-space}||'0';
119 0   0       my $bold=($opts{-bold}||0)*10; # convert to em
120            
121 0           $self->{' slant'}=$slant;
122 0           $self->{' oblique'}=$oblique;
123 0           $self->{' bold'}=$bold;
124 0           $self->{' boldmove'}=0.001;
125 0           $self->{' space'}=$space;
126            
127 0 0         $class = ref $class if ref $class;
128 0 0         $self = $class->SUPER::new($pdf,
    0          
129             pdfkey()
130             .'+'.($font->name)
131             .($opts{-caps} ? '+Caps' : '')
132             .($opts{-vname} ? '+'.$opts{-vname} : '')
133             );
134 0 0         $pdf->new_obj($self) unless($self->is_obj($pdf));
135 0           $self->{' font'}=$font;
136 0           $self->{' data'}={
137             'type' => 'Type3',
138             'ascender' => $font->ascender,
139             'capheight' => $font->capheight,
140             'descender' => $font->descender,
141             'iscore' => '0',
142             'isfixedpitch' => $font->isfixedpitch,
143             'italicangle' => $font->italicangle + $oblique,
144             'missingwidth' => $font->missingwidth * $slant,
145             'underlineposition' => $font->underlineposition,
146             'underlinethickness' => $font->underlinethickness,
147             'xheight' => $font->xheight,
148             'firstchar' => $first,
149             'lastchar' => $last,
150             'char' => [ '.notdef' ],
151             'uni' => [ 0 ],
152             'u2e' => { 0 => 0 },
153             'fontbbox' => '',
154             'wx' => { 'space' => '600' },
155             };
156            
157 0 0         if(ref($font->fontbbox))
158             {
159 0           $self->data->{fontbbox}=[ @{$font->fontbbox} ];
  0            
160             }
161             else
162             {
163 0           $self->data->{fontbbox}=[ $font->fontbbox ];
164             }
165 0           $self->data->{fontbbox}->[0]*=$slant;
166 0           $self->data->{fontbbox}->[2]*=$slant;
167            
168 0           $self->{'Subtype'} = PDFName('Type3');
169 0           $self->{'FirstChar'} = PDFNum($first);
170 0           $self->{'LastChar'} = PDFNum($last);
171 0           $self->{'FontMatrix'} = PDFArray(map { PDFNum($_) } ( 0.001, 0, 0, 0.001, 0, 0 ) );
  0            
172 0           $self->{'FontBBox'} = PDFArray(map { PDFNum($_) } ( $self->fontbbox ) );
  0            
173            
174 0           my $procs=PDFDict();
175 0           $pdf->new_obj($procs);
176 0           $self->{'CharProcs'} = $procs;
177            
178 0           $self->{Resources}=PDFDict();
179 0           $self->{Resources}->{ProcSet}=PDFArray(map { PDFName($_) } qw[ PDF Text ImageB ImageC ImageI ]);
  0            
180 0           my $xo=PDFDict();
181 0           $self->{Resources}->{Font}=$xo;
182 0           $self->{Resources}->{Font}->{FSN}=$font;
183 0           foreach my $w ($first..$last)
184             {
185 0           $self->data->{char}->[$w]=$font->glyphByEnc($w);
186 0           $self->data->{uni}->[$w]=uniByName($self->data->{char}->[$w]);
187 0           $self->data->{u2e}->{$self->data->{uni}->[$w]}=$w;
188             }
189            
190 0 0         if($font->isa('PDF::API3::Compat::API2::Resource::CIDFont'))
191             {
192 0           $self->{'Encoding'}=PDFDict();
193 0           $self->{'Encoding'}->{Type}=PDFName('Encoding');
194 0           $self->{'Encoding'}->{Differences}=PDFArray();
195 0           foreach my $w ($first..$last)
196             {
197 0 0 0       if(defined $self->data->{char}->[$w] && $self->data->{char}->[$w] ne '.notdef')
198             {
199 0           $self->{'Encoding'}->{Differences}->add_elements(PDFNum($w),PDFName($self->data->{char}->[$w]));
200             }
201             }
202             }
203             else
204             {
205 0           $self->{'Encoding'}=$font->{Encoding};
206             }
207            
208             #use Data::Dumper;
209             #print Dumper($self->data);
210 0           my @widths=();
211 0           foreach my $w ($first..$last)
212             {
213 0 0         if($self->data->{char}->[$w] eq '.notdef')
214             {
215 0           push @widths,$self->missingwidth;
216 0           next;
217             }
218 0           my $char=PDFDict();
219 0           my $wth=int($font->width(chr($w))*1000*$slant+2*$space);
220 0           $procs->{$font->glyphByEnc($w)}=$char;
221             #$char->{Filter}=PDFArray(PDFName('FlateDecode'));
222 0           $char->{' stream'}=$wth." 0 ".join(' ',map { int($_) } $self->fontbbox)." d1\n";
  0            
223 0           $char->{' stream'}.="BT\n";
224 0 0         $char->{' stream'}.=join(' ',1,0,tan(deg2rad($oblique)),1,0,0)." Tm\n" if($oblique);
225 0 0         $char->{' stream'}.="2 Tr ".($bold)." w\n" if($bold);
226             # my $ci = charinfo($self->data->{uni}->[$w]);
227 0           my $ci={};
228 0 0         if ($self->data->{uni}->[$w] ne '')
229             {
230 0           $ci = charinfo($self->data->{uni}->[$w]);
231             }
232 0 0 0       if($opts{-caps} && $ci->{upper})
233             {
234 0           $char->{' stream'}.="/FSN 800 Tf\n";
235 0           $char->{' stream'}.=($slant*110)." Tz\n";
236 0 0         $char->{' stream'}.=" [ -$space ] TJ\n" if($space);
237 0           my $ch=$self->encByUni(hex($ci->{upper}));
238 0           $wth=int($font->width(chr($ch))*800*$slant*1.1+2*$space);
239 0           $char->{' stream'}.=$font->text(chr($ch));
240             }
241             else
242             {
243 0           $char->{' stream'}.="/FSN 1000 Tf\n";
244 0 0         $char->{' stream'}.=($slant*100)." Tz\n" if($slant!=1);
245 0 0         $char->{' stream'}.=" [ -$space ] TJ\n" if($space);
246 0           $char->{' stream'}.=$font->text(chr($w));
247             }
248 0           $char->{' stream'}.=" Tj\nET\n";
249 0           push @widths,$wth;
250 0           $self->data->{wx}->{$font->glyphByEnc($w)}=$wth;
251 0           $pdf->new_obj($char);
252             }
253            
254 0           $procs->{'.notdef'}=$procs->{$font->data->{char}->[32]};
255 0           $self->{Widths}=PDFArray(map { PDFNum($_) } @widths);
  0            
256 0           $self->data->{e2n}=$self->data->{char};
257 0           $self->data->{e2u}=$self->data->{uni};
258            
259 0           $self->data->{u2c}={};
260 0           $self->data->{u2e}={};
261 0           $self->data->{u2n}={};
262 0           $self->data->{n2c}={};
263 0           $self->data->{n2e}={};
264 0           $self->data->{n2u}={};
265            
266 0           foreach my $n (reverse 0..255)
267             {
268 0 0 0       $self->data->{n2c}->{$self->data->{char}->[$n] || '.notdef'}=$n unless(defined $self->data->{n2c}->{$self->data->{char}->[$n] || '.notdef'});
      0        
269 0 0 0       $self->data->{n2e}->{$self->data->{e2n}->[$n] || '.notdef'}=$n unless(defined $self->data->{n2e}->{$self->data->{e2n}->[$n] || '.notdef'});
      0        
270            
271 0 0 0       $self->data->{n2u}->{$self->data->{e2n}->[$n] || '.notdef'}=$self->data->{e2u}->[$n] unless(defined $self->data->{n2u}->{$self->data->{e2n}->[$n] || '.notdef'});
      0        
272 0 0 0       $self->data->{n2u}->{$self->data->{char}->[$n] || '.notdef'}=$self->data->{uni}->[$n] unless(defined $self->data->{n2u}->{$self->data->{char}->[$n] || '.notdef'});
      0        
273            
274 0 0         $self->data->{u2c}->{$self->data->{uni}->[$n]}=$n unless(defined $self->data->{u2c}->{$self->data->{uni}->[$n]});
275 0 0         $self->data->{u2e}->{$self->data->{e2u}->[$n]}=$n unless(defined $self->data->{u2e}->{$self->data->{e2u}->[$n]});
276            
277 0 0 0       $self->data->{u2n}->{$self->data->{e2u}->[$n]}=($self->data->{e2n}->[$n] || '.notdef') unless(defined $self->data->{u2n}->{$self->data->{e2u}->[$n]});
278 0 0 0       $self->data->{u2n}->{$self->data->{uni}->[$n]}=($self->data->{char}->[$n] || '.notdef') unless(defined $self->data->{u2n}->{$self->data->{uni}->[$n]});
279             }
280            
281 0           return($self);
282             }
283            
284            
285             =item $font = PDF::API3::Compat::API2::Resource::Font::SynFont->new_api $api, $fontobj, %options
286            
287             Returns a synfont object. This method is different from 'new' that
288             it needs an PDF::API3::Compat::API2-object rather than a PDF::API3::Compat::API2::PDF::File-object.
289            
290             =cut
291            
292             sub new_api
293             {
294 0     0 1   my ($class,$api,@opts)=@_;
295            
296 0           my $obj=$class->new($api->{pdf},@opts);
297            
298 0 0         $api->{pdf}->new_obj($obj) unless($obj->is_obj($api->{pdf}));
299            
300 0           $api->{pdf}->out_obj($api->{pages});
301 0           return($obj);
302             }
303            
304             1;
305            
306             __END__