1 51 package org.apache.fop.fonts; 52 53 import java.io.*; 54 import java.util.ArrayList ; 55 import java.util.HashMap ; 56 import java.util.Iterator ; 57 58 63 public class TTFFile { 64 static final byte NTABS = 24; 65 static final int NMACGLYPHS = 258; 66 static final int MAX_CHAR_CODE = 255; 67 static final int ENC_BUF_SIZE = 1024; 68 69 static String encoding = "WinAnsiEncoding"; short firstChar = 0; 71 boolean is_embeddable = true; 72 boolean hasSerifs = true; 73 HashMap dirTabs; HashMap kerningTab; HashMap ansiKerningTab; ArrayList cmaps; 77 ArrayList unicodeMapping; 79 int upem; int nhmtx; int post_format; 82 int loca_format; 83 long lastLoca = 0; int nglyphs; int nmglyphs; 87 TTFMtxEntry mtx_tab[]; int[] mtx_encoded = null; 89 90 String fontName = ""; 91 String fullName = ""; 92 String notice = ""; 93 String familyName = ""; 94 String subFamilyName = ""; 95 96 long italicAngle = 0; 97 long isFixedPitch = 0; 98 int fontBBox1 = 0; 99 int fontBBox2 = 0; 100 int fontBBox3 = 0; 101 int fontBBox4 = 0; 102 int capHeight = 0; 103 int underlinePosition = 0; 104 int underlineThickness = 0; 105 int xHeight = 0; 106 int ascender = 0; 107 int descender = 0; 108 109 short lastChar = 0; 110 111 int ansiWidth[]; 112 HashMap ansiIndex; 113 114 private TTFDirTabEntry currentDirTab; 115 116 120 void seek_tab(FontFileReader in, String name, 121 long offset) throws IOException { 122 TTFDirTabEntry dt = (TTFDirTabEntry)dirTabs.get(name); 123 if (dt == null) { 124 System.out.println("Dirtab " + name + " not found."); 125 } else { 126 in.seek_set(dt.offset + offset); 127 this.currentDirTab = dt; 128 } 129 } 130 131 137 int get_ttf_funit(int n) { 138 int ret; 139 if (n < 0) { 140 long rest1 = n % upem; 141 long storrest = 1000 * rest1; 142 long ledd2 = rest1 / storrest; 143 ret = -((-1000 * n) / upem - (int)ledd2); 144 } else { 145 ret = (n / upem) * 1000 + ((n % upem) * 1000) / upem; 146 } 147 148 return ret; 149 } 150 151 158 private boolean readCMAP(FontFileReader in) throws IOException { 159 160 unicodeMapping = new ArrayList (); 161 162 165 int mtxPtr = 0; 166 167 seek_tab(in, "cmap", 2); 168 int num_cmap = in.readTTFUShort(); long cmap_unioffset = 0; 170 171 173 177 for (int i = 0; i < num_cmap; i++) { 178 int cmap_pid = in.readTTFUShort(); 179 int cmap_eid = in.readTTFUShort(); 180 long cmap_offset = in.readTTFULong(); 181 182 185 if (cmap_pid == 3 && cmap_eid == 1) { 186 cmap_unioffset = cmap_offset; 187 } 188 } 189 190 if (cmap_unioffset <= 0) { 191 System.out.println("Unicode cmap table not present"); 192 return false; 193 } 194 195 seek_tab(in, "cmap", cmap_unioffset); 197 int cmap_format = in.readTTFUShort(); 198 int cmap_length = in.readTTFUShort(); 199 200 if (cmap_format == 4) { 202 in.skip(2); int cmap_segCountX2 = in.readTTFUShort(); 204 int cmap_searchRange = in.readTTFUShort(); 205 int cmap_entrySelector = in.readTTFUShort(); 206 int cmap_rangeShift = in.readTTFUShort(); 207 208 214 215 int cmap_endCounts[] = new int[cmap_segCountX2 / 2]; 216 int cmap_startCounts[] = new int[cmap_segCountX2 / 2]; 217 int cmap_deltas[] = new int[cmap_segCountX2 / 2]; 218 int cmap_rangeOffsets[] = new int[cmap_segCountX2 / 2]; 219 220 for (int i = 0; i < (cmap_segCountX2 / 2); i++) { 221 cmap_endCounts[i] = in.readTTFUShort(); 222 } 223 224 in.skip(2); 226 for (int i = 0; i < (cmap_segCountX2 / 2); i++) { 227 cmap_startCounts[i] = in.readTTFUShort(); 228 } 229 230 for (int i = 0; i < (cmap_segCountX2 / 2); i++) { 231 cmap_deltas[i] = in.readTTFShort(); 232 } 233 234 236 for (int i = 0; i < (cmap_segCountX2 / 2); i++) { 237 cmap_rangeOffsets[i] = in.readTTFUShort(); 238 } 239 240 int glyphIdArrayOffset = in.getCurrentPos(); 241 242 245 for (int i = 0; i < cmap_startCounts.length; i++) { 246 250 for (int j = cmap_startCounts[i]; j <= cmap_endCounts[i]; 251 j++) { 252 253 if (j < 256 && j > lastChar) { 255 lastChar = (short)j; 256 } 257 258 if (mtxPtr < mtx_tab.length) { 259 int glyphIdx; 260 if (cmap_rangeOffsets[i] != 0 && j != 65535) { 263 int glyphOffset = 264 glyphIdArrayOffset 265 + ((cmap_rangeOffsets[i] / 2) + (j - cmap_startCounts[i]) + (i) - cmap_segCountX2 / 2) 266 * 2; 267 in.seek_set(glyphOffset); 268 glyphIdx = (in.readTTFUShort() + cmap_deltas[i]) 269 & 0xffff; 270 271 unicodeMapping.add(new UnicodeMapping(glyphIdx, j)); 272 mtx_tab[glyphIdx].unicodeIndex.add(new Integer (j)); 273 ArrayList v = (ArrayList )ansiIndex.get(new Integer (j)); 275 if (v != null) { 276 for (int k = 0; k < v.size(); k++ ) { 277 Integer aIdx = (Integer )v.get(k); 278 ansiWidth[aIdx.intValue()] = 279 mtx_tab[glyphIdx].wx; 280 286 } 287 } 288 296 297 } else { 298 299 glyphIdx = (j + cmap_deltas[i]) & 0xffff; 300 301 if (glyphIdx < mtx_tab.length) { 302 mtx_tab[glyphIdx].unicodeIndex.add(new Integer (j)); 303 } else { 304 System.out.println("Glyph " + glyphIdx 305 + " out of range: " 306 + mtx_tab.length); 307 } 308 309 unicodeMapping.add(new UnicodeMapping(glyphIdx, 310 j)); 311 if (glyphIdx < mtx_tab.length) { 312 mtx_tab[glyphIdx].unicodeIndex.add(new Integer (j)); 313 } else { 314 System.out.println("Glyph " + glyphIdx 315 + " out of range: " 316 + mtx_tab.length); 317 } 318 319 320 321 ArrayList v = (ArrayList )ansiIndex.get(new Integer (j)); 323 if (v != null) { 324 for (int k = 0; k < v.size(); k++ ) { 325 Integer aIdx = (Integer )v.get(k); 326 ansiWidth[aIdx.intValue()] = 327 mtx_tab[glyphIdx].wx; 328 } 329 } 330 331 339 } 340 if (glyphIdx < mtx_tab.length) { 341 if (mtx_tab[glyphIdx].unicodeIndex.size() < 2) { 342 mtxPtr++; 343 } 344 } 345 } 346 } 347 } 348 } 349 return true; 350 } 351 352 353 354 357 private void print_max_min() { 358 int min = 255; 359 int max = 0; 360 for (int i = 0; i < mtx_tab.length; i++) { 361 if (mtx_tab[i].index < min) 362 min = mtx_tab[i].index; 363 if (mtx_tab[i].index > max) 364 max = mtx_tab[i].index; 365 } 366 System.out.println("Min: " + min); 367 System.out.println("Max: " + max); 368 } 369 370 public void readFont(FontFileReader in) throws IOException { 371 readFont(in, (String )null); 372 } 373 374 378 private void initAnsiWidths() { 379 ansiWidth = new int[256]; 380 for (int i = 0; i < 256; i++) { 381 ansiWidth[i] = mtx_tab[0].wx; 382 } 383 384 ansiIndex = new HashMap (); 388 for (int i = 32; i < Glyphs.winAnsiEncoding.length; i++) { 389 Integer ansi = new Integer (i); 390 Integer uni = new Integer ((int)Glyphs.winAnsiEncoding[i]); 391 392 ArrayList v = (ArrayList )ansiIndex.get(uni); 393 if (v == null) { 394 v = new ArrayList (); 395 ansiIndex.put(uni, v); 396 } 397 v.add(ansi); 398 } 399 } 400 401 402 408 public void readFont(FontFileReader in, String name) throws IOException { 409 410 414 if (!checkTTC(in, name, true)) { 415 if (name == null) { 416 throw new IllegalArgumentException ( 417 "For TrueType collection you must specify which font " 418 + "to select (-ttcname)"); 419 } else { 420 throw new IOException( 421 "Name does not exist in the TrueType collection: " + name); 422 } 423 } 424 425 readDirTabs(in); 426 readFontHeader(in); 427 getNumGlyphs(in); 428 System.out.println("Number of glyphs in font: " + nglyphs); 429 readHorizontalHeader(in); 430 readHorizontalMetrics(in); 431 initAnsiWidths(); 432 readPostscript(in); 433 readOS2(in); 434 readIndexToLocation(in); 435 readGlyf(in); 436 readName(in); 437 readPCLT(in); 438 readCMAP(in); createCMaps(); 442 readKerning(in); 443 } 444 445 private void createCMaps() { 446 cmaps = new ArrayList (); 447 TTFCmapEntry tce = new TTFCmapEntry(); 448 449 UnicodeMapping um = (UnicodeMapping)unicodeMapping.get(0); 450 UnicodeMapping lastMapping = um; 451 452 tce.unicodeStart = um.uIdx; 453 tce.glyphStartIndex = um.gIdx; 454 455 for (int i = 1; i< unicodeMapping.size(); i++) { 456 um = (UnicodeMapping)unicodeMapping.get(i); 457 if (((lastMapping.uIdx + 1) != um.uIdx) 458 || ((lastMapping.gIdx + 1) != um.gIdx)) { 459 tce.unicodeEnd = lastMapping.uIdx; 460 cmaps.add(tce); 461 462 tce = new TTFCmapEntry(); 463 tce.unicodeStart = um.uIdx; 464 tce.glyphStartIndex = um.gIdx; 465 } 466 lastMapping = um; 467 } 468 469 tce.unicodeEnd = um.uIdx; 470 cmaps.add(tce); 471 } 472 473 public void printStuff() { 474 System.out.println("Font name: " + fontName); 475 System.out.println("Full name: " + fullName); 476 System.out.println("Family name: " + familyName); 477 System.out.println("Subfamily name: " + subFamilyName); 478 System.out.println("Notice: " + notice); 479 System.out.println("xHeight: " + (int)get_ttf_funit(xHeight)); 480 System.out.println("capheight: " + (int)get_ttf_funit(capHeight)); 481 482 int italic = (int)(italicAngle >> 16); 483 System.out.println("Italic: " + italic); 484 System.out.print("ItalicAngle: " + (short)(italicAngle / 0x10000)); 485 if ((italicAngle % 0x10000) > 0) { 486 System.out.print("." 487 + (short)((italicAngle % 0x10000) * 1000) 488 / 0x10000); 489 } 490 System.out.println(); 491 System.out.println("Ascender: " + get_ttf_funit(ascender)); 492 System.out.println("Descender: " + get_ttf_funit(descender)); 493 System.out.println("FontBBox: [" + (int)get_ttf_funit(fontBBox1) 494 + " " + (int)get_ttf_funit(fontBBox2) + " " 495 + (int)get_ttf_funit(fontBBox3) + " " 496 + (int)get_ttf_funit(fontBBox4) + "]"); 497 } 498 499 public static void main(String [] args) { 500 try { 501 TTFFile ttfFile = new TTFFile(); 502 FontFileReader reader = new FontFileReader(args[0]); 503 504 String name = null; 505 if (args.length >= 2) { 506 name = args[1]; 507 } 508 509 ttfFile.readFont(reader, name); 510 ttfFile.printStuff(); 511 512 } catch (IOException ioe) { 513 System.out.println(ioe.toString()); 514 } 515 } 516 517 public String getWindowsName() { 518 return new String (familyName + "," + subFamilyName); 519 } 520 521 public String getPostscriptName() { 522 if ("Regular".equals(subFamilyName) || "Roman".equals(subFamilyName)) { 523 return familyName; 524 } else { 525 return familyName + "," + subFamilyName; 526 } 527 } 528 529 public String getFamilyName() { 530 return familyName; 531 } 532 533 public String getCharSetName() { 534 return encoding; 535 } 536 537 public int getCapHeight() { 538 return (int)get_ttf_funit(capHeight); 539 } 540 541 public int getXHeight() { 542 return (int)get_ttf_funit(xHeight); 543 } 544 545 public int getFlags() { 546 int flags = 32; if (italicAngle != 0) { 548 flags = flags | 64; 549 } 550 if (isFixedPitch != 0) { 551 flags = flags | 2; 552 } 553 if (hasSerifs) { 554 flags = flags | 1; 555 } 556 return flags; 557 } 558 559 560 public String getStemV() { 561 return "0"; 562 } 563 564 public String getItalicAngle() { 565 String ia = Short.toString((short)(italicAngle / 0x10000)); 566 567 573 return ia; 574 } 575 576 public int[] getFontBBox() { 577 int[] fbb = new int[4]; 578 fbb[0] = (int)get_ttf_funit(fontBBox1); 579 fbb[1] = (int)get_ttf_funit(fontBBox2); 580 fbb[2] = (int)get_ttf_funit(fontBBox3); 581 fbb[3] = (int)get_ttf_funit(fontBBox4); 582 583 return fbb; 584 } 585 586 public int getLowerCaseAscent() { 587 return (int)get_ttf_funit(ascender); 588 } 589 590 public int getLowerCaseDescent() { 591 return (int)get_ttf_funit(descender); 592 } 593 594 public short getLastChar() { 597 return lastChar; 598 } 599 600 public short getFirstChar() { 601 return firstChar; 602 } 603 604 public int[] getWidths() { 605 int[] wx = new int[mtx_tab.length]; 606 for (int i = 0; i < wx.length; i++) { 607 wx[i] = (int)get_ttf_funit(mtx_tab[i].wx); 608 } 609 610 return wx; 611 } 612 613 public int getCharWidth(int idx) { 614 return (int)get_ttf_funit(ansiWidth[idx]); 615 } 616 617 public HashMap getKerning() { 618 return kerningTab; 619 } 620 621 public HashMap getAnsiKerning() { 622 return ansiKerningTab; 623 } 624 625 public boolean isEmbeddable() { 626 return is_embeddable; 627 } 628 629 630 636 protected void readDirTabs(FontFileReader in) throws IOException { 637 in.skip(4); int ntabs = in.readTTFUShort(); 639 in.skip(6); 641 dirTabs = new HashMap (); 642 TTFDirTabEntry[] pd = new TTFDirTabEntry[ntabs]; 643 for (int i = 0; i < ntabs; i++) { 645 pd[i] = new TTFDirTabEntry(); 646 dirTabs.put(pd[i].read(in), pd[i]); 647 } 648 } 649 650 654 protected void readFontHeader(FontFileReader in) throws IOException { 655 seek_tab(in, "head", 2 * 4 + 2 * 4 + 2); 656 upem = in.readTTFUShort(); 657 658 in.skip(16); 659 660 fontBBox1 = in.readTTFShort(); 661 fontBBox2 = in.readTTFShort(); 662 fontBBox3 = in.readTTFShort(); 663 fontBBox4 = in.readTTFShort(); 664 665 in.skip(2 + 2 + 2); 666 667 loca_format = in.readTTFShort(); 668 } 669 670 673 protected void getNumGlyphs(FontFileReader in) throws IOException { 674 seek_tab(in, "maxp", 4); 675 nglyphs = in.readTTFUShort(); 676 } 677 678 679 684 protected void readHorizontalHeader(FontFileReader in) 685 throws IOException { 686 seek_tab(in, "hhea", 4); 687 ascender = in.readTTFShort(); descender = in.readTTFShort(); 690 in.skip(2 + 2 + 3 * 2 + 8 * 2); 691 nhmtx = in.readTTFUShort(); 692 694 if (ascender == 0 || descender == 0) { 696 seek_tab(in, "OS/2", 68); 697 if (this.currentDirTab.length >= 78) { 698 ascender = in.readTTFShort(); descender = in.readTTFShort(); } 701 } 702 } 703 704 710 protected void readHorizontalMetrics(FontFileReader in) 711 throws IOException { 712 seek_tab(in, "hmtx", 0); 713 714 int mtx_size = (nglyphs > nhmtx) ? nglyphs : nhmtx; 715 mtx_tab = new TTFMtxEntry[mtx_size]; 716 717 for (int i = 0; i < mtx_size; i++) { 719 mtx_tab[i] = new TTFMtxEntry(); 720 } 721 for (int i = 0; i < nhmtx; i++) { 722 mtx_tab[i].wx = in.readTTFUShort(); 723 mtx_tab[i].lsb = in.readTTFShort(); 724 728 } 729 730 if (nhmtx < mtx_size) { 731 int lastWidth = mtx_tab[nhmtx - 1].wx; 733 for (int i = nhmtx; i < mtx_size; i++) { 734 mtx_tab[i].wx = lastWidth; 735 mtx_tab[i].lsb = in.readTTFShort(); 736 } 737 } 738 } 739 740 741 745 private final void readPostscript(FontFileReader in) throws IOException { 746 String [] ps_glyphs_buf; 747 int i, k, l; 748 749 seek_tab(in, "post", 0); 750 post_format = in.readTTFLong(); 751 italicAngle = in.readTTFULong(); 752 underlinePosition = in.readTTFShort(); 753 underlineThickness = in.readTTFShort(); 754 isFixedPitch = in.readTTFULong(); 755 756 in.skip(4 * 4); 757 758 switch (post_format) { 760 case 0x00010000: 761 for (i = 0; i < Glyphs.mac_glyph_names.length; i++) { 763 mtx_tab[i].name = Glyphs.mac_glyph_names[i]; 764 } 765 break; 766 case 0x00020000: 767 int numGlyphStrings = 0; 769 l = in.readTTFUShort(); for (i = 0; i < l; i++) { mtx_tab[i].index = in.readTTFUShort(); 773 776 if (mtx_tab[i].index > 257) 777 numGlyphStrings++; 778 779 } 781 ps_glyphs_buf = new String [numGlyphStrings]; 783 for (i = 0; i < ps_glyphs_buf.length; i++) { 787 ps_glyphs_buf[i] = in.readTTFString(in.readTTFUByte()); 788 } 789 790 for (i = 0; i < l; i++) { 791 if (mtx_tab[i].index < NMACGLYPHS) { 792 mtx_tab[i].name = 793 Glyphs.mac_glyph_names[mtx_tab[i].index]; 794 } else { 795 if (!mtx_tab[i].isIndexReserved()) { 796 k = mtx_tab[i].index - NMACGLYPHS; 797 801 mtx_tab[i].name = ps_glyphs_buf[k]; 802 } 803 } 804 } 805 806 break; 807 case 0x00030000: 808 System.out.println("Postscript format 3"); 810 break; 811 default: 812 System.out.println("Unknown Postscript format : " + post_format); 813 } 814 } 815 816 817 820 private final void readOS2(FontFileReader in) throws IOException { 821 if (dirTabs.get("OS/2") != null) { 823 seek_tab(in, "OS/2", 2 * 4); 824 int fsType = in.readTTFUShort(); 825 if (fsType == 2) { 826 is_embeddable = false; 827 } else { 828 is_embeddable = true; 829 } 830 } else { 831 is_embeddable = true; 832 } 833 } 834 835 838 protected final void readIndexToLocation(FontFileReader in) 839 throws IOException { 840 seek_tab(in, "loca", 0); 841 for (int i = 0; i < nglyphs; i++) { 842 mtx_tab[i].offset = (loca_format == 1 ? in.readTTFULong() 843 : (in.readTTFUShort() << 1)); 844 } 845 lastLoca = (loca_format == 1 ? in.readTTFULong() 846 : (in.readTTFUShort() << 1)); 847 } 848 849 852 private final void readGlyf(FontFileReader in) throws IOException { 853 TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("glyf"); 854 for (int i = 0; i < (nglyphs - 1); i++) { 855 if (mtx_tab[i].offset != mtx_tab[i + 1].offset) { 856 in.seek_set(dirTab.offset + mtx_tab[i].offset); 857 in.skip(2); 858 mtx_tab[i].bbox[0] = in.readTTFShort(); 859 mtx_tab[i].bbox[1] = in.readTTFShort(); 860 mtx_tab[i].bbox[2] = in.readTTFShort(); 861 mtx_tab[i].bbox[3] = in.readTTFShort(); 862 } else { 863 mtx_tab[i].bbox[0] = mtx_tab[0].bbox[0]; 864 mtx_tab[i].bbox[1] = mtx_tab[0].bbox[1]; 865 mtx_tab[i].bbox[2] = mtx_tab[0].bbox[2]; 866 mtx_tab[i].bbox[3] = mtx_tab[0].bbox[3]; 867 } 868 } 869 870 871 long n = ((TTFDirTabEntry)dirTabs.get("glyf")).offset; 872 for (int i = 0; i < nglyphs; i++) { 873 if ((i + 1) >= mtx_tab.length 874 || mtx_tab[i].offset != mtx_tab[i + 1].offset) { 875 in.seek_set(n + mtx_tab[i].offset); 876 in.skip(2); 877 mtx_tab[i].bbox[0] = in.readTTFShort(); 878 mtx_tab[i].bbox[1] = in.readTTFShort(); 879 mtx_tab[i].bbox[2] = in.readTTFShort(); 880 mtx_tab[i].bbox[3] = in.readTTFShort(); 881 } else { 882 mtx_tab[i].bbox[0] = mtx_tab[0].bbox[0]; 883 mtx_tab[i].bbox[1] = mtx_tab[0].bbox[0]; 884 mtx_tab[i].bbox[2] = mtx_tab[0].bbox[0]; 885 mtx_tab[i].bbox[3] = mtx_tab[0].bbox[0]; 886 } 887 } 889 } 890 891 894 private final void readName(FontFileReader in) throws IOException { 895 seek_tab(in, "name", 2); 896 int i = in.getCurrentPos(); 897 int n = in.readTTFUShort(); 898 int j = in.readTTFUShort() + i - 2; 899 i += 2 * 2; 900 901 while (n-- > 0) { 902 in.seek_set(i); 904 int platform_id = in.readTTFUShort(); 905 int encoding_id = in.readTTFUShort(); 906 int language_id = in.readTTFUShort(); 907 908 int k = in.readTTFUShort(); 909 int l = in.readTTFUShort(); 910 911 if (((platform_id == 1 || platform_id == 3) && (encoding_id == 0 || encoding_id == 1)) 912 && (k == 1 || k == 2 || k == 0 || k == 4 || k == 6)) { 913 in.seek_set(j + in.readTTFUShort()); 915 String txt = in.readTTFString(l); 916 switch (k) { 919 case 0: 920 notice = txt; 921 break; 922 case 1: 923 familyName = txt; 924 break; 925 case 2: 926 subFamilyName = txt; 927 break; 928 case 4: 929 fullName = txt; 930 break; 931 case 6: 932 fontName = txt; 933 break; 934 } 935 if (!notice.equals("") &&!fullName.equals("") 936 &&!fontName.equals("") &&!familyName.equals("") 937 &&!subFamilyName.equals("")) { 938 break; 939 } 940 } 941 i += 6 * 2; 942 } 943 } 944 945 948 private final void readPCLT(FontFileReader in) throws IOException { 949 TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("PCLT"); 950 if (dirTab != null) { 951 in.seek_set(dirTab.offset + 4 + 4 + 2); 952 xHeight = in.readTTFUShort(); 953 in.skip(2 * 2); 954 capHeight = in.readTTFUShort(); 955 in.skip(2 + 16 + 8 + 6 + 1 + 1); 956 957 int serifStyle = in.readTTFUByte(); 958 serifStyle = serifStyle >> 6; 959 serifStyle = serifStyle & 3; 960 if (serifStyle == 1) { 961 hasSerifs = false; 962 } else { 963 hasSerifs = true; 964 } 965 966 } else { 967 for (int i = 0; i < mtx_tab.length; i++) { 973 if ("H".equals(mtx_tab[i].name)) { 974 capHeight = mtx_tab[i].bbox[3] - mtx_tab[i].bbox[1]; 975 } 976 } 977 } 978 } 979 980 984 private final void readKerning(FontFileReader in) throws IOException { 985 kerningTab = new HashMap (); 987 ansiKerningTab = new HashMap (); 988 TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("kern"); 989 if (dirTab != null) { 990 seek_tab(in, "kern", 2); 991 for (int n = in.readTTFUShort(); n > 0; n--) { 992 in.skip(2 * 2); 993 int k = in.readTTFUShort(); 994 if (!((k & 1) != 0) || (k & 2) != 0 || (k & 4) != 0) { 995 return; 996 } 997 if ((k >> 8) != 0) { 998 continue; 999 } 1000 1001 k = in.readTTFUShort(); 1002 in.skip(3 * 2); 1003 while (k-- > 0) { 1004 int i = in.readTTFUShort(); 1005 int j = in.readTTFUShort(); 1006 int kpx = in.readTTFShort(); 1007 if (kpx != 0) { 1008 Integer iObj = new Integer (i); 1010 HashMap adjTab = (HashMap )kerningTab.get(iObj); 1011 if (adjTab == null) { 1012 adjTab = new HashMap (); 1013 } 1014 adjTab.put(new Integer (j), 1015 new Integer ((int)get_ttf_funit(kpx))); 1016 kerningTab.put(iObj, adjTab); 1017 } 1018 } 1019 } 1020 1022 1024 for (Iterator ae = kerningTab.keySet().iterator(); ae.hasNext(); ) { 1025 Integer cidKey = (Integer )ae.next(); 1026 HashMap akpx = new HashMap (); 1027 HashMap ckpx = (HashMap )kerningTab.get(cidKey); 1028 1029 for (Iterator aee = ckpx.keySet().iterator(); aee.hasNext(); ) { 1030 Integer cidKey2 = (Integer )aee.next(); 1031 Integer kern = (Integer )ckpx.get(cidKey2); 1032 1033 ArrayList unicodeIndex = mtx_tab[cidKey2.intValue()].unicodeIndex; 1034 for (int i = 0; i < unicodeIndex.size(); i++) { 1035 Integer unicodeKey = (Integer )unicodeIndex.get(i); 1036 Integer [] ansiKeys = 1037 unicodeToWinAnsi(unicodeKey.intValue()); 1038 for (int u = 0; u < ansiKeys.length; u++) { 1039 akpx.put(ansiKeys[u], kern); 1040 } 1041 } 1042 } 1043 1044 if (akpx.size() > 0) { 1045 ArrayList unicodeIndex = mtx_tab[cidKey.intValue()].unicodeIndex; 1046 for (int i = 0; i< unicodeIndex.size(); i++) { 1047 Integer unicodeKey = (Integer )unicodeIndex.get(i); 1048 Integer [] ansiKeys = 1049 unicodeToWinAnsi(unicodeKey.intValue()); 1050 for (int u = 0; u < ansiKeys.length; u++) { 1051 ansiKerningTab.put(ansiKeys[u], akpx); 1052 } 1053 } 1054 } 1055 } 1056 } 1057 } 1058 1059 1062 public ArrayList getCMaps() { 1063 return cmaps; 1064 } 1065 1066 1074 protected final boolean checkTTC(FontFileReader in, String name, 1075 boolean verbose) throws IOException { 1076 String tag = in.readTTFString(4); 1077 1078 if ("ttcf".equals(tag)) { 1079 in.skip(4); 1081 1082 int numDirectories = (int)in.readTTFULong(); 1084 long[] dirOffsets = new long[numDirectories]; 1086 for (int i = 0; i < numDirectories; i++) { 1087 dirOffsets[i] = in.readTTFULong(); 1088 } 1089 1090 if (verbose) { 1091 System.out.println("This is a TrueType collection file with " 1092 + numDirectories + " fonts"); 1093 System.out.println("Containing the following fonts: "); 1094 } 1095 boolean found = false; 1098 1099 long dirTabOffset = 0; 1102 for (int i = 0; (i < numDirectories); i++) { 1103 in.seek_set(dirOffsets[i]); 1104 readDirTabs(in); 1105 1106 readName(in); 1107 1108 if (fullName.equals(name)) { 1109 found = true; 1110 dirTabOffset = dirOffsets[i]; 1111 if (verbose) { 1112 System.out.println("* " + fullName); 1113 } 1114 } else { 1115 if (verbose) { 1116 System.out.println(fullName); 1117 } 1118 } 1119 1120 notice = ""; 1122 fullName = ""; 1123 familyName = ""; 1124 fontName = ""; 1125 subFamilyName = ""; 1126 } 1127 1128 in.seek_set(dirTabOffset); 1129 return found; 1130 } else { 1131 in.seek_set(0); 1132 return true; 1133 } 1134 } 1135 1136 1140 private Integer [] unicodeToWinAnsi(int unicode) { 1141 ArrayList ret = new ArrayList (); 1142 for (int i = 32; i < Glyphs.winAnsiEncoding.length; i++) { 1143 if (unicode == Glyphs.winAnsiEncoding[i]) { 1144 ret.add(new Integer (i)); 1145 } 1146 } 1147 Integer [] itg = new Integer [ret.size()]; 1148 ret.toArray(itg); 1149 return itg; 1150 } 1151 1152} 1153 1154 1155 1158class UnicodeMapping { 1159 int uIdx; 1160 int gIdx; 1161 UnicodeMapping(int gIdx, int uIdx) { 1162 this.uIdx = uIdx; 1163 this.gIdx = gIdx; 1164 } 1165 1166} 1167 | Popular Tags |