outstanding change
[librarian.git] / librarian / font-optimizer / ext / Font-TTF / lib / Font / TTF / EBDT.pm
1 package Font::TTF::EBDT;
2
3 =head1 NAME
4
5 Font::TTF::EBDT - Embeeded Bitmap Data Table
6
7 =head1 DESCRIPTION
8
9 Contains the metrics and bitmap image data.
10
11 =head1 INSTANCE VARIABLES
12
13 Only has 'bitmap' instance variable.  It is an array of assosiative
14 array keyed by glyph-id.  The element is an object which consists
15 of metric information and image data.
16
17 =over 4
18
19 =item bitmap object
20
21 =over 8
22 =item format
23 Only 7 is supported.
24 =item height
25 =item width
26 =item horiBearingX
27 =item horiBearingY
28 =item horiAdvance
29 =item vertBearingX
30 =item vertBearingY
31 =item vertAdvance
32 =item imageData
33
34 =back
35
36 =back
37
38 =head1 METHODS
39
40 =cut
41
42 use strict;
43 use vars qw(@ISA);
44 require Font::TTF::Table;
45
46 @ISA = qw(Font::TTF::Table);
47
48
49 =head2 $t->read
50
51 Reads the embedded bitmap data from the TTF file into memory.
52 This routine should be called _after_ {'EBLC'}->read.
53
54 =cut
55
56 sub read
57 {
58     my ($self) = shift;
59     my ($fh) = $self->{' INFILE'};
60     my ($i, $dat);
61     my ($eblc) = $self->{' PARENT'}->{'EBLC'};
62     my ($bst_array);
63
64     $eblc->read;
65     $self->SUPER::read || return $self;
66
67     # ebdtHeader
68     $fh->read($dat, 4); # version
69
70     $bst_array = $eblc->{'bitmapSizeTable'};
71
72     for ($i = 0; $i < $eblc->{'Num'}; $i++)
73     {
74         my ($bst) = $bst_array->[$i];
75         my ($format) = $bst->{'imageFormat'};
76         my ($offset) = $bst->{'imageDataOffset'};
77         my ($j);
78         my ($ist_array) = $eblc->{'indexSubTableArray'}[$i];
79         my ($bitmap) = {};
80
81         die "Only EBDT format 7 is implemented." unless  ($format == 7);
82
83         $self->{'bitmap'}[$i] = $bitmap;
84
85         for ($j = 0; $j < $bst->{'numberOfIndexSubTables'}; $j++) {
86             my ($ista) = $ist_array->[$j];
87             my ($offsetArray) = $eblc->{'indexSubTable'}[$i][$j];
88             my ($p, $o0, $c);
89
90 #           if ($fh->tell != $self->{' OFFSET'} + $offset) {
91 #               $fh->seek($self->{' OFFSET'} + $offset, 0);
92 #           }
93
94             $p = 0;
95             $o0 = $offsetArray->[$p++];
96             for ($c = $ista->{'firstGlyphIndex'}; $c <= $ista->{'lastGlyphIndex'}; $c++)
97             {
98                 my ($b) = {};
99                 my ($o1) = $offsetArray->[$p++];
100                 my ($len) = $o1 - $o0 - 8;
101
102 #               if ($fh->tell != $self->{' OFFSET'} + $offset + $o0) {
103 #                   $fh->seek($self->{' OFFSET'} + $offset + $o0, 0);
104 #               }
105
106                 $fh->read($dat, 8);
107                 ($b->{'height'},
108                  $b->{'width'},
109                  $b->{'horiBearingX'},
110                  $b->{'horiBearingY'},
111                  $b->{'horiAdvance'},
112                  $b->{'vertBearingX'},
113                  $b->{'vertBearingY'},
114                  $b->{'vertAdvance'})
115                     = unpack("cccccccc", $dat);
116
117                 $fh->read($dat, $len);
118                 $b->{'imageData'} = $dat;
119                 $b->{'format'} = 7; # bitmap and bigMetrics
120
121                 $bitmap->{$c} = $b;
122                 $o0 = $o1;
123             }
124
125             $offset += $o0;
126         }
127     }
128
129     $self;
130 }
131
132
133 =head2 $t->update
134
135 Update EBLC information using EBDT data.
136
137 =cut
138
139 sub get_regions
140 {
141     my (@l) = @_;
142     my (@r) = ();
143     my ($e);
144     my ($first);
145     my ($last);
146
147     $first = $l[0];
148     $last = $first - 1;
149     foreach $e (@l) {
150         if ($last + 1 != $e) {  # not contiguous
151             $r[++$#r] = [$first, $last];
152             $first = $e;
153         }
154
155         $last = $e;
156     }
157
158     $r[++$#r] = [$first, $last];
159     @r;
160 }
161
162 sub update
163 {
164     my ($self) = @_;
165     my ($eblc) = $self->{' PARENT'}->{'EBLC'};
166     my ($bst_array) = [];
167     my ($offset) = 4;
168     my ($i);
169     my ($bitmap_array) = $self->{'bitmap'};
170     my ($istao) = 8 + 48 * $eblc->{'Num'};
171
172     $eblc->{'bitmapSizeTable'} = $bst_array;
173
174     for ($i = 0; $i < $eblc->{'Num'}; $i++) {
175         my ($bst) = {};
176         my ($ist_array) = [];
177         my ($j);
178         my ($bitmap) = $bitmap_array->[$i];
179         my (@regions) = get_regions(sort {$a <=> $b} keys (%$bitmap));
180         my ($aotis) = 8 * (1+$#regions);
181
182         $bst->{'indexFormat'} = 1;
183         $bst->{'imageFormat'} = 7;
184         $bst->{'imageDataOffset'} = $offset;
185         $bst->{'numberOfIndexSubTables'} = 1+$#regions;
186         $bst->{'indexSubTableArrayOffset'} = $istao;
187         $bst->{'colorRef'} = 0;
188
189         $bst->{'startGlyphIndex'} = $regions[0][0];
190         $bst->{'endGlyphIndex'} = $regions[-1][1];
191         $bst->{'bitDepth'} = 1;
192         $bst->{'flags'} = 1;    # Horizontal
193         $bst_array->[$i] = $bst;
194
195         $eblc->{'indexSubTableArray'}[$i] = $ist_array;
196         for ($j = 0; $j <= $#regions; $j++) {
197             my ($ista) = {};
198             my ($offsetArray) = [];
199             my ($p, $o0, $c);
200             $ist_array->[$j] = $ista;
201
202             $ista->{'firstGlyphIndex'} = $regions[$j][0];
203             $ista->{'lastGlyphIndex'} = $regions[$j][1];
204             $ista->{'additionalOffsetToIndexSubtable'} = $aotis;
205             $eblc->{'indexSubTable'}[$i][$j] = $offsetArray;
206             $p = 0;
207             $o0 = 0;
208             for ($c = $regions[$j][0]; $c <= $regions[$j][1]; $c++) {
209                 my ($b) = $bitmap->{$c};
210
211                 $offsetArray->[$p++] = $o0;
212                 $o0 += 8 + length($b->{'imageData'});
213             }
214
215             $offsetArray->[$p++] = $o0;
216
217             $aotis += ($regions[$j][1] - $regions[$j][0] + 1 + 1)*4;
218             $offset += $o0;
219
220             # Do we need the element of 0x10007 and absolute offset here,
221             # at the end of offsetArray?
222 #               if ($j + 1 <= $#regions) {
223 #               $offsetArray->[$p++] = 0x10007;
224 #               $offsetArray->[$p++] = $offset;
225 #               $aotis += 8;
226 #           }
227         }
228
229         $istao += $aotis + 8;
230         $bst->{'indexTablesSize'} = $aotis + 8;
231     }
232 }
233
234 =head2 $t->out($fh)
235
236 Outputs the bitmap data of embedded bitmap for this font.
237
238 =cut
239
240 sub out
241 {
242     my ($self, $fh) = @_;
243     my ($eblc) = $self->{' PARENT'}->{'EBLC'};
244     my ($i);
245     my ($bitmap_array) = $self->{'bitmap'};
246
247     $fh->print(pack("N", 0x00020000));
248
249     for ($i = 0; $i < $eblc->{'Num'}; $i++) {
250         my ($j);
251         my ($bitmap) = $bitmap_array->[$i];
252         my (@regions) = get_regions(sort {$a <=> $b} keys (%$bitmap));
253
254         for ($j = 0; $j <= $#regions; $j++) {
255             my ($c);
256
257             for ($c = $regions[$j][0]; $c <= $regions[$j][1]; $c++) {
258                 my ($b) = $bitmap->{$c};
259
260                 $fh->print(pack("cccccccc",
261                                 $b->{'height'}, $b->{'width'},
262                                 $b->{'horiBearingX'}, $b->{'horiBearingY'},
263                                 $b->{'horiAdvance'}, $b->{'vertBearingX'},
264                                 $b->{'vertBearingY'}, $b->{'vertAdvance'}));
265                 $fh->print($b->{'imageData'});
266             }
267         }
268     }
269 }
270
271 1;
272
273 =head1 BUGS
274
275 Only Format 7 is implemented.  XML output is not supported (yet).
276
277 =head1 AUTHOR
278
279 NIIBE Yutaka L<gniibe@fsij.org>.  See L<Font::TTF::Font> for copyright and
280 licensing.
281
282 This was written at the CodeFest Akihabara 2006 hosted by FSIJ.
283
284 =cut
285