Introduce src dir.
[librarian.git] / src / librarian / font-optimizer / ext / Font-TTF / lib / Font / TTF / EBDT.pm
diff --git a/src/librarian/font-optimizer/ext/Font-TTF/lib/Font/TTF/EBDT.pm b/src/librarian/font-optimizer/ext/Font-TTF/lib/Font/TTF/EBDT.pm
new file mode 100644 (file)
index 0000000..257e8d7
--- /dev/null
@@ -0,0 +1,285 @@
+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<gniibe@fsij.org>.  See L<Font::TTF::Font> for copyright and
+licensing.
+
+This was written at the CodeFest Akihabara 2006 hosted by FSIJ.
+
+=cut
+