<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">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-&gt;read

Reads the embedded bitmap data from the TTF file into memory.
This routine should be called _after_ {'EBLC'}-&gt;read.

=cut

sub read
{
    my ($self) = shift;
    my ($fh) = $self-&gt;{' INFILE'};
    my ($i, $dat);
    my ($eblc) = $self-&gt;{' PARENT'}-&gt;{'EBLC'};
    my ($bst_array);

    $eblc-&gt;read;
    $self-&gt;SUPER::read || return $self;

    # ebdtHeader
    $fh-&gt;read($dat, 4);	# version

    $bst_array = $eblc-&gt;{'bitmapSizeTable'};

    for ($i = 0; $i &lt; $eblc-&gt;{'Num'}; $i++)
    {
        my ($bst) = $bst_array-&gt;[$i];
        my ($format) = $bst-&gt;{'imageFormat'};
        my ($offset) = $bst-&gt;{'imageDataOffset'};
        my ($j);
        my ($ist_array) = $eblc-&gt;{'indexSubTableArray'}[$i];
        my ($bitmap) = {};

        die "Only EBDT format 7 is implemented." unless  ($format == 7);

        $self-&gt;{'bitmap'}[$i] = $bitmap;

        for ($j = 0; $j &lt; $bst-&gt;{'numberOfIndexSubTables'}; $j++) {
            my ($ista) = $ist_array-&gt;[$j];
            my ($offsetArray) = $eblc-&gt;{'indexSubTable'}[$i][$j];
            my ($p, $o0, $c);

#           if ($fh-&gt;tell != $self-&gt;{' OFFSET'} + $offset) {
#               $fh-&gt;seek($self-&gt;{' OFFSET'} + $offset, 0);
#           }

            $p = 0;
            $o0 = $offsetArray-&gt;[$p++];
            for ($c = $ista-&gt;{'firstGlyphIndex'}; $c &lt;= $ista-&gt;{'lastGlyphIndex'}; $c++)
            {
                my ($b) = {};
                my ($o1) = $offsetArray-&gt;[$p++];
                my ($len) = $o1 - $o0 - 8;

#               if ($fh-&gt;tell != $self-&gt;{' OFFSET'} + $offset + $o0) {
#                   $fh-&gt;seek($self-&gt;{' OFFSET'} + $offset + $o0, 0);
#               }

                $fh-&gt;read($dat, 8);
                ($b-&gt;{'height'},
                 $b-&gt;{'width'},
                 $b-&gt;{'horiBearingX'},
                 $b-&gt;{'horiBearingY'},
                 $b-&gt;{'horiAdvance'},
                 $b-&gt;{'vertBearingX'},
                 $b-&gt;{'vertBearingY'},
                 $b-&gt;{'vertAdvance'})
                    = unpack("cccccccc", $dat);

                $fh-&gt;read($dat, $len);
                $b-&gt;{'imageData'} = $dat;
                $b-&gt;{'format'} = 7; # bitmap and bigMetrics

                $bitmap-&gt;{$c} = $b;
                $o0 = $o1;
            }

            $offset += $o0;
        }
    }

    $self;
}


=head2 $t-&gt;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-&gt;{' PARENT'}-&gt;{'EBLC'};
    my ($bst_array) = [];
    my ($offset) = 4;
    my ($i);
    my ($bitmap_array) = $self-&gt;{'bitmap'};
    my ($istao) = 8 + 48 * $eblc-&gt;{'Num'};

    $eblc-&gt;{'bitmapSizeTable'} = $bst_array;

    for ($i = 0; $i &lt; $eblc-&gt;{'Num'}; $i++) {
        my ($bst) = {};
        my ($ist_array) = [];
        my ($j);
        my ($bitmap) = $bitmap_array-&gt;[$i];
        my (@regions) = get_regions(sort {$a &lt;=&gt; $b} keys (%$bitmap));
        my ($aotis) = 8 * (1+$#regions);

        $bst-&gt;{'indexFormat'} = 1;
        $bst-&gt;{'imageFormat'} = 7;
        $bst-&gt;{'imageDataOffset'} = $offset;
        $bst-&gt;{'numberOfIndexSubTables'} = 1+$#regions;
        $bst-&gt;{'indexSubTableArrayOffset'} = $istao;
        $bst-&gt;{'colorRef'} = 0;

        $bst-&gt;{'startGlyphIndex'} = $regions[0][0];
        $bst-&gt;{'endGlyphIndex'} = $regions[-1][1];
        $bst-&gt;{'bitDepth'} = 1;
        $bst-&gt;{'flags'} = 1;	# Horizontal
        $bst_array-&gt;[$i] = $bst;

        $eblc-&gt;{'indexSubTableArray'}[$i] = $ist_array;
        for ($j = 0; $j &lt;= $#regions; $j++) {
            my ($ista) = {};
            my ($offsetArray) = [];
            my ($p, $o0, $c);
            $ist_array-&gt;[$j] = $ista;

            $ista-&gt;{'firstGlyphIndex'} = $regions[$j][0];
            $ista-&gt;{'lastGlyphIndex'} = $regions[$j][1];
            $ista-&gt;{'additionalOffsetToIndexSubtable'} = $aotis;
            $eblc-&gt;{'indexSubTable'}[$i][$j] = $offsetArray;
            $p = 0;
            $o0 = 0;
            for ($c = $regions[$j][0]; $c &lt;= $regions[$j][1]; $c++) {
                my ($b) = $bitmap-&gt;{$c};

                $offsetArray-&gt;[$p++] = $o0;
                $o0 += 8 + length($b-&gt;{'imageData'});
            }

            $offsetArray-&gt;[$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 &lt;= $#regions) {
#       	$offsetArray-&gt;[$p++] = 0x10007;
#       	$offsetArray-&gt;[$p++] = $offset;
#       	$aotis += 8;
#           }
        }

        $istao += $aotis + 8;
        $bst-&gt;{'indexTablesSize'} = $aotis + 8;
    }
}

=head2 $t-&gt;out($fh)

Outputs the bitmap data of embedded bitmap for this font.

=cut

sub out
{
    my ($self, $fh) = @_;
    my ($eblc) = $self-&gt;{' PARENT'}-&gt;{'EBLC'};
    my ($i);
    my ($bitmap_array) = $self-&gt;{'bitmap'};

    $fh-&gt;print(pack("N", 0x00020000));

    for ($i = 0; $i &lt; $eblc-&gt;{'Num'}; $i++) {
        my ($j);
        my ($bitmap) = $bitmap_array-&gt;[$i];
        my (@regions) = get_regions(sort {$a &lt;=&gt; $b} keys (%$bitmap));

        for ($j = 0; $j &lt;= $#regions; $j++) {
            my ($c);

            for ($c = $regions[$j][0]; $c &lt;= $regions[$j][1]; $c++) {
                my ($b) = $bitmap-&gt;{$c};

                $fh-&gt;print(pack("cccccccc",
                                $b-&gt;{'height'}, $b-&gt;{'width'},
                                $b-&gt;{'horiBearingX'}, $b-&gt;{'horiBearingY'},
                                $b-&gt;{'horiAdvance'}, $b-&gt;{'vertBearingX'},
                                $b-&gt;{'vertBearingY'}, $b-&gt;{'vertAdvance'}));
                $fh-&gt;print($b-&gt;{'imageData'});
            }
        }
    }
}

1;

=head1 BUGS

Only Format 7 is implemented.  XML output is not supported (yet).

=head1 AUTHOR

NIIBE Yutaka L&lt;gniibe@fsij.org&gt;.  See L&lt;Font::TTF::Font&gt; for copyright and
licensing.

This was written at the CodeFest Akihabara 2006 hosted by FSIJ.

=cut

</pre></body></html>