/** * Fix a broken font name table for a TrueType font. Some fonts do not have Microsoft-specific * name information, but Java won't work without it (grrr.). This method takes a font and adds the * Microsoft data into it. * * @param ttf the font * @param name the font's name table * @return true if the table was fixed, or false if it was left as is */ private boolean fixNameTable(TrueTypeFont ttf, NameTable name) { // if we didn't find the table, or there was an exception, // just create a new one if (name == null) { name = (NameTable) TrueTypeTable.createTable(ttf, "name"); ttf.addTable("name", name); } // first, figure out some info about the font String fName = this.getBaseFont(); String style = "Regular"; if (fName.indexOf("Italic") > -1 || fName.indexOf("italic") > -1) { style = "Italic"; } else if (fName.indexOf("Bold") > -1 || fName.indexOf("bold") > -1) { style = "Bold"; } if (fName.indexOf('-') > -1) { fName = fName.substring(0, fName.indexOf('-')); } short platID = NameTable.PLATFORMID_MICROSOFT; short encID = 1; short langID = 1033; short[] nameIDs = { NameTable.NAMEID_COPYRIGHT, NameTable.NAMEID_FAMILY, NameTable.NAMEID_SUBFAMILY, NameTable.NAMEID_SUBFAMILY_UNIQUE, NameTable.NAMEID_FULL_NAME, NameTable.NAMEID_VERSION, NameTable.NAMEID_POSTSCRIPT_NAME, NameTable.NAMEID_TRADEMARK }; String[] defaultValues = { "No copyright", fName, style, fName + " " + style, fName + " " + style, "1.0 (Fake)", fName, "No Trademark" }; boolean changed = false; for (int i = 0; i < nameIDs.length; i++) { if (name.getRecord(platID, encID, langID, nameIDs[i]) == null) { name.addRecord(platID, encID, langID, nameIDs[i], defaultValues[i]); changed = true; } } return changed; }
/** * Fix the CMap table. This can be necessary if characters are mapped to control characters (0x9, * 0xa, 0xd) Java will not render them, even though they are valid. * * <p>Also, Java tends to not like it when there is only a Format 0 CMap, which happens frequently * when included Format 4 CMaps are broken. Since PDF prefers the Format 0 map, while Java prefers * the Format 4 map, it is generally necessary to re-write the Format 0 map as a Format 4 map to * make most PDFs work. * * @param ttf the font * @param cmap the CMap table * @return true if the font was changed, or false if it was left as-is */ private boolean fixCMapTable(TrueTypeFont ttf, CmapTable cmap) { CMapFormat4 fourMap = null; CMapFormat0 zeroMap = null; for (int i = 0; i < mapIDs.length; i += 2) { CMap map = this.cmapTable.getCMap(mapIDs[i], mapIDs[i + 1]); if (map != null) { if (fourMap == null && map instanceof CMapFormat4) { fourMap = (CMapFormat4) map; } else if (zeroMap == null && map instanceof CMapFormat0) { zeroMap = (CMapFormat0) map; } } } // if there were no maps, we could have problems. Just try creating // an identity map if (zeroMap == null && fourMap == null) { fourMap = (CMapFormat4) CMap.createMap((short) 4, (short) 0); fourMap.addSegment((short) getFirstChar(), (short) getLastChar(), (short) 0); } // create our map based on the type 0 map, since PDF seems // to prefer a type 0 map (Java prefers a unicode map) if (zeroMap != null) { fourMap = (CMapFormat4) CMap.createMap((short) 4, (short) 0); // add the mappings from 0 to null and 1 to notdef fourMap.addSegment((short) 0, (short) 1, (short) 0); for (int i = getFirstChar(); i <= getLastChar(); i++) { short value = (short) (zeroMap.map((byte) i) & 0xff); if (value != 0) { fourMap.addSegment((short) i, (short) i, (short) (value - i)); } } } // now that we have a type four map, remap control characters for (int i = 0; i < controlChars.length; i++) { short idx = (short) (0xf000 | controlChars[i]); short value = (short) fourMap.map(controlChars[i]); fourMap.addSegment(idx, idx, (short) (value - idx)); } // create a whole new table with just our map cmap = (CmapTable) TrueTypeTable.createTable(ttf, "cmap"); cmap.addCMap((short) 3, (short) 1, fourMap); // replace the table in the font ttf.addTable("cmap", cmap); // change the stored table this.cmapTable = cmap; return true; }
/** * Set the font * * @param f the font to use */ protected void setFont(Font f) { this.f = f; // if it's an OpenType font, parse the relevant tables to get // glyph name to code mappings if (f instanceof OpenType) { OpenType ot = (OpenType) f; byte[] cmapData = ot.getFontTable(OpenType.TAG_CMAP); byte[] postData = ot.getFontTable(OpenType.TAG_POST); TrueTypeFont ttf = new TrueTypeFont(0x10000); this.cmapTable = (CmapTable) TrueTypeTable.createTable(ttf, "cmap", ByteBuffer.wrap(cmapData)); ttf.addTable("cmap", this.cmapTable); this.postTable = (PostTable) TrueTypeTable.createTable(ttf, "post", ByteBuffer.wrap(postData)); ttf.addTable("post", this.postTable); } }