package Font::TTF::EBDT; =head1 NAME Font::TTF::EBDT - Embeeded Bitmap Data Table =head1 DESCRIPTION Contains the metrics and bitmap image data. =head1 INSTANCE VARIABLES Only has 'bitmap' instance variable. It is an array of assosiative array keyed by glyph-id. The element is an object which consists of metric information and image data. =over 4 =item bitmap object =over 8 =item format Only 7 is supported. =item height =item width =item horiBearingX =item horiBearingY =item horiAdvance =item vertBearingX =item vertBearingY =item vertAdvance =item imageData =back =back =head1 METHODS =cut use strict; use vars qw(@ISA); require Font::TTF::Table; @ISA = qw(Font::TTF::Table); =head2 $t->read Reads the embedded bitmap data from the TTF file into memory. This routine should be called _after_ {'EBLC'}->read. =cut sub read { my ($self) = shift; my ($fh) = $self->{' INFILE'}; my ($i, $dat); my ($eblc) = $self->{' PARENT'}->{'EBLC'}; my ($bst_array); $eblc->read; $self->SUPER::read || return $self; # ebdtHeader $fh->read($dat, 4); # version $bst_array = $eblc->{'bitmapSizeTable'}; for ($i = 0; $i < $eblc->{'Num'}; $i++) { my ($bst) = $bst_array->[$i]; my ($format) = $bst->{'imageFormat'}; my ($offset) = $bst->{'imageDataOffset'}; my ($j); my ($ist_array) = $eblc->{'indexSubTableArray'}[$i]; my ($bitmap) = {}; die "Only EBDT format 7 is implemented." unless ($format == 7); $self->{'bitmap'}[$i] = $bitmap; for ($j = 0; $j < $bst->{'numberOfIndexSubTables'}; $j++) { my ($ista) = $ist_array->[$j]; my ($offsetArray) = $eblc->{'indexSubTable'}[$i][$j]; my ($p, $o0, $c); # if ($fh->tell != $self->{' OFFSET'} + $offset) { # $fh->seek($self->{' OFFSET'} + $offset, 0); # } $p = 0; $o0 = $offsetArray->[$p++]; for ($c = $ista->{'firstGlyphIndex'}; $c <= $ista->{'lastGlyphIndex'}; $c++) { my ($b) = {}; my ($o1) = $offsetArray->[$p++]; my ($len) = $o1 - $o0 - 8; # if ($fh->tell != $self->{' OFFSET'} + $offset + $o0) { # $fh->seek($self->{' OFFSET'} + $offset + $o0, 0); # } $fh->read($dat, 8); ($b->{'height'}, $b->{'width'}, $b->{'horiBearingX'}, $b->{'horiBearingY'}, $b->{'horiAdvance'}, $b->{'vertBearingX'}, $b->{'vertBearingY'}, $b->{'vertAdvance'}) = unpack("cccccccc", $dat); $fh->read($dat, $len); $b->{'imageData'} = $dat; $b->{'format'} = 7; # bitmap and bigMetrics $bitmap->{$c} = $b; $o0 = $o1; } $offset += $o0; } } $self; } =head2 $t->update Update EBLC information using EBDT data. =cut sub get_regions { my (@l) = @_; my (@r) = (); my ($e); my ($first); my ($last); $first = $l[0]; $last = $first - 1; foreach $e (@l) { if ($last + 1 != $e) { # not contiguous $r[++$#r] = [$first, $last]; $first = $e; } $last = $e; } $r[++$#r] = [$first, $last]; @r; } sub update { my ($self) = @_; my ($eblc) = $self->{' PARENT'}->{'EBLC'}; my ($bst_array) = []; my ($offset) = 4; my ($i); my ($bitmap_array) = $self->{'bitmap'}; my ($istao) = 8 + 48 * $eblc->{'Num'}; $eblc->{'bitmapSizeTable'} = $bst_array; for ($i = 0; $i < $eblc->{'Num'}; $i++) { my ($bst) = {}; my ($ist_array) = []; my ($j); my ($bitmap) = $bitmap_array->[$i]; my (@regions) = get_regions(sort {$a <=> $b} keys (%$bitmap)); my ($aotis) = 8 * (1+$#regions); $bst->{'indexFormat'} = 1; $bst->{'imageFormat'} = 7; $bst->{'imageDataOffset'} = $offset; $bst->{'numberOfIndexSubTables'} = 1+$#regions; $bst->{'indexSubTableArrayOffset'} = $istao; $bst->{'colorRef'} = 0; $bst->{'startGlyphIndex'} = $regions[0][0]; $bst->{'endGlyphIndex'} = $regions[-1][1]; $bst->{'bitDepth'} = 1; $bst->{'flags'} = 1; # Horizontal $bst_array->[$i] = $bst; $eblc->{'indexSubTableArray'}[$i] = $ist_array; for ($j = 0; $j <= $#regions; $j++) { my ($ista) = {}; my ($offsetArray) = []; my ($p, $o0, $c); $ist_array->[$j] = $ista; $ista->{'firstGlyphIndex'} = $regions[$j][0]; $ista->{'lastGlyphIndex'} = $regions[$j][1]; $ista->{'additionalOffsetToIndexSubtable'} = $aotis; $eblc->{'indexSubTable'}[$i][$j] = $offsetArray; $p = 0; $o0 = 0; for ($c = $regions[$j][0]; $c <= $regions[$j][1]; $c++) { my ($b) = $bitmap->{$c}; $offsetArray->[$p++] = $o0; $o0 += 8 + length($b->{'imageData'}); } $offsetArray->[$p++] = $o0; $aotis += ($regions[$j][1] - $regions[$j][0] + 1 + 1)*4; $offset += $o0; # Do we need the element of 0x10007 and absolute offset here, # at the end of offsetArray? # if ($j + 1 <= $#regions) { # $offsetArray->[$p++] = 0x10007; # $offsetArray->[$p++] = $offset; # $aotis += 8; # } } $istao += $aotis + 8; $bst->{'indexTablesSize'} = $aotis + 8; } } =head2 $t->out($fh) Outputs the bitmap data of embedded bitmap for this font. =cut sub out { my ($self, $fh) = @_; my ($eblc) = $self->{' PARENT'}->{'EBLC'}; my ($i); my ($bitmap_array) = $self->{'bitmap'}; $fh->print(pack("N", 0x00020000)); for ($i = 0; $i < $eblc->{'Num'}; $i++) { my ($j); my ($bitmap) = $bitmap_array->[$i]; my (@regions) = get_regions(sort {$a <=> $b} keys (%$bitmap)); for ($j = 0; $j <= $#regions; $j++) { my ($c); for ($c = $regions[$j][0]; $c <= $regions[$j][1]; $c++) { my ($b) = $bitmap->{$c}; $fh->print(pack("cccccccc", $b->{'height'}, $b->{'width'}, $b->{'horiBearingX'}, $b->{'horiBearingY'}, $b->{'horiAdvance'}, $b->{'vertBearingX'}, $b->{'vertBearingY'}, $b->{'vertAdvance'})); $fh->print($b->{'imageData'}); } } } } 1; =head1 BUGS Only Format 7 is implemented. XML output is not supported (yet). =head1 AUTHOR NIIBE Yutaka L. See L for copyright and licensing. This was written at the CodeFest Akihabara 2006 hosted by FSIJ. =cut