/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.sanselan.formats.tiff.write; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.apache.sanselan.ImageWriteException; import org.apache.sanselan.common.BinaryOutputStream; import org.apache.sanselan.formats.tiff.JpegImageData; import org.apache.sanselan.formats.tiff.TiffDirectory; import org.apache.sanselan.formats.tiff.TiffElement; import org.apache.sanselan.formats.tiff.TiffImageData; import org.apache.sanselan.formats.tiff.constants.TagConstantsUtils; import org.apache.sanselan.formats.tiff.constants.TagInfo; import org.apache.sanselan.formats.tiff.constants.TiffConstants; import org.apache.sanselan.formats.tiff.fieldtypes.FieldType; public final class TiffOutputDirectory extends TiffOutputItem implements TiffConstants { public final int type; private final ArrayList fields = new ArrayList(); private TiffOutputDirectory nextDirectory = null; public void setNextDirectory(TiffOutputDirectory nextDirectory) { this.nextDirectory = nextDirectory; } public TiffOutputDirectory(final int type) { this.type = type; } public void add(TiffOutputField field) { fields.add(field); } public ArrayList getFields() { return new ArrayList(fields); } public void removeField(TagInfo tagInfo) { removeField(tagInfo.tag); } public void removeField(int tag) { ArrayList matches = new ArrayList(); for (int i = 0; i < fields.size(); i++) { TiffOutputField field = (TiffOutputField) fields.get(i); if (field.tag == tag) matches.add(field); } fields.removeAll(matches); } public TiffOutputField findField(TagInfo tagInfo) { return findField(tagInfo.tag); } public TiffOutputField findField(int tag) { for (int i = 0; i < fields.size(); i++) { TiffOutputField field = (TiffOutputField) fields.get(i); if (field.tag == tag) return field; } return null; } public void sortFields() { Comparator comparator = new Comparator() { public int compare(Object o1, Object o2) { TiffOutputField e1 = (TiffOutputField) o1; TiffOutputField e2 = (TiffOutputField) o2; if (e1.tag != e2.tag) return e1.tag - e2.tag; return e1.getSortHint() - e2.getSortHint(); } }; Collections.sort(fields, comparator); } public String description() { return TiffDirectory.description(type); } public void writeItem(BinaryOutputStream bos) throws IOException, ImageWriteException { // Write Directory Field Count bos.write2Bytes(fields.size()); // DirectoryFieldCount // Write Fields for (int i = 0; i < fields.size(); i++) { TiffOutputField field = (TiffOutputField) fields.get(i); field.writeField(bos); // Debug.debug("\t" + "writing field (" + field.tag + ", 0x" + // Integer.toHexString(field.tag) + ")", field.tagInfo); // if(field.tagInfo.isOffset()) // Debug.debug("\t\tOFFSET!", field.bytes); } int nextDirectoryOffset = 0; if (nextDirectory != null) nextDirectoryOffset = nextDirectory.getOffset(); // Write nextDirectoryOffset if (nextDirectoryOffset == UNDEFINED_VALUE) bos.write4Bytes(0); else bos.write4Bytes(nextDirectoryOffset); } private JpegImageData jpegImageData = null; public void setJpegImageData(JpegImageData rawJpegImageData) { this.jpegImageData = rawJpegImageData; } public JpegImageData getRawJpegImageData() { return jpegImageData; } private TiffImageData tiffImageData = null; public void setTiffImageData(TiffImageData rawTiffImageData) { this.tiffImageData = rawTiffImageData; } public TiffImageData getRawTiffImageData() { return tiffImageData; } public int getItemLength() { return TIFF_ENTRY_LENGTH * fields.size() + TIFF_DIRECTORY_HEADER_LENGTH + TIFF_DIRECTORY_FOOTER_LENGTH; } public String getItemDescription() { ExifDirectoryType dirType = TagConstantsUtils .getExifDirectoryType(type); return "Directory: " + dirType.name + " (" + type + ")"; } private void removeFieldIfPresent(TagInfo tagInfo) { TiffOutputField field = findField(tagInfo); if (null != field) fields.remove(field); } protected List getOutputItems(TiffOutputSummary outputSummary) throws ImageWriteException { // first validate directory fields. removeFieldIfPresent(TIFF_TAG_JPEG_INTERCHANGE_FORMAT); removeFieldIfPresent(TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH); TiffOutputField jpegOffsetField = null; if (null != jpegImageData) { jpegOffsetField = new TiffOutputField( TIFF_TAG_JPEG_INTERCHANGE_FORMAT, FIELD_TYPE_LONG, 1, FieldType.getStubLocalValue()); add(jpegOffsetField); byte lengthValue[] = FIELD_TYPE_LONG.writeData( new int[] { jpegImageData.length, }, outputSummary.byteOrder); TiffOutputField jpegLengthField = new TiffOutputField( TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, FIELD_TYPE_LONG, 1, lengthValue); add(jpegLengthField); } // -------------------------------------------------------------- removeFieldIfPresent(TIFF_TAG_STRIP_OFFSETS); removeFieldIfPresent(TIFF_TAG_STRIP_BYTE_COUNTS); removeFieldIfPresent(TIFF_TAG_TILE_OFFSETS); removeFieldIfPresent(TIFF_TAG_TILE_BYTE_COUNTS); TiffOutputField imageDataOffsetField; ImageDataOffsets imageDataInfo = null; if (null != tiffImageData) { boolean stripsNotTiles = tiffImageData.stripsNotTiles(); TagInfo offsetTag; TagInfo byteCountsTag; if (stripsNotTiles) { offsetTag = TIFF_TAG_STRIP_OFFSETS; byteCountsTag = TIFF_TAG_STRIP_BYTE_COUNTS; } else { offsetTag = TIFF_TAG_TILE_OFFSETS; byteCountsTag = TIFF_TAG_TILE_BYTE_COUNTS; } // -------- TiffElement.DataElement imageData[] = tiffImageData.getImageData(); int imageDataOffsets[] = null; int imageDataByteCounts[] = null; // TiffOutputField imageDataOffsetsField = null; imageDataOffsets = new int[imageData.length]; imageDataByteCounts = new int[imageData.length]; for (int i = 0; i < imageData.length; i++) { imageDataByteCounts[i] = imageData[i].length; } // -------- // Append imageData-related fields to first directory imageDataOffsetField = new TiffOutputField(offsetTag, FIELD_TYPE_LONG, imageDataOffsets.length, FIELD_TYPE_LONG .writeData(imageDataOffsets, outputSummary.byteOrder)); add(imageDataOffsetField); // -------- byte data[] = FIELD_TYPE_LONG.writeData(imageDataByteCounts, outputSummary.byteOrder); TiffOutputField byteCountsField = new TiffOutputField( byteCountsTag, FIELD_TYPE_LONG, imageDataByteCounts.length, data); add(byteCountsField); // -------- imageDataInfo = new ImageDataOffsets(imageData, imageDataOffsets, imageDataOffsetField); } // -------------------------------------------------------------- List result = new ArrayList(); result.add(this); sortFields(); for (int i = 0; i < fields.size(); i++) { TiffOutputField field = (TiffOutputField) fields.get(i); if (field.isLocalValue()) continue; TiffOutputItem item = field.getSeperateValue(); result.add(item); // outputSummary.add(item, field); } if (null != imageDataInfo) { for (int i = 0; i < imageDataInfo.outputItems.length; i++) result.add(imageDataInfo.outputItems[i]); outputSummary.addTiffImageData(imageDataInfo); } if (null != jpegImageData) { TiffOutputItem item = new TiffOutputItem.Value("JPEG image data", jpegImageData.data); result.add(item); outputSummary.add(item, jpegOffsetField); } return result; } }