package PDF::API2::Resource::CIDFont; use base 'PDF::API2::Resource::BaseFont'; use strict; use warnings; our $VERSION = '2.043'; # VERSION use Encode qw(:all); use PDF::API2::Basic::PDF::Utils; use PDF::API2::Util; =head1 NAME PDF::API2::Resource::CIDFont - Base class for CID fonts =head1 METHODS =over =item $font = PDF::API2::Resource::CIDFont->new $pdf, $name Returns a cid-font object. base class form all CID based fonts. =cut sub new { my ($class, $pdf, $name, %opts) = @_; $class = ref($class) if ref($class); my $self = $class->SUPER::new($pdf, $name); $pdf->new_obj($self) if defined $pdf and not $self->is_obj($pdf); $self->{'Type'} = PDFName('Font'); $self->{'Subtype'} = PDFName('Type0'); $self->{'Encoding'} = PDFName('Identity-H'); my $de = PDFDict(); $pdf->new_obj($de); $self->{'DescendantFonts'} = PDFArray($de); $de->{'Type'} = PDFName('Font'); $de->{'CIDSystemInfo'} = PDFDict(); $de->{'CIDSystemInfo'}->{'Registry'} = PDFStr('Adobe'); $de->{'CIDSystemInfo'}->{'Ordering'} = PDFStr('Identity'); $de->{'CIDSystemInfo'}->{'Supplement'} = PDFNum(0); $de->{'CIDToGIDMap'} = PDFName('Identity'); $self->{' de'} = $de; return $self; } sub glyphByCId { return $_[0]->data->{'g2n'}->[$_[1]] } sub uniByCId { return $_[0]->data->{'g2u'}->[$_[1]] } sub cidByUni { return $_[0]->data->{'u2g'}->{$_[1]} } sub cidByEnc { return $_[0]->data->{'e2g'}->[$_[1]] } sub wxByCId { my ($self, $g) = @_; my $widths = $self->data->{'wx'}; if (ref($widths) eq 'ARRAY') { return int($widths->[$g]) if defined $widths->[$g]; } elsif (ref($widths) eq 'HASH') { return int($widths->{$g}) if defined $widths->{$g}; } return $self->missingwidth(); } sub wxByUni { return $_[0]->wxByCId($_[0]->data->{'u2g'}->{$_[1]}) } sub wxByEnc { return $_[0]->wxByCId($_[0]->data->{'e2g'}->[$_[1]]) } sub width { my ($self, $text) = @_; return $self->width_cid($self->cidsByStr($text)); } sub width_cid { my ($self, $text) = @_; my $width = 0; my $lastglyph = 0; foreach my $n (unpack('n*', $text)) { $width += $self->wxByCId($n); if ($self->{'-dokern'} and $self->haveKernPairs()) { if ($self->kernPairCid($lastglyph, $n)) { $width -= $self->kernPairCid($lastglyph, $n); } } $lastglyph = $n; } $width /= 1000; return $width; } =item $cidstring = $font->cidsByStr $string Returns the cid-string from string based on the fonts encoding map. =cut sub _cidsByStr { my ($self, $s) = @_; $s = pack('n*', map { $self->cidByEnc($_) } unpack('C*', $s)); return $s; } sub cidsByStr { my ($self, $text) = @_; if (utf8::is_utf8($text) and defined $self->data->{'decode'} and $self->data->{'decode'} ne 'ident') { $text = encode($self->data->{'decode'}, $text); } elsif (utf8::is_utf8($text) and defined $self->data->{'decode'} and $self->data->{'decode'} eq 'ident') { $text = $self->cidsByUtf($text); } elsif (not utf8::is_utf8($text) and defined $self->data->{'encode'} and defined $self->data->{'decode'} and $self->data->{'decode'} eq 'ident') { $text = $self->cidsByUtf(decode($self->data->{'encode'}, $text)); } elsif (not utf8::is_utf8($text) and $self->can('issymbol') and $self->issymbol() and defined $self->data->{'decode'} and $self->data->{'decode'} eq 'ident') { $text = pack('U*', map { $_ + 0xf000 } unpack('C*', $text)); $text = $self->cidsByUtf($text); } else { $text = $self->_cidsByStr($text); } return $text; } =item $cidstring = $font->cidsByUtf $utf8string Returns the cid-encoded string from utf8-string. =cut sub cidsByUtf { my ($self, $s) = @_; $s = pack('n*', map { $self->cidByUni($_) } (map { ($_ and $_ > 0x7f and $_ < 0xa0) ? uniByName(nameByUni($_)) : $_ } unpack('U*', $s))); utf8::downgrade($s); return $s; } sub textByStr { my ($self, $text) = @_; return $self->text_cid($self->cidsByStr($text)); } sub textByStrKern { my ($self, $text, $size, $indent) = @_; return $self->text_cid_kern($self->cidsByStr($text), $size, $indent); } sub text { my ($self, $text, $size, $indent) = @_; my $newtext = $self->textByStr($text); if (defined $size and $self->{'-dokern'}) { $newtext = $self->textByStrKern($text, $size, $indent); return $newtext; } elsif (defined $size) { if (defined($indent) and $indent != 0) { return "[ $indent $newtext ] TJ"; } else { return "$newtext Tj"; } } else { return $newtext; } } sub text_cid { my ($self, $text, $size) = @_; if ($self->can('fontfile')) { foreach my $g (unpack('n*', $text)) { $self->fontfile->subsetByCId($g); } } my $newtext = unpack('H*', $text); if (defined $size) { return "<$newtext> Tj"; } else { return "<$newtext>"; } } sub text_cid_kern { my ($self, $text, $size, $indent) = @_; if ($self->can('fontfile')) { foreach my $g (unpack('n*', $text)) { $self->fontfile->subsetByCId($g); } } if (defined $size and $self->{'-dokern'} and $self->haveKernPairs()) { my $newtext = ' '; my $lastglyph = 0; my $tBefore = 0; foreach my $n (unpack('n*', $text)) { if ($self->kernPairCid($lastglyph, $n)) { $newtext .= '> ' if $tBefore; $newtext .= sprintf('%i ', $self->kernPairCid($lastglyph, $n)); $tBefore = 0; } $lastglyph = $n; my $t = sprintf('%04X', $n); $newtext .= '<' unless $tBefore; $newtext .= $t; $tBefore = 1; } $newtext .= '> ' if $tBefore; if (defined $indent and $indent != 0) { return "[ $indent $newtext ] TJ"; } else { return "[ $newtext ] TJ"; } } elsif (defined $size) { my $newtext = unpack('H*', $text); if (defined($indent) and $indent != 0) { return "[ $indent <$newtext> ] TJ"; } else { return "<$newtext> Tj"; } } else { my $newtext = unpack('H*', $text); return "<$newtext>"; } } sub kernPairCid { return 0; } sub haveKernPairs { return; } sub encodeByName { my ($self, $enc) = @_; return if $self->issymbol(); if (defined $enc) { $self->data->{'e2u'} = [ map { ($_ > 0x7f and $_ < 0xA0) ? uniByName(nameByUni($_)) : $_ } unpack('U*', decode($enc, pack('C*', 0 .. 255))) ]; } $self->data->{'e2n'} = [ map { $self->data->{'g2n'}->[$self->data->{'u2g'}->{$_} || 0] || '.notdef' } @{$self->data->{'e2u'}} ]; $self->data->{'e2g'} = [ map { $self->data->{'u2g'}->{$_} || 0 } @{$self->data->{'e2u'}} ]; $self->data->{'u2e'} = {}; foreach my $n (reverse 0 .. 255) { $self->data->{'u2e'}->{$self->data->{'e2u'}->[$n]} //= $n; } return $self; } sub subsetByCId { return 1; } sub subvec { return 1; } sub glyphNum { my $self = shift(); if (defined $self->data->{'glyphs'}) { return $self->data->{'glyphs'}; } return scalar @{$self->data->{'wx'}}; } =back =cut 1;