public void writeToStream(ImageOutputStream stream, final boolean isBTIFF) throws IOException { long nextSpace; if (!isBTIFF) { int numFields = getNumTIFFFields(); stream.writeShort(numFields); nextSpace = stream.getStreamPosition() + 12 * numFields + 4; } else { long numFields = getNumTIFFFields(); stream.writeLong(numFields); nextSpace = stream.getStreamPosition() + 20 * numFields + 8; } Iterator iter = iterator(); while (iter.hasNext()) { TIFFField f = (TIFFField) iter.next(); TIFFTag tag = f.getTag(); int type = f.getType(); int count = f.getCount(); // Hack to deal with unknown tags if (type == 0) { type = TIFFTag.TIFF_UNDEFINED; } int size = count * TIFFTag.getSizeOfType(type); if (type == TIFFTag.TIFF_ASCII) { int chars = 0; for (int i = 0; i < count; i++) { chars += f.getAsString(i).length() + 1; } count = chars; size = count; } int tagNumber = f.getTagNumber(); stream.writeShort(tagNumber); stream.writeShort(type); if (isBTIFF) { stream.writeLong(count); stream.writeLong(0); stream.mark(); // Mark beginning of next field stream.skipBytes(-8); } else { stream.writeInt(count); stream.writeInt(0); stream.mark(); // Mark beginning of next field stream.skipBytes(-4); } long pos; if (!isBTIFF) { if (size > 4 || tag.isIFDPointer()) { // Ensure IFD or value is written on a word boundary nextSpace = (nextSpace + 3) & ~0x3; stream.writeInt((int) nextSpace); stream.seek(nextSpace); pos = nextSpace; if (tag.isIFDPointer()) { TIFFIFD subIFD = (TIFFIFD) f.getData(); subIFD.writeToStream(stream, isBTIFF); nextSpace = subIFD.lastPosition; } else { writeTIFFFieldToStream(f, stream); nextSpace = stream.getStreamPosition(); } } else { pos = stream.getStreamPosition(); writeTIFFFieldToStream(f, stream); } } else { if (size > 8 || tag.isIFDPointer()) { // Ensure IFD or value is written on a Long boundary nextSpace = (nextSpace + 7) & ~0x7; stream.writeLong(nextSpace); stream.seek(nextSpace); pos = nextSpace; if (tag.isIFDPointer()) { TIFFIFD subIFD = (TIFFIFD) f.getData(); subIFD.writeToStream(stream, isBTIFF); nextSpace = subIFD.lastPosition; } else { writeTIFFFieldToStream(f, stream); nextSpace = stream.getStreamPosition(); } } else { pos = stream.getStreamPosition(); writeTIFFFieldToStream(f, stream); } } // If we are writing the data for the // StripByteCounts, TileByteCounts, StripOffsets, // TileOffsets, JPEGInterchangeFormat, or // JPEGInterchangeFormatLength fields, record the current stream // position for backpatching if (tagNumber == BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS || tagNumber == BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS || tagNumber == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH) { this.stripOrTileByteCountsPosition = pos; } else if (tagNumber == BaselineTIFFTagSet.TAG_STRIP_OFFSETS || tagNumber == BaselineTIFFTagSet.TAG_TILE_OFFSETS || tagNumber == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) { this.stripOrTileOffsetsPosition = pos; } stream.reset(); // Go to marked position of next field } this.lastPosition = nextSpace; }
public void initialize( ImageInputStream stream, boolean ignoreUnknownFields, final boolean isBTIFF) throws IOException { removeTIFFFields(); List tagSetList = getTagSetList(); final long numEntries; if (isBTIFF) numEntries = stream.readLong(); else numEntries = stream.readUnsignedShort(); for (int i = 0; i < numEntries; i++) { // Read tag number, value type, and value count. int tag = stream.readUnsignedShort(); int type = stream.readUnsignedShort(); int count; if (isBTIFF) { long count_ = stream.readLong(); count = (int) count_; if (count != count_) throw new IllegalArgumentException("unable to use long number of values"); } else count = (int) stream.readUnsignedInt(); // Get the associated TIFFTag. TIFFTag tiffTag = getTag(tag, tagSetList); // Ignore unknown fields. if (ignoreUnknownFields && tiffTag == null) { // Skip the value/offset so as to leave the stream // position at the start of the next IFD entry. if (isBTIFF) stream.skipBytes(8); else stream.skipBytes(4); // XXX Warning message ... // Continue with the next IFD entry. continue; } long nextTagOffset; if (isBTIFF) { nextTagOffset = stream.getStreamPosition() + 8; int sizeOfType = TIFFTag.getSizeOfType(type); if (count * sizeOfType > 8) { long value = stream.readLong(); stream.seek(value); } } else { nextTagOffset = stream.getStreamPosition() + 4; int sizeOfType = TIFFTag.getSizeOfType(type); if (count * sizeOfType > 4) { long value = stream.readUnsignedInt(); stream.seek(value); } } if (tag == BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS || tag == BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS || tag == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH) { this.stripOrTileByteCountsPosition = stream.getStreamPosition(); if (LAZY_LOADING) { type = type == TIFFTag.TIFF_LONG ? TIFFTag.TIFF_LAZY_LONG : TIFFTag.TIFF_LAZY_LONG8; } } else if (tag == BaselineTIFFTagSet.TAG_STRIP_OFFSETS || tag == BaselineTIFFTagSet.TAG_TILE_OFFSETS || tag == BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) { this.stripOrTileOffsetsPosition = stream.getStreamPosition(); if (LAZY_LOADING) { type = type == TIFFTag.TIFF_LONG ? TIFFTag.TIFF_LAZY_LONG : TIFFTag.TIFF_LAZY_LONG8; } } Object obj = null; try { switch (type) { case TIFFTag.TIFF_BYTE: case TIFFTag.TIFF_SBYTE: case TIFFTag.TIFF_UNDEFINED: case TIFFTag.TIFF_ASCII: byte[] bvalues = new byte[count]; stream.readFully(bvalues, 0, count); if (type == TIFFTag.TIFF_ASCII) { // Can be multiple strings final List<String> v = new ArrayList<String>(); boolean inString = false; int prevIndex = 0; for (int index = 0; index <= count; index++) { if (index < count && bvalues[index] != 0) { if (!inString) { // start of string prevIndex = index; inString = true; } } else { // null or special case at end of string if (inString) { // end of string final String s = new String(bvalues, prevIndex, index - prevIndex); v.add(s); inString = false; } } } count = v.size(); String[] strings; if (count != 0) { strings = new String[count]; for (int c = 0; c < count; c++) { strings[c] = v.get(c); } } else { // This case has been observed when the value of // 'count' recorded in the field is non-zero but // the value portion contains all nulls. count = 1; strings = new String[] {""}; } obj = strings; } else { obj = bvalues; } break; case TIFFTag.TIFF_SHORT: char[] cvalues = new char[count]; for (int j = 0; j < count; j++) { cvalues[j] = (char) (stream.readUnsignedShort()); } obj = cvalues; break; case TIFFTag.TIFF_LONG: case TIFFTag.TIFF_IFD_POINTER: long[] lvalues = new long[count]; for (int j = 0; j < count; j++) { lvalues[j] = stream.readUnsignedInt(); } obj = lvalues; break; case TIFFTag.TIFF_RATIONAL: long[][] llvalues = new long[count][2]; for (int j = 0; j < count; j++) { llvalues[j][0] = stream.readUnsignedInt(); llvalues[j][1] = stream.readUnsignedInt(); } obj = llvalues; break; case TIFFTag.TIFF_SSHORT: short[] svalues = new short[count]; for (int j = 0; j < count; j++) { svalues[j] = stream.readShort(); } obj = svalues; break; case TIFFTag.TIFF_SLONG: int[] ivalues = new int[count]; for (int j = 0; j < count; j++) { ivalues[j] = stream.readInt(); } obj = ivalues; break; case TIFFTag.TIFF_SRATIONAL: int[][] iivalues = new int[count][2]; for (int j = 0; j < count; j++) { iivalues[j][0] = stream.readInt(); iivalues[j][1] = stream.readInt(); } obj = iivalues; break; case TIFFTag.TIFF_FLOAT: float[] fvalues = new float[count]; for (int j = 0; j < count; j++) { fvalues[j] = stream.readFloat(); } obj = fvalues; break; case TIFFTag.TIFF_DOUBLE: double[] dvalues = new double[count]; for (int j = 0; j < count; j++) { dvalues[j] = stream.readDouble(); } obj = dvalues; break; case TIFFTag.TIFF_LONG8: case TIFFTag.TIFF_SLONG8: case TIFFTag.TIFF_IFD8: long[] lBvalues = new long[count]; for (int j = 0; j < count; j++) { lBvalues[j] = stream.readLong(); } obj = lBvalues; break; case TIFFTag.TIFF_LAZY_LONG8: case TIFFTag.TIFF_LAZY_LONG: obj = new TIFFLazyData(stream, type, count); break; default: // XXX Warning break; } } catch (EOFException eofe) { // The TIFF 6.0 fields have tag numbers less than or equal // to 532 (ReferenceBlackWhite) or equal to 33432 (Copyright). // If there is an error reading a baseline tag, then re-throw // the exception and fail; otherwise continue with the next // field. if (BaselineTIFFTagSet.getInstance().getTag(tag) == null) { throw eofe; } } if (tiffTag == null) { // XXX Warning: unknown tag } else if (!tiffTag.isDataTypeOK(type)) { // XXX Warning: bad data type } else if (tiffTag.isIFDPointer() && obj != null) { stream.mark(); stream.seek(((long[]) obj)[0]); List tagSets = new ArrayList(1); tagSets.add(tiffTag.getTagSet()); TIFFIFD subIFD = new TIFFIFD(tagSets); // XXX Use same ignore policy for sub-IFD fields? subIFD.initialize(stream, ignoreUnknownFields); obj = subIFD; stream.reset(); } if (tiffTag == null) { tiffTag = new TIFFTag(null, tag, 1 << type, null); } // Add the field if its contents have been initialized which // will not be the case if an EOF was ignored above. if (obj != null) { TIFFField f = new TIFFField(tiffTag, type, count, obj); addTIFFField(f); } stream.seek(nextTagOffset); } this.lastPosition = stream.getStreamPosition(); }