@@ -12,6 +12,8 @@ import (
12
12
"io"
13
13
"math"
14
14
"os"
15
+
16
+ "github.com/sirupsen/logrus"
15
17
)
16
18
17
19
// Font wraps font for outside access.
@@ -75,15 +77,8 @@ func ValidateFile(filePath string) error {
75
77
return fnt .validate (br )
76
78
}
77
79
78
- // Decode decodes charcodes in raw byte data to runes (string/UTF-8).
79
- // TODO(gunnsth): Implement. Document the use case.
80
- func (f * Font ) Decode (charcodes []byte ) (string , error ) {
81
- return "" , errors .New ("not implemented" )
82
- }
83
-
84
- // GetCmap returns the font's character encoding map (cmap). Used in PDF for decoding.
85
- // If not found nil is returned.
86
- // TODO(gunnsth): Document use.
80
+ // GetCmap returns the specific cmap specified by `platformID` and platform-specific `encodingID`.
81
+ // If not available, nil is returned. Used in PDF for decoding.
87
82
func (f * Font ) GetCmap (platformID , encodingID int ) map [rune ]GlyphIndex {
88
83
if f .cmap == nil {
89
84
return nil
@@ -98,10 +93,143 @@ func (f *Font) GetCmap(platformID, encodingID int) map[rune]GlyphIndex {
98
93
return nil
99
94
}
100
95
101
- // GetCMapByPlatform returns the specific cmap specified by `platformID` and platform-specific `encodingID`.
102
- // If not available, nil is returned.
103
- func (f * font ) GetCmapByPlatform (platformID int , encodingID int ) * cmapTable {
104
- return nil
96
+ // SubsetKeepRunes prunes data for all GIDs except the ones corresponding to `runes`. The GIDs are
97
+ // maintained. Typically reduces glyf table size significantly.
98
+ func (f * Font ) SubsetKeepRunes (runes []rune ) (* Font , error ) {
99
+ var maps []map [rune ]GlyphIndex
100
+ // Search order (3,1), (1,0), (0,3).
101
+ maps = append (maps , f .GetCmap (3 , 1 ), f .GetCmap (1 , 0 ), f .GetCmap (0 , 3 ))
102
+
103
+ var indices []GlyphIndex
104
+ for _ , r := range runes {
105
+ index := GlyphIndex (0 )
106
+ for _ , cmap := range maps {
107
+ ind , has := cmap [r ]
108
+ if has {
109
+ index = ind
110
+ break
111
+ }
112
+ }
113
+ if index == 0 {
114
+ return nil , fmt .Errorf ("rune not found: %v" , r )
115
+ }
116
+ indices = append (indices , index )
117
+ }
118
+ logrus .Debugf ("Runes: %+v %s" , runes , string (runes ))
119
+ logrus .Debugf ("GIDs: %+v" , indices )
120
+ return f .SubsetKeepIndices (indices )
121
+ }
122
+
123
+ // SubsetKeepIndices prunes data for all GIDs outside of `indices`. The GIDs are maintained.
124
+ // This typically works well and is a simple way to prune most of the unnecessary data as the
125
+ // glyf table is usually the biggest by far.
126
+ func (f * Font ) SubsetKeepIndices (indices []GlyphIndex ) (* Font , error ) {
127
+ newfnt := font {}
128
+
129
+ gidIncludedMap := make (map [GlyphIndex ]struct {}, len (indices ))
130
+ for _ , gid := range indices {
131
+ gidIncludedMap [gid ] = struct {}{}
132
+ }
133
+
134
+ newfnt .ot = & offsetTable {}
135
+ * newfnt .ot = * f .font .ot
136
+
137
+ newfnt .trec = & tableRecords {}
138
+ * newfnt .trec = * f .font .trec
139
+
140
+ if f .font .head != nil {
141
+ newfnt .head = & headTable {}
142
+ * newfnt .head = * f .font .head
143
+ }
144
+
145
+ if f .font .maxp != nil {
146
+ newfnt .maxp = & maxpTable {}
147
+ * newfnt .maxp = * f .font .maxp
148
+ }
149
+
150
+ if f .font .hhea != nil {
151
+ newfnt .hhea = & hheaTable {}
152
+ * newfnt .hhea = * f .font .hhea
153
+ }
154
+
155
+ if f .font .hmtx != nil {
156
+ newfnt .hmtx = & hmtxTable {}
157
+ * newfnt .hmtx = * f .font .hmtx
158
+ newfnt .optimizeHmtx ()
159
+ }
160
+
161
+ if f .font .glyf != nil && f .font .loca != nil {
162
+ newfnt .loca = & locaTable {}
163
+ newfnt .glyf = & glyfTable {}
164
+ * newfnt .glyf = * f .font .glyf
165
+
166
+ // Empty glyf contents for non-included glyphs.
167
+ for i := range newfnt .glyf .descs {
168
+ if _ , has := gidIncludedMap [GlyphIndex (i )]; has {
169
+ continue
170
+ }
171
+
172
+ if newfnt .glyf .descs [i ].IsSimple () {
173
+ newfnt .glyf .descs [i ].raw = nil
174
+ } else {
175
+ // TODO: For composite glyphs, need to know which ones are used together.
176
+ // If one gid relies on another on that is not included, need to include it.
177
+ // - Start by crawling through all the glyph descriptions and for any composite
178
+ // glyph in use, mark others that are required.
179
+ }
180
+ }
181
+
182
+ // Update loca offsets.
183
+ isShort := f .font .head .indexToLocFormat == 0
184
+ if isShort {
185
+ newfnt .loca .offsetsShort = make ([]offset16 , len (newfnt .glyf .descs )+ 1 )
186
+ newfnt .loca .offsetsShort [0 ] = f .font .loca .offsetsShort [0 ]
187
+ } else {
188
+ newfnt .loca .offsetsLong = make ([]offset32 , len (newfnt .glyf .descs )+ 1 )
189
+ newfnt .loca .offsetsLong [0 ] = f .font .loca .offsetsLong [0 ]
190
+ }
191
+ for i , desc := range newfnt .glyf .descs {
192
+ if isShort {
193
+ newfnt .loca .offsetsShort [i + 1 ] = newfnt .loca .offsetsShort [i ] + offset16 (len (desc .raw ))/ 2
194
+ } else {
195
+ newfnt .loca .offsetsLong [i + 1 ] = newfnt .loca .offsetsLong [i ] + offset32 (len (desc .raw ))
196
+ }
197
+ }
198
+ }
199
+
200
+ if f .font .prep != nil {
201
+ newfnt .prep = & prepTable {}
202
+ * newfnt .prep = * f .font .prep
203
+ }
204
+
205
+ if f .font .cvt != nil {
206
+ newfnt .cvt = & cvtTable {}
207
+ * newfnt .cvt = * f .font .cvt
208
+ }
209
+
210
+ if f .font .name != nil {
211
+ newfnt .name = & nameTable {}
212
+ * newfnt .name = * f .font .name
213
+ }
214
+
215
+ if f .font .os2 != nil {
216
+ newfnt .os2 = & os2Table {}
217
+ * newfnt .os2 = * f .font .os2
218
+ }
219
+ if f .font .post != nil {
220
+ newfnt .post = & postTable {}
221
+ * newfnt .post = * f .font .post
222
+ }
223
+ if f .font .cmap != nil {
224
+ newfnt .cmap = & cmapTable {}
225
+ * newfnt .cmap = * f .font .cmap
226
+ }
227
+
228
+ subfnt := & Font {
229
+ br : nil ,
230
+ font : & newfnt ,
231
+ }
232
+ return subfnt , nil
105
233
}
106
234
107
235
// SubsetSimple creates a simple subset of `f` with only first `numGlyphs`.
@@ -154,9 +282,6 @@ func (f *Font) SubsetSimple(numGlyphs int) (*Font, error) {
154
282
newfnt .hmtx .leftSideBearings = newfnt .hmtx .leftSideBearings [0 :numKeep ]
155
283
}
156
284
newfnt .optimizeHmtx ()
157
- fmt .Printf ("2 hmtx numHmetrics: %d\n " , newfnt .hhea .numberOfHMetrics )
158
- fmt .Printf ("2 hmtx.hMetrics : %d\n " , len (newfnt .hmtx .hMetrics ))
159
- fmt .Printf ("2 hmtx.leftSideBearinggs: %d\n " , len (newfnt .hmtx .leftSideBearings ))
160
285
}
161
286
162
287
if f .font .glyf != nil && f .font .loca != nil {
@@ -178,7 +303,6 @@ func (f *Font) SubsetSimple(numGlyphs int) (*Font, error) {
178
303
// TODO: Allow glyphs that are within the subset range: Can place the additional glyphs needed at the end.
179
304
// Only support simple glyphs here, since otherwise they could refer to outside the exported range.
180
305
// Remove non-simple glyphs.
181
- fmt .Printf ("%d - not simple\n " , i )
182
306
desc .raw = nil
183
307
}
184
308
if isShort {
@@ -314,23 +438,15 @@ func (f *Font) SubsetSimple(numGlyphs int) (*Font, error) {
314
438
return subfnt , nil
315
439
}
316
440
317
- // Subset creates a subset of `f` including only glyphs with `runes`.
318
- // If `cmap` is nil, the cmap will be loaded from the font.
319
- // Returns the subsetted font, a map of rune to GlyphIndex in the new font.
320
- //func (f *Font) Subset(runes []rune, cmap map[rune]GlyphIndex) (*Font, map[rune]GlyphIndex, error) {
321
441
// Subset creates a subset of `f` including only glyph indices specified by `indices`.
322
- func (f * Font ) Subset (indices []GlyphIndex ) (* Font , map [rune ]GlyphIndex , error ) {
323
-
324
- newfnt := font {}
325
-
326
- //newfnt.ot = f.fnt.ot.copy() // make a copy of ot.
327
- _ = newfnt
328
-
442
+ // Returns the new subsetted font, a map of old to new GlyphIndex to GlyphIndex as the removal
443
+ // of glyphs requires reordering.
444
+ func (f * Font ) Subset (indices []GlyphIndex ) (newf * Font , oldnew map [GlyphIndex ]GlyphIndex , err error ) {
329
445
// TODO:
330
446
// 1. Make the new cmap for `runes` if `cmap` is nil, using the cmap table and make a []GlyphIndex
331
447
// with the glyph indices to keep (index prior to subsetting).
332
448
// 2. Go through each table and leave only data for the glyph indices to be kept.
333
- return nil , nil , nil
449
+ return nil , nil , errors . New ( "not implemented yet" )
334
450
}
335
451
336
452
// Write writes the font to `w`.
0 commit comments