github.com/signintech/pdft@v0.5.0/minigopdf/fontmaker/core/ttfparser.go (about) 1 package core 2 3 import ( 4 //"encoding/binary" 5 //"encoding/hex" 6 "bytes" 7 "encoding/binary" 8 "errors" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "os" 13 "regexp" 14 "strconv" 15 "strings" 16 ) 17 18 var ERROR_NO_UNICODE_ENCODING_FOUND = errors.New("No Unicode encoding found") 19 var ERROR_UNEXPECTED_SUBTABLE_FORMAT = errors.New("Unexpected subtable format") 20 var ERROR_INCORRECT_MAGIC_NUMBER = errors.New("Incorrect magic number") 21 var ERROR_POSTSCRIPT_NAME_NOT_FOUND = errors.New("PostScript name not found") 22 23 // TTFParser true type font parser 24 type TTFParser struct { 25 tables map[string]TableDirectoryEntry 26 //head 27 unitsPerEm uint 28 xMin int 29 yMin int 30 xMax int 31 yMax int 32 indexToLocFormat int 33 //Hhea 34 numberOfHMetrics uint 35 ascender int 36 descender int 37 //end Hhea 38 39 numGlyphs uint 40 widths []uint 41 chars map[int]uint 42 postScriptName string 43 44 //os2 45 os2Version uint 46 Embeddable bool 47 Bold bool 48 typoAscender int 49 typoDescender int 50 capHeight int 51 sxHeight int 52 53 //post 54 italicAngle int 55 underlinePosition int 56 underlineThickness int 57 isFixedPitch bool 58 sTypoLineGap int 59 usWinAscent uint 60 usWinDescent uint 61 62 //cmap 63 IsShortIndex bool 64 LocaTable []uint 65 SegCount uint 66 StartCount []uint 67 EndCount []uint 68 IdRangeOffset []uint 69 IdDelta []uint 70 GlyphIdArray []uint 71 symbol bool 72 73 //cmap format 12 74 groupingTables []CmapFormat12GroupingTable 75 76 //data of font 77 cahceFontData []byte 78 79 //kerning 80 useKerning bool //user config for use or not use kerning 81 kern *KernTable 82 } 83 84 var Symbolic = 1 << 2 85 var Nonsymbolic = (1 << 5) 86 87 // Kern get KernTable 88 func (t *TTFParser) Kern() *KernTable { 89 return t.kern 90 } 91 92 // UnderlinePosition postion of underline 93 func (t *TTFParser) UnderlinePosition() int { 94 return t.underlinePosition 95 } 96 97 // GroupingTables get cmap format12 grouping table 98 func (t *TTFParser) GroupingTables() []CmapFormat12GroupingTable { 99 return t.groupingTables 100 } 101 102 // UnderlineThickness thickness of underline 103 func (t *TTFParser) UnderlineThickness() int { 104 return t.underlineThickness 105 } 106 107 func (t *TTFParser) XHeight() int { 108 if t.os2Version >= 2 && t.sxHeight != 0 { 109 return t.sxHeight 110 } else { 111 return int((0.66) * float64(t.ascender)) 112 } 113 } 114 115 func (t *TTFParser) XMin() int { 116 return t.xMin 117 } 118 119 func (t *TTFParser) YMin() int { 120 return t.yMin 121 } 122 123 func (t *TTFParser) XMax() int { 124 return t.xMax 125 } 126 127 func (t *TTFParser) YMax() int { 128 return t.yMax 129 } 130 131 func (t *TTFParser) ItalicAngle() int { 132 return t.italicAngle 133 } 134 135 func (t *TTFParser) Flag() int { 136 flag := 0 137 if t.symbol { 138 flag |= Symbolic 139 } else { 140 flag |= Nonsymbolic 141 } 142 return flag 143 } 144 145 func (t *TTFParser) Ascender() int { 146 if t.typoAscender == 0 { 147 return t.ascender 148 } 149 return int(t.usWinAscent) 150 } 151 152 func (t *TTFParser) Descender() int { 153 if t.typoDescender == 0 { 154 return t.descender 155 } 156 descender := int(t.usWinDescent) 157 if t.descender < 0 { 158 descender = descender * (-1) 159 } 160 return descender 161 } 162 163 func (t *TTFParser) TypoAscender() int { 164 return t.typoAscender 165 } 166 167 func (t *TTFParser) TypoDescender() int { 168 return t.typoDescender 169 } 170 171 // CapHeight https://en.wikipedia.org/wiki/Cap_height 172 func (t *TTFParser) CapHeight() int { 173 return t.capHeight 174 } 175 176 // NumGlyphs number of glyph 177 func (t *TTFParser) NumGlyphs() uint { 178 return t.numGlyphs 179 } 180 181 func (t *TTFParser) UnitsPerEm() uint { 182 return t.unitsPerEm 183 } 184 185 func (t *TTFParser) NumberOfHMetrics() uint { 186 return t.numberOfHMetrics 187 } 188 189 func (t *TTFParser) Widths() []uint { 190 return t.widths 191 } 192 193 func (t *TTFParser) Chars() map[int]uint { 194 return t.chars 195 } 196 197 func (t *TTFParser) GetTables() map[string]TableDirectoryEntry { 198 return t.tables 199 } 200 201 // SetUseKerning set useKerning must set before Parse 202 func (t *TTFParser) SetUseKerning(use bool) { 203 t.useKerning = use 204 } 205 206 // Parse parse 207 func (t *TTFParser) Parse(filepath string) error { 208 data, err := ioutil.ReadFile(filepath) 209 if err != nil { 210 return err 211 } 212 buff := bytes.NewBuffer(data) 213 return t.parse(buff) 214 } 215 216 // ParseByReader parse by io.reader 217 func (t *TTFParser) ParseByReader(rd io.Reader) error { 218 return t.parse(rd) 219 } 220 221 func (t *TTFParser) parse(rd io.Reader) error { 222 223 fontdata, err := ioutil.ReadAll(rd) 224 if err != nil { 225 return err 226 } 227 //t.cahceFontData = fontdata 228 fd := bytes.NewReader(fontdata) 229 230 version, err := t.Read(fd, 4) 231 if err != nil { 232 return err 233 } 234 if !t.CompareBytes(version, []byte{0x00, 0x01, 0x00, 0x00}) { 235 return errors.New("Unrecognized file (font) format") 236 } 237 238 i := uint(0) 239 numTables, err := t.ReadUShort(fd) 240 if err != nil { 241 return err 242 } 243 t.Skip(fd, 3*2) //searchRange, entrySelector, rangeShift 244 t.tables = make(map[string]TableDirectoryEntry) 245 for i < numTables { 246 247 tag, err := t.Read(fd, 4) 248 if err != nil { 249 return err 250 } 251 252 checksum, err := t.ReadULong(fd) 253 if err != nil { 254 return err 255 } 256 257 //fmt.Printf("offset\n") 258 offset, err := t.ReadULong(fd) 259 if err != nil { 260 return err 261 } 262 263 length, err := t.ReadULong(fd) 264 if err != nil { 265 return err 266 } 267 //fmt.Printf("\n\ntag=%s \nOffset = %d\n", tag, offset) 268 var table TableDirectoryEntry 269 table.Offset = uint(offset) 270 table.CheckSum = checksum 271 table.Length = length 272 //fmt.Printf("\n\ntag=%s \nOffset = %d\nPaddedLength =%d\n\n ", tag, table.Offset, table.PaddedLength()) 273 t.tables[t.BytesToString(tag)] = table 274 i++ 275 } 276 277 //fmt.Printf("%+v\n", me.tables) 278 279 err = t.ParseHead(fd) 280 if err != nil { 281 return err 282 } 283 284 err = t.ParseHhea(fd) 285 if err != nil { 286 return err 287 } 288 289 err = t.ParseMaxp(fd) 290 if err != nil { 291 return err 292 } 293 err = t.ParseHmtx(fd) 294 if err != nil { 295 return err 296 } 297 err = t.ParseCmap(fd) 298 if err != nil { 299 return err 300 } 301 err = t.ParseName(fd) 302 if err != nil { 303 return err 304 } 305 err = t.ParseOS2(fd) 306 if err != nil { 307 return err 308 } 309 err = t.ParsePost(fd) 310 if err != nil { 311 return err 312 } 313 err = t.ParseLoca(fd) 314 if err != nil { 315 return err 316 } 317 318 if t.useKerning { 319 err = t.Parsekern(fd) 320 if err != nil { 321 return err 322 } 323 } 324 325 //fmt.Printf("%#v\n", me.widths) 326 t.cahceFontData = fontdata //t.readFontData(fontpath) 327 328 return nil 329 } 330 331 func (t *TTFParser) FontData() []byte { 332 return t.cahceFontData 333 } 334 335 // ParseLoca parse loca table https://www.microsoft.com/typography/otspec/loca.htm 336 func (t *TTFParser) ParseLoca(fd *bytes.Reader) error { 337 338 t.IsShortIndex = false 339 if t.indexToLocFormat == 0 { 340 t.IsShortIndex = true 341 } 342 343 //fmt.Printf("indexToLocFormat = %d\n", me.indexToLocFormat) 344 err := t.Seek(fd, "loca") 345 if err != nil { 346 return err 347 } 348 var locaTable []uint 349 table := t.tables["loca"] 350 if t.IsShortIndex { 351 //do ShortIndex 352 entries := table.Length / 2 353 i := uint(0) 354 for i < entries { 355 item, err := t.ReadUShort(fd) 356 if err != nil { 357 return err 358 } 359 locaTable = append(locaTable, item*2) 360 i++ 361 } 362 } else { 363 entries := table.Length / 4 364 i := uint(0) 365 for i < entries { 366 item, err := t.ReadULong(fd) 367 if err != nil { 368 return err 369 } 370 locaTable = append(locaTable, item) 371 i++ 372 } 373 } 374 t.LocaTable = locaTable 375 return nil 376 } 377 378 // ParsePost parse post table https://www.microsoft.com/typography/otspec/post.htm 379 func (t *TTFParser) ParsePost(fd *bytes.Reader) error { 380 381 err := t.Seek(fd, "post") 382 if err != nil { 383 return err 384 } 385 386 err = t.Skip(fd, 4) // version 387 if err != nil { 388 return err 389 } 390 391 t.italicAngle, err = t.ReadShort(fd) 392 if err != nil { 393 return err 394 } 395 396 err = t.Skip(fd, 2) // Skip decimal part 397 if err != nil { 398 return err 399 } 400 401 t.underlinePosition, err = t.ReadShort(fd) 402 if err != nil { 403 return err 404 } 405 406 //fmt.Printf("start>>>>>>>\n") 407 t.underlineThickness, err = t.ReadShort(fd) 408 if err != nil { 409 return err 410 } 411 //fmt.Printf("underlineThickness=%d\n", t.underlineThickness) 412 //fmt.Printf(">>>>>>>%d\n", me.underlineThickness) 413 414 isFixedPitch, err := t.ReadULong(fd) 415 if err != nil { 416 return err 417 } 418 t.isFixedPitch = (isFixedPitch != 0) 419 420 return nil 421 } 422 423 // ParseOS2 parse OS2 table https://www.microsoft.com/typography/otspec/OS2.htm 424 func (t *TTFParser) ParseOS2(fd *bytes.Reader) error { 425 err := t.Seek(fd, "OS/2") 426 if err != nil { 427 return err 428 } 429 version, err := t.ReadUShort(fd) 430 if err != nil { 431 return err 432 } 433 t.os2Version = version 434 435 err = t.Skip(fd, 3*2) // xAvgCharWidth, usWeightClass, usWidthClass 436 if err != nil { 437 return err 438 } 439 fsType, err := t.ReadUShort(fd) 440 if err != nil { 441 return err 442 } 443 t.Embeddable = (fsType != 2) && ((fsType & 0x200) == 0) 444 445 err = t.Skip(fd, (11*2)+10+(4*4)+4) 446 if err != nil { 447 return err 448 } 449 fsSelection, err := t.ReadUShort(fd) 450 if err != nil { 451 return err 452 } 453 t.Bold = ((fsSelection & 32) != 0) 454 err = t.Skip(fd, 2*2) // usFirstCharIndex, usLastCharIndex 455 if err != nil { 456 return err 457 } 458 t.typoAscender, err = t.ReadShort(fd) 459 if err != nil { 460 return err 461 } 462 463 t.typoDescender, err = t.ReadShort(fd) 464 if err != nil { 465 return err 466 } 467 468 t.sTypoLineGap, err = t.ReadShort(fd) 469 if err != nil { 470 return err 471 } 472 473 t.usWinAscent, err = t.ReadUShort(fd) 474 if err != nil { 475 return err 476 } 477 478 t.usWinDescent, err = t.ReadUShort(fd) 479 if err != nil { 480 return err 481 } 482 483 if version >= 2 { 484 485 err = t.Skip(fd, 2*4) 486 if err != nil { 487 return err 488 } 489 490 t.sxHeight, err = t.ReadShort(fd) 491 if err != nil { 492 return err 493 } 494 495 t.capHeight, err = t.ReadShort(fd) 496 if err != nil { 497 return err 498 } 499 500 } else { 501 t.capHeight = t.ascender 502 } 503 504 return nil 505 } 506 507 // ParseName parse name table https://www.microsoft.com/typography/otspec/name.htm 508 func (t *TTFParser) ParseName(fd *bytes.Reader) error { 509 510 //$this->Seek('name'); 511 err := t.Seek(fd, "name") 512 if err != nil { 513 return err 514 } 515 516 tableOffset, err := t.FTell(fd) 517 if err != nil { 518 return err 519 } 520 521 t.postScriptName = "" 522 err = t.Skip(fd, 2) // format 523 if err != nil { 524 return err 525 } 526 527 count, err := t.ReadUShort(fd) 528 if err != nil { 529 return err 530 } 531 532 stringOffset, err := t.ReadUShort(fd) 533 if err != nil { 534 return err 535 } 536 537 for i := 0; i < int(count); i++ { 538 err = t.Skip(fd, 3*2) // platformID, encodingID, languageID 539 if err != nil { 540 return err 541 } 542 nameID, err := t.ReadUShort(fd) 543 if err != nil { 544 return err 545 } 546 length, err := t.ReadUShort(fd) 547 if err != nil { 548 return err 549 } 550 offset, err := t.ReadUShort(fd) 551 if err != nil { 552 return err 553 } 554 if nameID == 6 { 555 // PostScript name 556 _, err = fd.Seek(int64(tableOffset+stringOffset+offset), 0) 557 if err != nil { 558 return err 559 } 560 561 stmp, err := t.Read(fd, int(length)) 562 if err != nil { 563 return err 564 } 565 566 var tmpStmp []byte 567 for _, v := range stmp { 568 if v != 0 { 569 tmpStmp = append(tmpStmp, v) 570 } 571 } 572 s := fmt.Sprintf("%s", string(tmpStmp)) //strings(stmp) 573 s = strings.Replace(s, strconv.Itoa(0), "", -1) 574 s, err = t.PregReplace("|[ \\[\\](){}<>/%]|", "", s) 575 if err != nil { 576 return err 577 } 578 t.postScriptName = s 579 break 580 } 581 } 582 583 if t.postScriptName == "" { 584 return ERROR_POSTSCRIPT_NAME_NOT_FOUND 585 } 586 587 //fmt.Printf("%s\n", me.postScriptName) 588 return nil 589 } 590 591 func (t *TTFParser) PregReplace(pattern string, replacement string, subject string) (string, error) { 592 593 reg, err := regexp.Compile(pattern) 594 if err != nil { 595 return "", err 596 } 597 str := reg.ReplaceAllString(subject, replacement) 598 return str, nil 599 } 600 601 // ParseCmap parse cmap table format 4 https://www.microsoft.com/typography/otspec/cmap.htm 602 func (t *TTFParser) ParseCmap(fd *bytes.Reader) error { 603 t.Seek(fd, "cmap") 604 t.Skip(fd, 2) // version 605 numTables, err := t.ReadUShort(fd) 606 if err != nil { 607 return err 608 } 609 610 offset31 := uint(0) 611 for i := 0; i < int(numTables); i++ { 612 platformID, err := t.ReadUShort(fd) 613 if err != nil { 614 return err 615 } 616 encodingID, err := t.ReadUShort(fd) 617 if err != nil { 618 return err 619 } 620 offset, err := t.ReadULong(fd) 621 if err != nil { 622 return err 623 } 624 625 t.symbol = false //init 626 if platformID == 3 && encodingID == 1 { 627 if encodingID == 0 { 628 t.symbol = true 629 } 630 offset31 = offset 631 } 632 //fmt.Printf("me.symbol=%d\n", me.symbol) 633 } //end for 634 635 if offset31 == 0 { 636 //No Unicode encoding found 637 return ERROR_NO_UNICODE_ENCODING_FOUND 638 } 639 640 var startCount, endCount, idDelta, idRangeOffset, glyphIDArray []uint 641 642 _, err = fd.Seek(int64(t.tables["cmap"].Offset+offset31), 0) 643 if err != nil { 644 return err 645 } 646 647 format, err := t.ReadUShort(fd) 648 if err != nil { 649 return err 650 } 651 652 if format != 4 { 653 //Unexpected subtable format 654 return ERROR_UNEXPECTED_SUBTABLE_FORMAT 655 } 656 657 length, err := t.ReadUShort(fd) 658 if err != nil { 659 return err 660 } 661 //fmt.Printf("\nlength=%d\n", length) 662 663 err = t.Skip(fd, 2) // language 664 if err != nil { 665 return err 666 } 667 segCount, err := t.ReadUShort(fd) 668 if err != nil { 669 return err 670 } 671 segCount = segCount / 2 672 t.SegCount = segCount 673 err = t.Skip(fd, 3*2) // searchRange, entrySelector, rangeShift 674 if err != nil { 675 return err 676 } 677 678 glyphCount := (length - (16 + 8*segCount)) / 2 679 //fmt.Printf("\nglyphCount=%d\n", glyphCount) 680 681 for i := 0; i < int(segCount); i++ { 682 tmp, err := t.ReadUShort(fd) 683 if err != nil { 684 return err 685 } 686 endCount = append(endCount, tmp) 687 } 688 t.EndCount = endCount 689 690 err = t.Skip(fd, 2) // reservedPad 691 if err != nil { 692 return err 693 } 694 695 for i := 0; i < int(segCount); i++ { 696 tmp, err := t.ReadUShort(fd) 697 if err != nil { 698 return err 699 } 700 startCount = append(startCount, tmp) 701 } 702 t.StartCount = startCount 703 704 for i := 0; i < int(segCount); i++ { 705 tmp, err := t.ReadUShort(fd) 706 if err != nil { 707 return err 708 } 709 idDelta = append(idDelta, tmp) 710 } 711 t.IdDelta = idDelta 712 713 offset, err := t.FTell(fd) 714 if err != nil { 715 return err 716 } 717 for i := 0; i < int(segCount); i++ { 718 tmp, err := t.ReadUShort(fd) 719 if err != nil { 720 return err 721 } 722 idRangeOffset = append(idRangeOffset, tmp) 723 } 724 t.IdRangeOffset = idRangeOffset 725 //_ = glyphIdArray 726 for i := 0; i < int(glyphCount); i++ { 727 tmp, err := t.ReadUShort(fd) 728 if err != nil { 729 return err 730 } 731 glyphIDArray = append(glyphIDArray, tmp) 732 } 733 t.GlyphIdArray = glyphIDArray 734 735 t.chars = make(map[int]uint) 736 for i := 0; i < int(segCount); i++ { 737 c1 := startCount[i] 738 c2 := endCount[i] 739 d := idDelta[i] 740 ro := idRangeOffset[i] 741 if ro > 0 { 742 _, err = fd.Seek(int64(offset+uint(2*i)+ro), 0) 743 if err != nil { 744 return err 745 } 746 } 747 748 for c := c1; c <= c2; c++ { 749 var gid uint 750 if c == 0xFFFF { 751 break 752 } 753 if ro > 0 { 754 gid, err = t.ReadUShort(fd) 755 if err != nil { 756 return err 757 } 758 if gid > 0 { 759 gid += d 760 } 761 } else { 762 gid = c + d 763 } 764 765 if gid >= 65536 { 766 gid -= 65536 767 } 768 if gid > 0 { 769 //fmt.Printf("%d gid = %d, ", int(c), gid) 770 t.chars[int(c)] = gid 771 } 772 } 773 774 } 775 776 _, err = t.ParseCmapFormat12(fd) 777 if err != nil { 778 return err 779 } 780 781 return nil 782 } 783 784 func (t *TTFParser) FTell(fd *bytes.Reader) (uint, error) { 785 offset, err := fd.Seek(0, os.SEEK_CUR) 786 return uint(offset), err 787 } 788 789 // ParseHmtx parse hmtx table https://www.microsoft.com/typography/otspec/hmtx.htm 790 func (t *TTFParser) ParseHmtx(fd *bytes.Reader) error { 791 792 t.Seek(fd, "hmtx") 793 i := uint(0) 794 for i < t.numberOfHMetrics { 795 advanceWidth, err := t.ReadUShort(fd) 796 if err != nil { 797 return err 798 } 799 err = t.Skip(fd, 2) 800 if err != nil { 801 return err 802 } 803 t.widths = append(t.widths, advanceWidth) 804 i++ 805 } 806 if t.numberOfHMetrics < t.numGlyphs { 807 var err error 808 lastWidth := t.widths[t.numberOfHMetrics-1] 809 t.widths, err = t.ArrayPadUint(t.widths, t.numGlyphs, lastWidth) 810 if err != nil { 811 return err 812 } 813 } 814 815 return nil 816 } 817 818 func (t *TTFParser) ArrayPadUint(arr []uint, size uint, val uint) ([]uint, error) { 819 var result []uint 820 i := uint(0) 821 for i < size { 822 if int(i) < len(arr) { 823 result = append(result, arr[i]) 824 } else { 825 result = append(result, val) 826 } 827 i++ 828 } 829 830 return result, nil 831 } 832 833 // ParseHead parse head table https://www.microsoft.com/typography/otspec/Head.htm 834 func (t *TTFParser) ParseHead(fd *bytes.Reader) error { 835 836 //fmt.Printf("\nParseHead\n") 837 err := t.Seek(fd, "head") 838 if err != nil { 839 return err 840 } 841 842 err = t.Skip(fd, 3*4) // version, fontRevision, checkSumAdjustment 843 if err != nil { 844 return err 845 } 846 magicNumber, err := t.ReadULong(fd) 847 if err != nil { 848 return err 849 } 850 851 //fmt.Printf("\nmagicNumber = %d\n", magicNumber) 852 if magicNumber != 0x5F0F3CF5 { 853 return ERROR_INCORRECT_MAGIC_NUMBER 854 } 855 856 err = t.Skip(fd, 2) 857 if err != nil { 858 return err 859 } 860 861 t.unitsPerEm, err = t.ReadUShort(fd) 862 if err != nil { 863 return err 864 } 865 866 err = t.Skip(fd, 2*8) // created, modified 867 if err != nil { 868 return err 869 } 870 871 t.xMin, err = t.ReadShort(fd) 872 if err != nil { 873 return err 874 } 875 876 t.yMin, err = t.ReadShort(fd) 877 if err != nil { 878 return err 879 } 880 881 t.xMax, err = t.ReadShort(fd) 882 if err != nil { 883 return err 884 } 885 886 t.yMax, err = t.ReadShort(fd) 887 if err != nil { 888 return err 889 } 890 891 err = t.Skip(fd, 2*3) //skip macStyle,lowestRecPPEM,fontDirectionHint 892 if err != nil { 893 return err 894 } 895 896 t.indexToLocFormat, err = t.ReadShort(fd) 897 if err != nil { 898 return err 899 } 900 901 return nil 902 } 903 904 // ParseHhea parse hhea table https://www.microsoft.com/typography/otspec/hhea.htm 905 func (t *TTFParser) ParseHhea(fd *bytes.Reader) error { 906 907 err := t.Seek(fd, "hhea") 908 if err != nil { 909 return err 910 } 911 912 err = t.Skip(fd, 4) //skip version 913 if err != nil { 914 return err 915 } 916 917 t.ascender, err = t.ReadShort(fd) 918 if err != nil { 919 return err 920 } 921 922 t.descender, err = t.ReadShort(fd) 923 if err != nil { 924 return err 925 } 926 927 err = t.Skip(fd, 13*2) 928 if err != nil { 929 return err 930 } 931 932 t.numberOfHMetrics, err = t.ReadUShort(fd) 933 if err != nil { 934 return err 935 } 936 937 return nil 938 } 939 940 // ParseMaxp parse maxp table https://www.microsoft.com/typography/otspec/Maxp.htm 941 func (t *TTFParser) ParseMaxp(fd *bytes.Reader) error { 942 err := t.Seek(fd, "maxp") 943 if err != nil { 944 return err 945 } 946 err = t.Skip(fd, 4) 947 if err != nil { 948 return err 949 } 950 t.numGlyphs, err = t.ReadUShort(fd) 951 if err != nil { 952 return err 953 } 954 return nil 955 } 956 957 // ErrTableNotFound error table not found 958 var ErrTableNotFound = errors.New("table not found") 959 960 // Seek seek by tag 961 func (t *TTFParser) Seek(fd *bytes.Reader, tag string) error { 962 table, ok := t.tables[tag] 963 if !ok { 964 return ErrTableNotFound 965 } 966 val := table.Offset 967 _, err := fd.Seek(int64(val), 0) 968 if err != nil { 969 return err 970 } 971 return nil 972 } 973 974 // BytesToString convert bytes to string 975 func (t *TTFParser) BytesToString(b []byte) string { 976 return string(b) //strings.TrimSpace(string(b)) 977 } 978 979 // ReadUShort read ushort 980 func (t *TTFParser) ReadUShort(fd *bytes.Reader) (uint, error) { 981 buff, err := t.Read(fd, 2) 982 if err != nil { 983 return 0, err 984 } 985 n := binary.BigEndian.Uint16(buff) 986 return uint(n), nil 987 } 988 989 // ReadShort read short 990 func (t *TTFParser) ReadShort(fd *bytes.Reader) (int, error) { 991 u, err := t.ReadUShort(fd) 992 if err != nil { 993 return 0, err 994 } 995 996 //fmt.Printf("%#v\n", buff) 997 var v int 998 if u >= 0x8000 { 999 v = int(u) - 65536 1000 } else { 1001 v = int(u) 1002 } 1003 return v, nil 1004 } 1005 1006 // ReadShortInt16 read short return int16 1007 func (t *TTFParser) ReadShortInt16(fd *bytes.Reader) (int16, error) { 1008 n, err := t.ReadShort(fd) 1009 if err != nil { 1010 return 0, err 1011 } 1012 return int16(n), nil 1013 } 1014 1015 // ReadULong read ulong 1016 func (t *TTFParser) ReadULong(fd *bytes.Reader) (uint, error) { 1017 buff, err := t.Read(fd, 4) 1018 //fmt.Printf("%#v\n", buff) 1019 if err != nil { 1020 return 0, err 1021 } 1022 n := binary.BigEndian.Uint32(buff) 1023 return uint(n), nil 1024 } 1025 1026 // Skip skip 1027 func (t *TTFParser) Skip(fd *bytes.Reader, length int) error { 1028 _, err := fd.Seek(int64(length), 1) 1029 if err != nil { 1030 return err 1031 } 1032 return nil 1033 } 1034 1035 // Read read 1036 func (t *TTFParser) Read(fd *bytes.Reader, length int) ([]byte, error) { 1037 buff := make([]byte, length) 1038 readlength, err := fd.Read(buff) 1039 if err != nil { 1040 return nil, err 1041 } 1042 if readlength != length { 1043 return nil, errors.New("file out of length") 1044 } 1045 //fmt.Printf("%d,%s\n", readlength, string(buff)) 1046 return buff, nil 1047 } 1048 1049 // CompareBytes compare a and b 1050 func (t *TTFParser) CompareBytes(a []byte, b []byte) bool { 1051 1052 if a == nil && b == nil { 1053 return true 1054 } else if a == nil && b != nil { 1055 return false 1056 } else if a != nil && b == nil { 1057 return false 1058 } 1059 1060 if len(a) != len(b) { 1061 return false 1062 } 1063 1064 i := 0 1065 length := len(a) 1066 for i < length { 1067 if a[i] != b[i] { 1068 return false 1069 } 1070 i++ 1071 } 1072 return true 1073 }