Skip to content

Commit 7878e37

Browse files
committed
Multiple fixes and cleanups
1 parent 09d6ecd commit 7878e37

22 files changed

+849
-743
lines changed

Diff for: byte_reader.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ package unitype
88
import (
99
"bufio"
1010
"encoding/binary"
11-
"fmt"
1211
"io"
12+
13+
"github.com/sirupsen/logrus"
1314
)
1415

1516
// byteReader encapsulates io.ReadSeeker with buffering and provides methods to read binary data as
@@ -106,7 +107,7 @@ func (r *byteReader) readSlice(slice interface{}, length int) error {
106107
}
107108

108109
default:
109-
fmt.Printf("Unsupported type: %T (readSlice)\n", t)
110+
logrus.Errorf("Unsupported type: %T (readSlice)", t)
110111
return errTypeCheck
111112
}
112113
return nil
@@ -202,7 +203,7 @@ func (r byteReader) read(fields ...interface{}) error {
202203
*t = val
203204

204205
default:
205-
fmt.Printf("Unsupported type: %T (read)\n", t)
206+
logrus.Errorf("Unsupported type: %T (read)", t)
206207
return errTypeCheck
207208
}
208209
}

Diff for: byte_writer.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package unitype
88
import (
99
"bytes"
1010
"encoding/binary"
11-
"fmt"
1211
"io"
1312

1413
"github.com/sirupsen/logrus"
@@ -137,7 +136,7 @@ func (w *byteWriter) writeSlice(slice interface{}) error {
137136
}
138137

139138
default:
140-
fmt.Printf("Write type check error: %T (slice)\n", t)
139+
logrus.Errorf("Write type check error: %T (slice)", t)
141140
return errTypeCheck
142141
}
143142
return nil
@@ -204,7 +203,7 @@ func (w *byteWriter) write(fields ...interface{}) error {
204203
}
205204

206205
default:
207-
fmt.Printf("Write type check error: %T\n", t)
206+
logrus.Errorf("Write type check error: %T", t)
208207
return errTypeCheck
209208
}
210209
}

Diff for: export.go

+145-29
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"io"
1313
"math"
1414
"os"
15+
16+
"github.com/sirupsen/logrus"
1517
)
1618

1719
// Font wraps font for outside access.
@@ -75,15 +77,8 @@ func ValidateFile(filePath string) error {
7577
return fnt.validate(br)
7678
}
7779

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.
8782
func (f *Font) GetCmap(platformID, encodingID int) map[rune]GlyphIndex {
8883
if f.cmap == nil {
8984
return nil
@@ -98,10 +93,143 @@ func (f *Font) GetCmap(platformID, encodingID int) map[rune]GlyphIndex {
9893
return nil
9994
}
10095

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
105233
}
106234

107235
// SubsetSimple creates a simple subset of `f` with only first `numGlyphs`.
@@ -154,9 +282,6 @@ func (f *Font) SubsetSimple(numGlyphs int) (*Font, error) {
154282
newfnt.hmtx.leftSideBearings = newfnt.hmtx.leftSideBearings[0:numKeep]
155283
}
156284
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))
160285
}
161286

162287
if f.font.glyf != nil && f.font.loca != nil {
@@ -178,7 +303,6 @@ func (f *Font) SubsetSimple(numGlyphs int) (*Font, error) {
178303
// TODO: Allow glyphs that are within the subset range: Can place the additional glyphs needed at the end.
179304
// Only support simple glyphs here, since otherwise they could refer to outside the exported range.
180305
// Remove non-simple glyphs.
181-
fmt.Printf("%d - not simple\n", i)
182306
desc.raw = nil
183307
}
184308
if isShort {
@@ -314,23 +438,15 @@ func (f *Font) SubsetSimple(numGlyphs int) (*Font, error) {
314438
return subfnt, nil
315439
}
316440

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) {
321441
// 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) {
329445
// TODO:
330446
// 1. Make the new cmap for `runes` if `cmap` is nil, using the cmap table and make a []GlyphIndex
331447
// with the glyph indices to keep (index prior to subsetting).
332448
// 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")
334450
}
335451

336452
// Write writes the font to `w`.

0 commit comments

Comments
 (0)