1
18
19 package font
20
21 import (
22 "bytes"
23 "encoding/binary"
24 "fmt"
25 "math"
26 "sort"
27 )
28
29
30 const symbolWords = 1 << 0
31 const symbolScale = 1 << 3
32 const symbolContinue = 1 << 5
33 const symbolAllScale = 1 << 6
34 const symbol2x2 = 1 << 7
35
36 type fontBoxType struct {
37 Xmin, Ymin, Xmax, Ymax int
38 }
39
40 type utf8FontFile struct {
41 fileReader *fileReader
42 LastRune int
43 tableDescriptions map[string]*tableDescription
44 outTablesData map[string][]byte
45 symbolPosition []int
46 charSymbolDictionary map[int]int
47 Ascent int
48 Descent int
49 Bbox fontBoxType
50 CapHeight int
51 StemV int
52 ItalicAngle int
53 Flags int
54 UnderlinePosition float64
55 UnderlineThickness float64
56 CharWidths []int
57 DefaultWidth float64
58 symbolData map[int]map[string][]int
59 CodeSymbolDictionary map[int]int
60 }
61
62 type tableDescription struct {
63 name string
64 checksum []int
65 position int
66 size int
67 }
68
69 type fileReader struct {
70 readerPosition int64
71 array []byte
72 }
73
74 func (fr *fileReader) Read(s int) []byte {
75 b := fr.array[fr.readerPosition : fr.readerPosition+int64(s)]
76 fr.readerPosition += int64(s)
77 return b
78 }
79
80 func (fr *fileReader) seek(shift int64, flag int) (int64, error) {
81 if flag == 0 {
82 fr.readerPosition = shift
83 } else if flag == 1 {
84 fr.readerPosition += shift
85 } else if flag == 2 {
86 fr.readerPosition = int64(len(fr.array)) - shift
87 }
88 return int64(fr.readerPosition), nil
89 }
90
91 func newUTF8Font(reader *fileReader) *utf8FontFile {
92 utf := utf8FontFile{
93 fileReader: reader,
94 }
95 return &utf
96 }
97
98 func (utf *utf8FontFile) generateTableDescriptions() {
99
100 tablesCount := utf.readUint16()
101 _ = utf.readUint16()
102 _ = utf.readUint16()
103 _ = utf.readUint16()
104 utf.tableDescriptions = make(map[string]*tableDescription)
105
106 for i := 0; i < tablesCount; i++ {
107 record := tableDescription{
108 name: utf.readTableName(),
109 checksum: []int{utf.readUint16(), utf.readUint16()},
110 position: utf.readUint32(),
111 size: utf.readUint32(),
112 }
113 utf.tableDescriptions[record.name] = &record
114 }
115 }
116
117 func (utf *utf8FontFile) readTableName() string {
118 return string(utf.fileReader.Read(4))
119 }
120
121 func (utf *utf8FontFile) readUint16() int {
122 s := utf.fileReader.Read(2)
123 return (int(s[0]) << 8) + int(s[1])
124 }
125
126 func (utf *utf8FontFile) readUint32() int {
127 s := utf.fileReader.Read(4)
128 return (int(s[0]) * 16777216) + (int(s[1]) << 16) + (int(s[2]) << 8) + int(s[3])
129 }
130
131 func (utf *utf8FontFile) calcInt32(x, y []int) []int {
132 answer := make([]int, 2)
133 if y[1] > x[1] {
134 x[1] += 1 << 16
135 x[0]++
136 }
137 answer[1] = x[1] - y[1]
138 if y[0] > x[0] {
139 x[0] += 1 << 16
140 }
141 answer[0] = x[0] - y[0]
142 answer[0] = answer[0] & 0xFFFF
143 return answer
144 }
145
146 func (utf *utf8FontFile) generateChecksum(data []byte) []int {
147 if (len(data) % 4) != 0 {
148 for i := 0; (len(data) % 4) != 0; i++ {
149 data = append(data, 0)
150 }
151 }
152 answer := []int{0x0000, 0x0000}
153 for i := 0; i < len(data); i += 4 {
154 answer[0] += (int(data[i]) << 8) + int(data[i+1])
155 answer[1] += (int(data[i+2]) << 8) + int(data[i+3])
156 answer[0] += answer[1] >> 16
157 answer[1] = answer[1] & 0xFFFF
158 answer[0] = answer[0] & 0xFFFF
159 }
160 return answer
161 }
162
163 func (utf *utf8FontFile) seek(shift int) {
164 _, _ = utf.fileReader.seek(int64(shift), 0)
165 }
166
167 func (utf *utf8FontFile) skip(delta int) {
168 _, _ = utf.fileReader.seek(int64(delta), 1)
169 }
170
171
172 func (utf *utf8FontFile) SeekTable(name string) int {
173 return utf.seekTable(name, 0)
174 }
175
176 func (utf *utf8FontFile) seekTable(name string, offsetInTable int) int {
177 _, _ = utf.fileReader.seek(int64(utf.tableDescriptions[name].position+offsetInTable), 0)
178 return int(utf.fileReader.readerPosition)
179 }
180
181 func (utf *utf8FontFile) readInt16() int16 {
182 s := utf.fileReader.Read(2)
183 a := (int16(s[0]) << 8) + int16(s[1])
184 if (int(a) & (1 << 15)) == 0 {
185 a = int16(int(a) - (1 << 16))
186 }
187 return a
188 }
189
190 func (utf *utf8FontFile) getUint16(pos int) int {
191 _, _ = utf.fileReader.seek(int64(pos), 0)
192 s := utf.fileReader.Read(2)
193 return (int(s[0]) << 8) + int(s[1])
194 }
195
196 func (utf *utf8FontFile) splice(stream []byte, offset int, value []byte) []byte {
197 stream = append([]byte{}, stream...)
198 return append(append(stream[:offset], value...), stream[offset+len(value):]...)
199 }
200
201 func (utf *utf8FontFile) insertUint16(stream []byte, offset int, value int) []byte {
202 up := make([]byte, 2)
203 binary.BigEndian.PutUint16(up, uint16(value))
204 return utf.splice(stream, offset, up)
205 }
206
207 func (utf *utf8FontFile) getRange(pos, length int) []byte {
208 _, _ = utf.fileReader.seek(int64(pos), 0)
209 if length < 1 {
210 return make([]byte, 0)
211 }
212 s := utf.fileReader.Read(length)
213 return s
214 }
215
216 func (utf *utf8FontFile) getTableData(name string) []byte {
217 desckrip := utf.tableDescriptions[name]
218 if desckrip == nil {
219 return nil
220 }
221 if desckrip.size == 0 {
222 return nil
223 }
224 _, _ = utf.fileReader.seek(int64(desckrip.position), 0)
225 s := utf.fileReader.Read(desckrip.size)
226 return s
227 }
228
229 func (utf *utf8FontFile) setOutTable(name string, data []byte) {
230 if data == nil {
231 return
232 }
233 if name == "head" {
234 data = utf.splice(data, 8, []byte{0, 0, 0, 0})
235 }
236 utf.outTablesData[name] = data
237 }
238
239 func (utf *utf8FontFile) generateCMAP() map[int][]int {
240 cmapPosition := utf.SeekTable("cmap")
241 utf.skip(2)
242 cmapTableCount := utf.readUint16()
243 runeCmapPosition := 0
244 for i := 0; i < cmapTableCount; i++ {
245 system := utf.readUint16()
246 coder := utf.readUint16()
247 position := utf.readUint32()
248 oldPosition := utf.fileReader.readerPosition
249 if (system == 3 && coder == 1) || system == 0 {
250 format := utf.getUint16(cmapPosition + position)
251 if format == 4 {
252 runeCmapPosition = cmapPosition + position
253 break
254 }
255 }
256 utf.seek(int(oldPosition))
257 }
258
259 if runeCmapPosition == 0 {
260 fmt.Printf("Font does not have cmap for Unicode\n")
261 return nil
262 }
263
264 symbolCharDictionary := make(map[int][]int)
265 charSymbolDictionary := make(map[int]int)
266 utf.generateSCCSDictionaries(runeCmapPosition, symbolCharDictionary, charSymbolDictionary)
267
268 utf.charSymbolDictionary = charSymbolDictionary
269
270 return symbolCharDictionary
271 }
272
273 func (utf *utf8FontFile) parseSymbols(usedRunes map[int]int) (map[int]int, map[int]int, map[int]int, []int) {
274 symbolCollection := map[int]int{0: 0}
275 charSymbolPairCollection := make(map[int]int)
276 for _, char := range usedRunes {
277 if _, OK := utf.charSymbolDictionary[char]; OK {
278 symbolCollection[utf.charSymbolDictionary[char]] = char
279 charSymbolPairCollection[char] = utf.charSymbolDictionary[char]
280
281 }
282 utf.LastRune = max(utf.LastRune, char)
283 }
284
285 begin := utf.tableDescriptions["glyf"].position
286
287 symbolArray := make(map[int]int)
288 symbolCollectionKeys := keySortInt(symbolCollection)
289
290 symbolCounter := 0
291 maxRune := 0
292 for _, oldSymbolIndex := range symbolCollectionKeys {
293 maxRune = max(maxRune, symbolCollection[oldSymbolIndex])
294 symbolArray[oldSymbolIndex] = symbolCounter
295 symbolCounter++
296 }
297 charSymbolPairCollectionKeys := keySortInt(charSymbolPairCollection)
298 runeSymbolPairCollection := make(map[int]int)
299 for _, runa := range charSymbolPairCollectionKeys {
300 runeSymbolPairCollection[runa] = symbolArray[charSymbolPairCollection[runa]]
301 }
302 utf.CodeSymbolDictionary = runeSymbolPairCollection
303
304 symbolCollectionKeys = keySortInt(symbolCollection)
305 for _, oldSymbolIndex := range symbolCollectionKeys {
306 _, symbolArray, symbolCollection, symbolCollectionKeys = utf.getSymbols(oldSymbolIndex, &begin, symbolArray, symbolCollection, symbolCollectionKeys)
307 }
308
309 return runeSymbolPairCollection, symbolArray, symbolCollection, symbolCollectionKeys
310 }
311
312 func (utf *utf8FontFile) generateCMAPTable(cidSymbolPairCollection map[int]int, numSymbols int) []byte {
313 cidSymbolPairCollectionKeys := keySortInt(cidSymbolPairCollection)
314 cidID := 0
315 cidArray := make(map[int][]int)
316 prevCid := -2
317 prevSymbol := -1
318 for _, cid := range cidSymbolPairCollectionKeys {
319 if cid == (prevCid+1) && cidSymbolPairCollection[cid] == (prevSymbol+1) {
320 if n, OK := cidArray[cidID]; !OK || n == nil {
321 cidArray[cidID] = make([]int, 0)
322 }
323 cidArray[cidID] = append(cidArray[cidID], cidSymbolPairCollection[cid])
324 } else {
325 cidID = cid
326 cidArray[cidID] = make([]int, 0)
327 cidArray[cidID] = append(cidArray[cidID], cidSymbolPairCollection[cid])
328 }
329 prevCid = cid
330 prevSymbol = cidSymbolPairCollection[cid]
331 }
332 cidArrayKeys := keySortArrayRangeMap(cidArray)
333 segCount := len(cidArray) + 1
334
335 searchRange := 1
336 entrySelector := 0
337 for searchRange*2 <= segCount {
338 searchRange = searchRange * 2
339 entrySelector = entrySelector + 1
340 }
341 searchRange = searchRange * 2
342 rangeShift := segCount*2 - searchRange
343
344 data := []int{0, 1, 3, 1, 0, 12, 4}
345
346 cmap := []int{segCount * 2, searchRange, entrySelector, rangeShift}
347 for _, start := range cidArrayKeys {
348 endCode := start + (len(cidArray[start]) - 1)
349 cmap = append(cmap, endCode)
350 }
351 cmap = append(cmap, 0xFFFF)
352 cmap = append(cmap, 0)
353
354 cmap = append(cmap, cidArrayKeys...)
355 cmap = append(cmap, 0xFFFF)
356 for _, cidKey := range cidArrayKeys {
357 idDelta := -(cidKey - cidArray[cidKey][0])
358 cmap = append(cmap, idDelta)
359 }
360 cmap = append(cmap, 1)
361 for range cidArray {
362 cmap = append(cmap, 0)
363
364 }
365 cmap = append(cmap, 0)
366 for _, start := range cidArrayKeys {
367 cmap = append(cmap, cidArray[start]...)
368 }
369 cmap = append(cmap, 0)
370
371
372
373
374 length := (3 + len(cmap)) * 2
375 data = append(data, length, 0)
376 data = append(data, cmap...)
377
378 cmapstr := make([]byte, 0)
379 for _, cm := range data {
380 cmapstr = append(cmapstr, packUint16(cm)...)
381 }
382
383 return cmapstr
384 }
385
386
387 func (utf *utf8FontFile) GenerateCutFont(usedRunes map[int]int) []byte {
388 utf.fileReader.readerPosition = 0
389 utf.symbolPosition = make([]int, 0)
390 utf.charSymbolDictionary = make(map[int]int)
391 utf.tableDescriptions = make(map[string]*tableDescription)
392 utf.outTablesData = make(map[string][]byte)
393 utf.Ascent = 0
394 utf.Descent = 0
395 utf.skip(4)
396 utf.LastRune = 0
397 utf.generateTableDescriptions()
398
399 utf.SeekTable("head")
400 utf.skip(50)
401 LocaFormat := utf.readUint16()
402
403 utf.SeekTable("hhea")
404 utf.skip(34)
405 metricsCount := utf.readUint16()
406 oldMetrics := metricsCount
407
408 utf.SeekTable("maxp")
409 utf.skip(4)
410 numSymbols := utf.readUint16()
411
412 symbolCharDictionary := utf.generateCMAP()
413 if symbolCharDictionary == nil {
414 return nil
415 }
416
417 utf.parseHMTXTable(metricsCount, numSymbols, symbolCharDictionary, 1.0)
418
419 utf.parseLOCATable(LocaFormat, numSymbols)
420
421 cidSymbolPairCollection, symbolArray, symbolCollection, symbolCollectionKeys := utf.parseSymbols(usedRunes)
422
423 metricsCount = len(symbolCollection)
424 numSymbols = metricsCount
425
426 utf.setOutTable("name", utf.getTableData("name"))
427 utf.setOutTable("cvt ", utf.getTableData("cvt "))
428 utf.setOutTable("fpgm", utf.getTableData("fpgm"))
429 utf.setOutTable("prep", utf.getTableData("prep"))
430 utf.setOutTable("gasp", utf.getTableData("gasp"))
431
432 postTable := utf.getTableData("post")
433 postTable = append(append([]byte{0x00, 0x03, 0x00, 0x00}, postTable[4:16]...), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}...)
434 utf.setOutTable("post", postTable)
435
436 delete(cidSymbolPairCollection, 0)
437
438 utf.setOutTable("cmap", utf.generateCMAPTable(cidSymbolPairCollection, numSymbols))
439
440 symbolData := utf.getTableData("glyf")
441
442 offsets := make([]int, 0)
443 glyfData := make([]byte, 0)
444 pos := 0
445 hmtxData := make([]byte, 0)
446 utf.symbolData = make(map[int]map[string][]int, 0)
447
448 for _, originalSymbolIdx := range symbolCollectionKeys {
449 hm := utf.getMetrics(oldMetrics, originalSymbolIdx)
450 hmtxData = append(hmtxData, hm...)
451
452 offsets = append(offsets, pos)
453 symbolPos := utf.symbolPosition[originalSymbolIdx]
454 symbolLen := utf.symbolPosition[originalSymbolIdx+1] - symbolPos
455 data := symbolData[symbolPos : symbolPos+symbolLen]
456 var up int
457 if symbolLen > 0 {
458 up = unpackUint16(data[0:2])
459 }
460
461 if symbolLen > 2 && (up&(1<<15)) != 0 {
462 posInSymbol := 10
463 flags := symbolContinue
464 nComponentElements := 0
465 for (flags & symbolContinue) != 0 {
466 nComponentElements++
467 up = unpackUint16(data[posInSymbol : posInSymbol+2])
468 flags = up
469 up = unpackUint16(data[posInSymbol+2 : posInSymbol+4])
470 symbolIdx := up
471 if _, OK := utf.symbolData[originalSymbolIdx]; !OK {
472 utf.symbolData[originalSymbolIdx] = make(map[string][]int)
473 }
474 if _, OK := utf.symbolData[originalSymbolIdx]["compSymbols"]; !OK {
475 utf.symbolData[originalSymbolIdx]["compSymbols"] = make([]int, 0)
476 }
477 utf.symbolData[originalSymbolIdx]["compSymbols"] = append(utf.symbolData[originalSymbolIdx]["compSymbols"], symbolIdx)
478 data = utf.insertUint16(data, posInSymbol+2, symbolArray[symbolIdx])
479 posInSymbol += 4
480 if (flags & symbolWords) != 0 {
481 posInSymbol += 4
482 } else {
483 posInSymbol += 2
484 }
485 if (flags & symbolScale) != 0 {
486 posInSymbol += 2
487 } else if (flags & symbolAllScale) != 0 {
488 posInSymbol += 4
489 } else if (flags & symbol2x2) != 0 {
490 posInSymbol += 8
491 }
492 }
493 }
494
495 glyfData = append(glyfData, data...)
496 pos += symbolLen
497 if pos%4 != 0 {
498 padding := 4 - (pos % 4)
499 glyfData = append(glyfData, make([]byte, padding)...)
500 pos += padding
501 }
502 }
503
504 offsets = append(offsets, pos)
505 utf.setOutTable("glyf", glyfData)
506
507 utf.setOutTable("hmtx", hmtxData)
508
509 locaData := make([]byte, 0)
510 if ((pos + 1) >> 1) > 0xFFFF {
511 LocaFormat = 1
512 for _, offset := range offsets {
513 locaData = append(locaData, packUint32(offset)...)
514 }
515 } else {
516 LocaFormat = 0
517 for _, offset := range offsets {
518 locaData = append(locaData, packUint16(offset/2)...)
519 }
520 }
521 utf.setOutTable("loca", locaData)
522
523 headData := utf.getTableData("head")
524 headData = utf.insertUint16(headData, 50, LocaFormat)
525 utf.setOutTable("head", headData)
526
527 hheaData := utf.getTableData("hhea")
528 hheaData = utf.insertUint16(hheaData, 34, metricsCount)
529 utf.setOutTable("hhea", hheaData)
530
531 maxp := utf.getTableData("maxp")
532 maxp = utf.insertUint16(maxp, 4, numSymbols)
533 utf.setOutTable("maxp", maxp)
534
535 os2Data := utf.getTableData("OS/2")
536 utf.setOutTable("OS/2", os2Data)
537
538 return utf.assembleTables()
539 }
540
541 func (utf *utf8FontFile) getSymbols(originalSymbolIdx int, start *int, symbolSet map[int]int, SymbolsCollection map[int]int, SymbolsCollectionKeys []int) (*int, map[int]int, map[int]int, []int) {
542 symbolPos := utf.symbolPosition[originalSymbolIdx]
543 symbolSize := utf.symbolPosition[originalSymbolIdx+1] - symbolPos
544 if symbolSize == 0 {
545 return start, symbolSet, SymbolsCollection, SymbolsCollectionKeys
546 }
547 utf.seek(*start + symbolPos)
548
549 lineCount := utf.readInt16()
550
551 if lineCount < 0 {
552 utf.skip(8)
553 flags := symbolContinue
554 for flags&symbolContinue != 0 {
555 flags = utf.readUint16()
556 symbolIndex := utf.readUint16()
557 if _, OK := symbolSet[symbolIndex]; !OK {
558 symbolSet[symbolIndex] = len(SymbolsCollection)
559 SymbolsCollection[symbolIndex] = 1
560 SymbolsCollectionKeys = append(SymbolsCollectionKeys, symbolIndex)
561 }
562 oldPosition, _ := utf.fileReader.seek(0, 1)
563 _, _, _, SymbolsCollectionKeys = utf.getSymbols(symbolIndex, start, symbolSet, SymbolsCollection, SymbolsCollectionKeys)
564 utf.seek(int(oldPosition))
565 if flags&symbolWords != 0 {
566 utf.skip(4)
567 } else {
568 utf.skip(2)
569 }
570 if flags&symbolScale != 0 {
571 utf.skip(2)
572 } else if flags&symbolAllScale != 0 {
573 utf.skip(4)
574 } else if flags&symbol2x2 != 0 {
575 utf.skip(8)
576 }
577 }
578 }
579 return start, symbolSet, SymbolsCollection, SymbolsCollectionKeys
580 }
581
582 func (utf *utf8FontFile) parseHMTXTable(numberOfHMetrics, numSymbols int, symbolToChar map[int][]int, scale float64) {
583 var widths int
584 start := utf.SeekTable("hmtx")
585 arrayWidths := 0
586 var arr []int
587 utf.CharWidths = make([]int, 256*256)
588 charCount := 0
589 arr = unpackUint16Array(utf.getRange(start, numberOfHMetrics*4))
590 for symbol := 0; symbol < numberOfHMetrics; symbol++ {
591 arrayWidths = arr[(symbol*2)+1]
592 if _, OK := symbolToChar[symbol]; OK || symbol == 0 {
593
594 if arrayWidths >= (1 << 15) {
595 arrayWidths = 0
596 }
597 if symbol == 0 {
598 utf.DefaultWidth = scale * float64(arrayWidths)
599 continue
600 }
601 for _, char := range symbolToChar[symbol] {
602 if char != 0 && char != 65535 {
603 widths = int(math.Round(scale * float64(arrayWidths)))
604 if widths == 0 {
605 widths = 65535
606 }
607 if char < 196608 {
608 utf.CharWidths[char] = widths
609 charCount++
610 }
611 }
612 }
613 }
614 }
615 diff := numSymbols - numberOfHMetrics
616 for pos := 0; pos < diff; pos++ {
617 symbol := pos + numberOfHMetrics
618 if _, OK := symbolToChar[symbol]; OK {
619 for _, char := range symbolToChar[symbol] {
620 if char != 0 && char != 65535 {
621 widths = int(math.Round(scale * float64(arrayWidths)))
622 if widths == 0 {
623 widths = 65535
624 }
625 if char < 196608 {
626 utf.CharWidths[char] = widths
627 charCount++
628 }
629 }
630 }
631 }
632 }
633 utf.CharWidths[0] = charCount
634 }
635
636 func (utf *utf8FontFile) getMetrics(metricCount, gid int) []byte {
637 start := utf.SeekTable("hmtx")
638 var metrics []byte
639 if gid < metricCount {
640 utf.seek(start + (gid * 4))
641 metrics = utf.fileReader.Read(4)
642 } else {
643 utf.seek(start + ((metricCount - 1) * 4))
644 metrics = utf.fileReader.Read(2)
645 utf.seek(start + (metricCount * 2) + (gid * 2))
646 metrics = append(metrics, utf.fileReader.Read(2)...)
647 }
648 return metrics
649 }
650
651 func (utf *utf8FontFile) parseLOCATable(format, numSymbols int) {
652 start := utf.SeekTable("loca")
653 utf.symbolPosition = make([]int, 0)
654 if format == 0 {
655 data := utf.getRange(start, (numSymbols*2)+2)
656 arr := unpackUint16Array(data)
657 for n := 0; n <= numSymbols; n++ {
658 utf.symbolPosition = append(utf.symbolPosition, arr[n+1]*2)
659 }
660 } else if format == 1 {
661 data := utf.getRange(start, (numSymbols*4)+4)
662 arr := unpackUint32Array(data)
663 for n := 0; n <= numSymbols; n++ {
664 utf.symbolPosition = append(utf.symbolPosition, arr[n+1])
665 }
666 } else {
667 fmt.Printf("Unknown loca table format %d\n", format)
668 return
669 }
670 }
671
672 func (utf *utf8FontFile) generateSCCSDictionaries(runeCmapPosition int, symbolCharDictionary map[int][]int, charSymbolDictionary map[int]int) {
673 maxRune := 0
674 utf.seek(runeCmapPosition + 2)
675 size := utf.readUint16()
676 rim := runeCmapPosition + size
677 utf.skip(2)
678
679 segmentSize := utf.readUint16() / 2
680 utf.skip(6)
681 completers := make([]int, 0)
682 for i := 0; i < segmentSize; i++ {
683 completers = append(completers, utf.readUint16())
684 }
685 utf.skip(2)
686 beginners := make([]int, 0)
687 for i := 0; i < segmentSize; i++ {
688 beginners = append(beginners, utf.readUint16())
689 }
690 sizes := make([]int, 0)
691 for i := 0; i < segmentSize; i++ {
692 sizes = append(sizes, int(utf.readInt16()))
693 }
694 readerPositionStart := utf.fileReader.readerPosition
695 positions := make([]int, 0)
696 for i := 0; i < segmentSize; i++ {
697 positions = append(positions, utf.readUint16())
698 }
699 var symbol int
700 for n := 0; n < segmentSize; n++ {
701 completePosition := completers[n] + 1
702 for char := beginners[n]; char < completePosition; char++ {
703 if positions[n] == 0 {
704 symbol = (char + sizes[n]) & 0xFFFF
705 } else {
706 position := (char-beginners[n])*2 + positions[n]
707 position = int(readerPositionStart) + 2*n + position
708 if position >= rim {
709 symbol = 0
710 } else {
711 symbol = utf.getUint16(position)
712 if symbol != 0 {
713 symbol = (symbol + sizes[n]) & 0xFFFF
714 }
715 }
716 }
717 charSymbolDictionary[char] = symbol
718 if char < 196608 {
719 maxRune = max(char, maxRune)
720 }
721 symbolCharDictionary[symbol] = append(symbolCharDictionary[symbol], char)
722 }
723 }
724 }
725
726 func max(i, n int) int {
727 if n > i {
728 return n
729 }
730 return i
731 }
732
733 func (utf *utf8FontFile) assembleTables() []byte {
734 answer := make([]byte, 0)
735 tablesCount := len(utf.outTablesData)
736 findSize := 1
737 writer := 0
738 for findSize*2 <= tablesCount {
739 findSize = findSize * 2
740 writer = writer + 1
741 }
742 findSize = findSize * 16
743 rOffset := tablesCount*16 - findSize
744
745 answer = append(answer, packHeader(0x00010000, tablesCount, findSize, writer, rOffset)...)
746
747 tables := utf.outTablesData
748 tablesNames := keySortStrings(tables)
749
750 offset := 12 + tablesCount*16
751 begin := 0
752
753 for _, name := range tablesNames {
754 if name == "head" {
755 begin = offset
756 }
757 answer = append(answer, []byte(name)...)
758 checksum := utf.generateChecksum(tables[name])
759 answer = append(answer, pack2Uint16(checksum[0], checksum[1])...)
760 answer = append(answer, pack2Uint32(offset, len(tables[name]))...)
761 paddedLength := (len(tables[name]) + 3) &^ 3
762 offset = offset + paddedLength
763 }
764
765 for _, key := range tablesNames {
766 data := append([]byte{}, tables[key]...)
767 data = append(data, []byte{0, 0, 0}...)
768 answer = append(answer, data[:(len(data)&^3)]...)
769 }
770
771 checksum := utf.generateChecksum([]byte(answer))
772 checksum = utf.calcInt32([]int{0xB1B0, 0xAFBA}, checksum)
773 answer = utf.splice(answer, (begin + 8), pack2Uint16(checksum[0], checksum[1]))
774 return answer
775 }
776
777 func unpackUint16Array(data []byte) []int {
778 answer := make([]int, 1)
779 r := bytes.NewReader(data)
780 bs := make([]byte, 2)
781 var e error
782 var c int
783 c, e = r.Read(bs)
784 for e == nil && c > 0 {
785 answer = append(answer, int(binary.BigEndian.Uint16(bs)))
786 c, e = r.Read(bs)
787 }
788 return answer
789 }
790
791 func unpackUint32Array(data []byte) []int {
792 answer := make([]int, 1)
793 r := bytes.NewReader(data)
794 bs := make([]byte, 4)
795 var e error
796 var c int
797 c, e = r.Read(bs)
798 for e == nil && c > 0 {
799 answer = append(answer, int(binary.BigEndian.Uint32(bs)))
800 c, e = r.Read(bs)
801 }
802 return answer
803 }
804
805 func unpackUint16(data []byte) int {
806 return int(binary.BigEndian.Uint16(data))
807 }
808
809 func packHeader(N uint32, n1, n2, n3, n4 int) []byte {
810 answer := make([]byte, 0)
811 bs4 := make([]byte, 4)
812 binary.BigEndian.PutUint32(bs4, N)
813 answer = append(answer, bs4...)
814 bs := make([]byte, 2)
815 binary.BigEndian.PutUint16(bs, uint16(n1))
816 answer = append(answer, bs...)
817 binary.BigEndian.PutUint16(bs, uint16(n2))
818 answer = append(answer, bs...)
819 binary.BigEndian.PutUint16(bs, uint16(n3))
820 answer = append(answer, bs...)
821 binary.BigEndian.PutUint16(bs, uint16(n4))
822 answer = append(answer, bs...)
823 return answer
824 }
825
826 func pack2Uint16(n1, n2 int) []byte {
827 answer := make([]byte, 0)
828 bs := make([]byte, 2)
829 binary.BigEndian.PutUint16(bs, uint16(n1))
830 answer = append(answer, bs...)
831 binary.BigEndian.PutUint16(bs, uint16(n2))
832 answer = append(answer, bs...)
833 return answer
834 }
835
836 func pack2Uint32(n1, n2 int) []byte {
837 answer := make([]byte, 0)
838 bs := make([]byte, 4)
839 binary.BigEndian.PutUint32(bs, uint32(n1))
840 answer = append(answer, bs...)
841 binary.BigEndian.PutUint32(bs, uint32(n2))
842 answer = append(answer, bs...)
843 return answer
844 }
845
846 func packUint32(n1 int) []byte {
847 bs := make([]byte, 4)
848 binary.BigEndian.PutUint32(bs, uint32(n1))
849 return bs
850 }
851
852 func packUint16(n1 int) []byte {
853 bs := make([]byte, 2)
854 binary.BigEndian.PutUint16(bs, uint16(n1))
855 return bs
856 }
857
858 func keySortStrings(s map[string][]byte) []string {
859 keys := make([]string, len(s))
860 i := 0
861 for key := range s {
862 keys[i] = key
863 i++
864 }
865 sort.Strings(keys)
866 return keys
867 }
868
869 func keySortInt(s map[int]int) []int {
870 keys := make([]int, len(s))
871 i := 0
872 for key := range s {
873 keys[i] = key
874 i++
875 }
876 sort.Ints(keys)
877 return keys
878 }
879
880 func keySortArrayRangeMap(s map[int][]int) []int {
881 keys := make([]int, len(s))
882 i := 0
883 for key := range s {
884 keys[i] = key
885 i++
886 }
887 sort.Ints(keys)
888 return keys
889 }
890
891
892
893
894 func UTF8CutFont(inBuf []byte, cutset string) (outBuf []byte) {
895 f := newUTF8Font(&fileReader{readerPosition: 0, array: inBuf})
896 runes := map[int]int{}
897 for i, r := range cutset {
898 runes[i] = int(r)
899 }
900 outBuf = f.GenerateCutFont(runes)
901 return
902 }
903
View as plain text