private int readInt(RandomAccessFileOrArray stream) throws IOException { if (isBigEndian) { return stream.readInt(); } else { return stream.readIntLE(); } }
/** * Reads the kerning information from the 'kern' table. * * @throws IOException the font file could not be read */ void readKerning() throws IOException { int table_location[]; table_location = (int[]) positionTables.get("kern"); if (table_location == null) return; rf.seek(table_location[0] + 2); int nTables = rf.readUnsignedShort(); int checkpoint = table_location[0] + 4; int length = 0; for (int k = 0; k < nTables; ++k) { checkpoint += length; rf.seek(checkpoint); rf.skipBytes(2); length = rf.readUnsignedShort(); int coverage = rf.readUnsignedShort(); if ((coverage & 0xfff7) == 0x0001) { int nPairs = rf.readUnsignedShort(); rf.skipBytes(6); for (int j = 0; j < nPairs; ++j) { int pair = rf.readInt(); int value = ((int) rf.readShort() * 1000) / head.unitsPerEm; kerning.put(pair, value); } } } }
/** * Reads the several maps from the table 'cmap'. The maps of interest are 1.0 for symbolic fonts * and 3.1 for all others. A symbolic font is defined as having the map 3.0. * * @throws DocumentException the font is invalid * @throws IOException the font file could not be read */ public void readCMaps() throws DocumentException, IOException { int table_location[]; table_location = (int[]) positionTables.get("cmap"); if (table_location == null) throw new DocumentException("Table 'cmap' does not exist in " + fileName + style); rf.seek(table_location[0]); rf.skipBytes(2); int num_tables = rf.readUnsignedShort(); fontSpecific = false; int map10 = 0; int map31 = 0; int map30 = 0; for (int k = 0; k < num_tables; ++k) { int platId = rf.readUnsignedShort(); int platSpecId = rf.readUnsignedShort(); int offset = rf.readInt(); if (platId == 3 && platSpecId == 0) { fontSpecific = true; map30 = offset; } else if (platId == 3 && platSpecId == 1) { map31 = offset; } if (platId == 1 && platSpecId == 0) { map10 = offset; } } if (map10 > 0) { rf.seek(table_location[0] + map10); int format = rf.readUnsignedShort(); switch (format) { case 0: cmap10 = readFormat0(); break; case 4: cmap10 = readFormat4(); break; case 6: cmap10 = readFormat6(); break; } } if (map31 > 0) { rf.seek(table_location[0] + map31); int format = rf.readUnsignedShort(); if (format == 4) { cmap31 = readFormat4(); } } if (map30 > 0) { rf.seek(table_location[0] + map30); int format = rf.readUnsignedShort(); if (format == 4) { cmap10 = readFormat4(); } } }
private void processPost() throws DocumentException, IOException { int[] tableLocation = getTableLocation("post"); if (tableLocation == null) { italicAngle = -Math.atan2(hhea.caretSlopeRun, hhea.caretSlopeRise) * 180 / Math.PI; return; } rf.seek(tableLocation[0] + 4); short mantissa = rf.readShort(); int fraction = rf.readUnsignedShort(); italicAngle = (double) mantissa + (double) fraction / 16384.0; underlinePosition = (double) rf.readShort() / head.unitsPerEm; underlineThickness = (double) rf.readShort() / head.unitsPerEm; isFixedPitch = rf.readInt() != 0; }
private int[] getGlyphDataPosition(int glyphIndex) throws IOException { int[] glyphDataPosition = new int[2]; int[] tableLocation = (int[]) positionTables.get("loca"); int offset = tableLocation[0] + head.locaBytesPerEntry * glyphIndex; rf.seek(offset); if (head.locaBytesPerEntry == 4) { glyphDataPosition[0] = rf.readInt(); glyphDataPosition[1] = rf.readInt() - glyphDataPosition[0]; } else { glyphDataPosition[0] = rf.readUnsignedShort() * 2; glyphDataPosition[1] = rf.readUnsignedShort() * 2 - glyphDataPosition[0]; } return glyphDataPosition; }
private void fillOS() throws DocumentException, IOException { int[] tableLocation = getTableLocation("OS/2"); rf.seek(tableLocation[0]); int version = rf.readUnsignedShort(); os_2.xAvgCharWidth = rf.readShort(); os_2.usWeightClass = rf.readUnsignedShort(); os_2.usWidthClass = rf.readUnsignedShort(); os_2.fsType = rf.readShort(); os_2.ySubscriptXSize = rf.readShort(); os_2.ySubscriptYSize = rf.readShort(); os_2.ySubscriptXOffset = rf.readShort(); os_2.ySubscriptYOffset = rf.readShort(); os_2.ySuperscriptXSize = rf.readShort(); os_2.ySuperscriptYSize = rf.readShort(); os_2.ySuperscriptXOffset = rf.readShort(); os_2.ySuperscriptYOffset = rf.readShort(); os_2.yStrikeoutSize = rf.readShort(); os_2.yStrikeoutPosition = rf.readShort(); os_2.sFamilyClass = rf.readShort(); rf.readFully(os_2.panose); rf.skipBytes(16); rf.readFully(os_2.achVendID); os_2.fsSelection = rf.readUnsignedShort(); os_2.usFirstCharIndex = rf.readUnsignedShort(); os_2.usLastCharIndex = rf.readUnsignedShort(); os_2.sTypoAscender = rf.readShort(); os_2.sTypoDescender = rf.readShort(); if (os_2.sTypoDescender > 0) os_2.sTypoDescender = (short) (-os_2.sTypoDescender); os_2.sTypoLineGap = rf.readShort(); os_2.usWinAscent = rf.readUnsignedShort(); os_2.usWinDescent = rf.readUnsignedShort(); os_2.ulCodePageRange1 = 0; os_2.ulCodePageRange2 = 0; if (version > 0) { os_2.ulCodePageRange1 = rf.readInt(); os_2.ulCodePageRange2 = rf.readInt(); } if (version > 1) { rf.skipBytes(2); os_2.sCapHeight = rf.readShort(); } else os_2.sCapHeight = (int) (0.7 * head.unitsPerEm); }
private void readBbox() throws DocumentException, IOException { int tableLocation[]; tableLocation = (int[]) positionTables.get("head"); if (tableLocation == null) throw new DocumentException("Table 'head' does not exist in " + fileName + style); rf.seek(tableLocation[0] + HEAD_LOCA_FORMAT_OFFSET); boolean locaShortTable = (rf.readUnsignedShort() == 0); tableLocation = (int[]) positionTables.get("loca"); if (tableLocation == null) return; rf.seek(tableLocation[0]); int locaTable[]; if (locaShortTable) { int entries = tableLocation[1] / 2; locaTable = new int[entries]; for (int k = 0; k < entries; ++k) locaTable[k] = rf.readUnsignedShort() * 2; } else { int entries = tableLocation[1] / 4; locaTable = new int[entries]; for (int k = 0; k < entries; ++k) locaTable[k] = rf.readInt(); } tableLocation = (int[]) positionTables.get("glyf"); if (tableLocation == null) throw new DocumentException("Table 'glyf' does not exist in " + fileName + style); int tableGlyphOffset = tableLocation[0]; bboxes = new int[locaTable.length - 1][]; for (int glyph = 0; glyph < locaTable.length - 1; ++glyph) { int start = locaTable[glyph]; if (start != locaTable[glyph + 1]) { rf.seek(tableGlyphOffset + start + 2); bboxes[glyph] = new int[] { (rf.readShort() * 1000) / head.unitsPerEm, (rf.readShort() * 1000) / head.unitsPerEm, (rf.readShort() * 1000) / head.unitsPerEm, (rf.readShort() * 1000) / head.unitsPerEm }; } } }
/** * Reads the font data. * * @param ttfAfm the font as a <CODE>byte</CODE> array, possibly <CODE>null</CODE> * @throws DocumentException the font is invalid * @throws IOException the font file could not be read */ void process() throws DocumentException, IOException { positionTables = new HashMap<String, int[]>(); metadataTables = new HashMap<String, byte[]>(); try { rf = new RandomAccessFileOrArray(fileName); if (ttcIndex.length() > 0) { int dirIdx = Integer.parseInt(ttcIndex); if (dirIdx < 0) throw new DocumentException("The font index for " + fileName + " must be positive."); String mainTag = readStandardString(4); if (!mainTag.equals("ttcf")) throw new DocumentException(fileName + " is not a valid TTC file."); rf.skipBytes(4); int dirCount = rf.readInt(); if (dirIdx >= dirCount) throw new DocumentException( "The font index for " + fileName + " must be between 0 and " + (dirCount - 1) + ". It was " + dirIdx + "."); rf.skipBytes(dirIdx * 4); directoryOffset = rf.readInt(); } rf.seek(directoryOffset); rf.readFully(directoryRawData); int ttId = Util.getInt(directoryRawData, 0); if (ttId != 0x00010000 && ttId != 0x4F54544F) throw new DocumentException(fileName + " is not a valid TTF or OTF file."); int num_tables = Util.getUnsignedShort(directoryRawData, 4); for (int k = 0; k < num_tables; ++k) { byte[] rawData = new byte[16]; rf.readFully(rawData); String tag = getStandardString(rawData, 0, 4); int table_location[] = new int[2]; table_location[0] = Util.getInt(rawData, 8); table_location[1] = Util.getInt(rawData, 12); positionTables.put(tag, table_location); metadataTables.put(tag, rawData); } fontName = getBaseFont(); fullName = getNames(4); // full name familyName = getNames(1); // family name notice = getNames(0); version = getNames(5); if (!justNames) { fillTables(); readGlyphWidths(); readCMaps(); readKerning(); readBbox(); GlyphWidths = null; } } finally { if (rf != null) { rf.close(); if (!embedded) rf = null; } } }