private double readDouble(RandomAccessFileOrArray stream) throws IOException { if (isBigEndian) { return stream.readDouble(); } else { return stream.readDoubleLE(); } }
private long readLong(RandomAccessFileOrArray stream) throws IOException { if (isBigEndian) { return stream.readLong(); } else { return stream.readLongLE(); } }
/** * 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); } } } }
private float readFloat(RandomAccessFileOrArray stream) throws IOException { if (isBigEndian) { return stream.readFloat(); } else { return stream.readFloatLE(); } }
private int readUnsignedShort(RandomAccessFileOrArray stream) throws IOException { if (isBigEndian) { return stream.readUnsignedShort(); } else { return stream.readUnsignedShortLE(); } }
private static long readUnsignedInt(RandomAccessFileOrArray stream, boolean isBigEndian) throws IOException { if (isBigEndian) { return stream.readUnsignedInt(); } else { return stream.readUnsignedIntLE(); } }
/** * The information in the maps of the table 'cmap' is coded in several formats. Format 0 is the * Apple standard character to glyph index mapping table. * * @return a <CODE>HashMap</CODE> representing this map * @throws IOException the font file could not be read */ HashMap<Integer, int[]> readFormat0() throws IOException { HashMap<Integer, int[]> h = new HashMap<Integer, int[]>(); rf.skipBytes(4); for (int k = 0; k < 256; ++k) { int r[] = new int[2]; r[0] = rf.readUnsignedByte(); r[1] = getGlyphWidth(r[0]); h.put(k, r); } return h; }
/** * Reads the glyphs widths. The widths are extracted from the table 'hmtx'. The glyphs are * normalized to 1000 units. * * @throws DocumentException the font is invalid * @throws IOException the font file could not be read */ protected void readGlyphWidths() throws DocumentException, IOException { int table_location[]; table_location = (int[]) positionTables.get("hmtx"); if (table_location == null) throw new DocumentException("Table 'hmtx' does not exist in " + fileName + style); rf.seek(table_location[0]); GlyphWidths = new int[hhea.numberOfHMetrics]; for (int k = 0; k < hhea.numberOfHMetrics; ++k) { GlyphWidths[k] = (rf.readUnsignedShort() * 1000) / head.unitsPerEm; rf.readUnsignedShort(); } }
public byte[] getGlyphData(int glyph) throws IOException { int dataOffsetRelativeToGlyfTable, dataLength; int[] glyphDataPosition = getGlyphDataPosition(glyph); dataOffsetRelativeToGlyfTable = glyphDataPosition[0]; dataLength = glyphDataPosition[1]; int[] glyphLocation = (int[]) positionTables.get("glyf"); int dataOffset = dataOffsetRelativeToGlyfTable + glyphLocation[0]; byte[] result = new byte[dataLength]; rf.seek(dataOffset); rf.readFully(result); return result; }
/** * The information in the maps of the table 'cmap' is coded in several formats. Format 6 is a * trimmed table mapping. It is similar to format 0 but can have less than 256 entries. * * @return a <CODE>HashMap</CODE> representing this map * @throws IOException the font file could not be read */ HashMap<Integer, int[]> readFormat6() throws IOException { HashMap<Integer, int[]> h = new HashMap<Integer, int[]>(); rf.skipBytes(4); int start_code = rf.readUnsignedShort(); int code_count = rf.readUnsignedShort(); for (int k = 0; k < code_count; ++k) { int r[] = new int[2]; r[0] = rf.readUnsignedShort(); r[1] = getGlyphWidth(r[0]); h.put(k + start_code, r); } return h; }
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; }
public static void populateDescription(String path, BaseFont font, FontDescription descr) throws IOException, NoSuchFieldException, IllegalAccessException, DocumentException { RandomAccessFileOrArray rf = null; try { rf = new RandomAccessFileOrArray(getTTCName(path)); rf = populateDescription0(path, font, descr, rf); } finally { if (rf != null) { try { rf.close(); } catch (IOException e) { // ignore } } } }
/** * Reads a Unicode <CODE>String</CODE> from the font file. Each character is represented by two * bytes. * * @param length the length of bytes to read. The <CODE>String</CODE> will have <CODE>length * </CODE>/2 characters * @return the <CODE>String</CODE> read * @throws IOException the font file could not be read */ protected String readUnicodeString(int length) throws IOException { StringBuffer buf = new StringBuffer(); length /= 2; for (int k = 0; k < length; ++k) { buf.append(rf.readChar()); } return buf.toString(); }
/** * The information in the maps of the table 'cmap' is coded in several formats. Format 4 is the * Microsoft standard character to glyph index mapping table. * * @return a <CODE>HashMap</CODE> representing this map * @throws IOException the font file could not be read */ HashMap<Integer, int[]> readFormat4() throws IOException { HashMap<Integer, int[]> h = new HashMap<Integer, int[]>(); int table_lenght = rf.readUnsignedShort(); rf.skipBytes(2); int segCount = rf.readUnsignedShort() / 2; rf.skipBytes(6); int endCount[] = new int[segCount]; for (int k = 0; k < segCount; ++k) { endCount[k] = rf.readUnsignedShort(); } rf.skipBytes(2); int startCount[] = new int[segCount]; for (int k = 0; k < segCount; ++k) { startCount[k] = rf.readUnsignedShort(); } int idDelta[] = new int[segCount]; for (int k = 0; k < segCount; ++k) { idDelta[k] = rf.readUnsignedShort(); } int idRO[] = new int[segCount]; for (int k = 0; k < segCount; ++k) { idRO[k] = rf.readUnsignedShort(); } int glyphId[] = new int[table_lenght / 2 - 8 - segCount * 4]; for (int k = 0; k < glyphId.length; ++k) { glyphId[k] = rf.readUnsignedShort(); } for (int k = 0; k < segCount; ++k) { int glyph; for (int j = startCount[k]; j <= endCount[k] && j != 0xFFFF; ++j) { if (idRO[k] == 0) { glyph = (j + idDelta[k]) & 0xFFFF; } else { int idx = k + idRO[k] / 2 - segCount + j - startCount[k]; if (idx >= glyphId.length) continue; glyph = (glyphId[idx] + idDelta[k]) & 0xFFFF; } int r[] = new int[2]; r[0] = glyph; r[1] = getGlyphWidth(r[0]); h.put((fontSpecific ? ((j & 0xff00) == 0xf000 ? j & 0xff : j) : j), r); } } return h; }
/** * Gets the Postscript font name. * * @throws DocumentException the font is invalid * @throws IOException the font file could not be read * @return the Postscript font name */ String getBaseFont() throws DocumentException, IOException { int table_location[]; table_location = (int[]) positionTables.get("name"); if (table_location == null) throw new DocumentException("Table 'name' does not exist in " + fileName + style); rf.seek(table_location[0] + 2); int numRecords = rf.readUnsignedShort(); int startOfStorage = rf.readUnsignedShort(); for (int k = 0; k < numRecords; ++k) { int platformID = rf.readUnsignedShort(); int nameID = rf.readUnsignedShort(); int length = rf.readUnsignedShort(); int offset = rf.readUnsignedShort(); if (nameID == 6) { rf.seek(table_location[0] + startOfStorage + offset); if (platformID != 0 && platformID != 3) { String name = readStandardString(length); name = name.replace(' ', '_'); return name.replace((char) 0, '_'); } } } File file = new File(fileName); return file.getName().replace(' ', '_'); }
public TIFFDirectory(RandomAccessFileOrArray stream, int directory) throws IOException { long global_save_offset = stream.getFilePointer(); long ifd_offset; stream.seek(0L); int endian = stream.readUnsignedShort(); if (!isValidEndianTag(endian)) { throw new IllegalArgumentException("Bad endianness tag (not 0x4949 or 0x4d4d)."); } isBigEndian = (endian == 0x4d4d); int magic = readUnsignedShort(stream); if (magic != 42) { throw new IllegalArgumentException("Bad magic number, should be 42."); } ifd_offset = readUnsignedInt(stream); for (int i = 0; i < directory; i++) { if (ifd_offset == 0L) { throw new IllegalArgumentException("Directory number too large."); } stream.seek(ifd_offset); int entries = readUnsignedShort(stream); stream.skip(12 * entries); ifd_offset = readUnsignedInt(stream); } stream.seek(ifd_offset); initialize(stream); stream.seek(global_save_offset); }
public TIFFDirectory(RandomAccessFileOrArray stream, long ifd_offset, int directory) throws IOException { long global_save_offset = stream.getFilePointer(); stream.seek(0L); int endian = stream.readUnsignedShort(); if (!isValidEndianTag(endian)) { throw new IllegalArgumentException("Bad endianness tag (not 0x4949 or 0x4d4d)."); } isBigEndian = (endian == 0x4d4d); stream.seek(ifd_offset); int dirNum = 0; while (dirNum < directory) { int numEntries = readUnsignedShort(stream); stream.seek(ifd_offset + 12 * numEntries); ifd_offset = readUnsignedInt(stream); stream.seek(ifd_offset); dirNum++; } initialize(stream); stream.seek(global_save_offset); }
public static int getNumDirectories(RandomAccessFileOrArray stream) throws IOException { long pointer = stream.getFilePointer(); stream.seek(0L); int endian = stream.readUnsignedShort(); if (!isValidEndianTag(endian)) { throw new IllegalArgumentException("Bad endianness tag (not 0x4949 or 0x4d4d)."); } boolean isBigEndian = (endian == 0x4d4d); int magic = readUnsignedShort(stream, isBigEndian); if (magic != 42) { throw new IllegalArgumentException("Bad magic number, should be 42."); } stream.seek(4L); long offset = readUnsignedInt(stream, isBigEndian); int numDirectories = 0; while (offset != 0L) { ++numDirectories; try { stream.seek(offset); int entries = readUnsignedShort(stream, isBigEndian); stream.skip(12 * entries); offset = readUnsignedInt(stream, isBigEndian); } catch (EOFException eof) { break; } } stream.seek(pointer); return numDirectories; }
private List<byte[]> readTable(String name) throws DocumentException, IOException { int[] tableLocation = getTableLocation(name); if (tableLocation == null) { return null; } rf.seek(tableLocation[0]); byte[] data = readData(getEvenLength(tableLocation[1])); return split(data); }
/** * Reads a <CODE>String</CODE> from the font file as bytes using the Cp1252 encoding. * * @param length the length of bytes to read * @return the <CODE>String</CODE> read * @throws IOException the font file could not be read */ protected String readStandardString(int length) throws IOException { byte buf[] = new byte[length]; rf.readFully(buf); try { return new String(buf, WINANSI); } catch (Exception e) { throw new ExceptionConverter(e); } }
private void fillHead() throws DocumentException, IOException { int tableLocation[] = getTableLocation("head"); rf.seek(tableLocation[0] + 16); head.flags = rf.readUnsignedShort(); head.unitsPerEm = rf.readUnsignedShort(); rf.skipBytes(16); head.xMin = rf.readShort(); head.yMin = rf.readShort(); head.xMax = rf.readShort(); head.yMax = rf.readShort(); head.macStyle = rf.readUnsignedShort(); rf.skip(4); int indexToLocFormat = rf.readUnsignedShort(); head.locaBytesPerEntry = indexToLocFormat == 0 ? 2 : 4; }
/** @see com.lowagie.toolbox.AbstractTool#execute() */ public void execute() { try { if (getValue("odd") == null) throw new InstantiationException("You need to choose a sourcefile for the odd pages"); File odd_file = (File) getValue("odd"); if (getValue("even") == null) throw new InstantiationException("You need to choose a sourcefile for the even pages"); File even_file = (File) getValue("even"); if (getValue("destfile") == null) throw new InstantiationException("You need to choose a destination file"); File pdf_file = (File) getValue("destfile"); RandomAccessFileOrArray odd = new RandomAccessFileOrArray(odd_file.getAbsolutePath()); RandomAccessFileOrArray even = new RandomAccessFileOrArray(even_file.getAbsolutePath()); Image img = TiffImage.getTiffImage(odd, 1); Document document = new Document(new Rectangle(img.getScaledWidth(), img.getScaledHeight())); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdf_file)); document.open(); PdfContentByte cb = writer.getDirectContent(); int count = Math.max(TiffImage.getNumberOfPages(odd), TiffImage.getNumberOfPages(even)); for (int c = 0; c < count; ++c) { try { Image imgOdd = TiffImage.getTiffImage(odd, c + 1); Image imgEven = TiffImage.getTiffImage(even, count - c); document.setPageSize(new Rectangle(imgOdd.getScaledWidth(), imgOdd.getScaledHeight())); document.newPage(); imgOdd.setAbsolutePosition(0, 0); cb.addImage(imgOdd); document.setPageSize(new Rectangle(imgEven.getScaledWidth(), imgEven.getScaledHeight())); document.newPage(); imgEven.setAbsolutePosition(0, 0); cb.addImage(imgEven); } catch (Exception e) { System.out.println("Exception page " + (c + 1) + " " + e.getMessage()); } } odd.close(); even.close(); document.close(); } catch (Exception e) { e.printStackTrace(); } }
protected List<TrueTypeGlyph> getCharactersToOutput(int glyph) throws IOException { ArrayList<TrueTypeGlyph> characters = new ArrayList<TrueTypeGlyph>(); int[] glyphDataPosition = getGlyphDataPosition(glyph); int glyphDataOffset = glyphDataPosition[0]; int glyphDataLength = glyphDataPosition[1]; if (glyphDataLength == 0) // no contour return characters; int tableGlyphOffset = ((int[]) positionTables.get("glyf"))[0]; rf.seek(tableGlyphOffset + glyphDataOffset); int numContours = rf.readShort(); if (numContours >= 0) return characters; rf.skipBytes(8); for (; ; ) { int flags = rf.readUnsignedShort(); Integer cGlyph = rf.readUnsignedShort(); TrueTypeGlyph trueTypeGlyph = new TrueTypeGlyph(cGlyph.intValue()); if (!glyphDefined.contains(trueTypeGlyph)) { characters.add(trueTypeGlyph); } if ((flags & MORE_COMPONENTS) == 0) return characters; int skip; if ((flags & ARG_1_AND_2_ARE_WORDS) != 0) skip = 4; else skip = 2; if ((flags & WE_HAVE_A_SCALE) != 0) skip += 2; else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) skip += 4; if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0) skip += 8; rf.skipBytes(skip); } }
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 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 }; } } }
private static RandomAccessFileOrArray populateDescription0( String path, BaseFont font, FontDescription descr, RandomAccessFileOrArray rf) throws NoSuchFieldException, IllegalAccessException, DocumentException, IOException { Map tables = extractTables(font); descr.setStyle(guessStyle(font)); int[] location = (int[]) tables.get("OS/2"); if (location == null) { throw new DocumentException("Table 'OS/2' does not exist in " + path); } rf.seek(location[0]); int want = 4; long got = rf.skip(want); if (got < want) { throw new DocumentException( "Skip TT font weight, expect read " + want + " bytes, but only got " + got); } descr.setWeight(rf.readUnsignedShort()); want = 20; got = rf.skip(want); if (got < want) { throw new DocumentException( "Skip TT font strikeout, expect read " + want + " bytes, but only got " + got); } descr.setYStrikeoutSize(rf.readShort()); descr.setYStrikeoutPosition(rf.readShort()); location = (int[]) tables.get("post"); if (location != null) { rf.seek(location[0]); want = 8; got = rf.skip(want); if (got < want) { throw new DocumentException( "Skip TT font underline, expect read " + want + " bytes, but only got " + got); } descr.setUnderlinePosition(rf.readShort()); descr.setUnderlineThickness(rf.readShort()); } rf.close(); rf = null; return rf; }
/** * Extracts the names of the font in all the languages available. * * @param id the name id to retrieve * @throws DocumentException on error * @throws IOException on error */ String[][] getNames(int id) throws DocumentException, IOException { int table_location[]; table_location = (int[]) positionTables.get("name"); if (table_location == null) throw new DocumentException("Table 'name' does not exist in " + fileName + style); rf.seek(table_location[0] + 2); int numRecords = rf.readUnsignedShort(); int startOfStorage = rf.readUnsignedShort(); ArrayList<String[]> names = new ArrayList<String[]>(); for (int k = 0; k < numRecords; ++k) { int platformID = rf.readUnsignedShort(); int platformEncodingID = rf.readUnsignedShort(); int languageID = rf.readUnsignedShort(); int nameID = rf.readUnsignedShort(); int length = rf.readUnsignedShort(); int offset = rf.readUnsignedShort(); if (nameID == id) { int pos = rf.getFilePointer(); rf.seek(table_location[0] + startOfStorage + offset); String name; if (platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1)) { name = readUnicodeString(length); } else { name = readStandardString(length); } names.add( new String[] { String.valueOf(platformID), String.valueOf(platformEncodingID), String.valueOf(languageID), name }); rf.seek(pos); } } String thisName[][] = new String[names.size()][]; for (int k = 0; k < names.size(); ++k) thisName[k] = (String[]) names.get(k); return thisName; }
/** * 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; } } }
/** * 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 initialize(RandomAccessFileOrArray stream) throws IOException { long nextTagOffset = 0L; long maxOffset = stream.length(); int i, j; IFDOffset = stream.getFilePointer(); numEntries = readUnsignedShort(stream); fields = new TIFFField[numEntries]; for (i = 0; (i < numEntries) && (nextTagOffset < maxOffset); i++) { int tag = readUnsignedShort(stream); int type = readUnsignedShort(stream); int count = (int) (readUnsignedInt(stream)); boolean processTag = true; nextTagOffset = stream.getFilePointer() + 4; try { if (count * sizeOfType[type] > 4) { long valueOffset = readUnsignedInt(stream); if (valueOffset < maxOffset) { stream.seek(valueOffset); } else { processTag = false; } } } catch (ArrayIndexOutOfBoundsException ae) { processTag = false; } if (processTag) { fieldIndex.put(new Integer(tag), new Integer(i)); Object obj = null; switch (type) { case TIFFField.TIFF_BYTE: case TIFFField.TIFF_SBYTE: case TIFFField.TIFF_UNDEFINED: case TIFFField.TIFF_ASCII: byte[] bvalues = new byte[count]; stream.readFully(bvalues, 0, count); if (type == TIFFField.TIFF_ASCII) { int index = 0, prevIndex = 0; ArrayList v = new ArrayList(); while (index < count) { while ((index < count) && (bvalues[index++] != 0)) ; v.add(new String(bvalues, prevIndex, (index - prevIndex))); prevIndex = index; } count = v.size(); String strings[] = new String[count]; for (int c = 0; c < count; c++) { strings[c] = (String) v.get(c); } obj = strings; } else { obj = bvalues; } break; case TIFFField.TIFF_SHORT: char[] cvalues = new char[count]; for (j = 0; j < count; j++) { cvalues[j] = (char) (readUnsignedShort(stream)); } obj = cvalues; break; case TIFFField.TIFF_LONG: long[] lvalues = new long[count]; for (j = 0; j < count; j++) { lvalues[j] = readUnsignedInt(stream); } obj = lvalues; break; case TIFFField.TIFF_RATIONAL: long[][] llvalues = new long[count][2]; for (j = 0; j < count; j++) { llvalues[j][0] = readUnsignedInt(stream); llvalues[j][1] = readUnsignedInt(stream); } obj = llvalues; break; case TIFFField.TIFF_SSHORT: short[] svalues = new short[count]; for (j = 0; j < count; j++) { svalues[j] = readShort(stream); } obj = svalues; break; case TIFFField.TIFF_SLONG: int[] ivalues = new int[count]; for (j = 0; j < count; j++) { ivalues[j] = readInt(stream); } obj = ivalues; break; case TIFFField.TIFF_SRATIONAL: int[][] iivalues = new int[count][2]; for (j = 0; j < count; j++) { iivalues[j][0] = readInt(stream); iivalues[j][1] = readInt(stream); } obj = iivalues; break; case TIFFField.TIFF_FLOAT: float[] fvalues = new float[count]; for (j = 0; j < count; j++) { fvalues[j] = readFloat(stream); } obj = fvalues; break; case TIFFField.TIFF_DOUBLE: double[] dvalues = new double[count]; for (j = 0; j < count; j++) { dvalues[j] = readDouble(stream); } obj = dvalues; break; default: break; } fields[i] = new TIFFField(tag, type, count, obj); } stream.seek(nextTagOffset); } try { nextIFDOffset = readUnsignedInt(stream); } catch (Exception e) { nextIFDOffset = 0; } }