001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.imaging.formats.tiff.write; 018 019import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_ENTRY_MAX_VALUE_LENGTH; 020 021import java.io.IOException; 022import java.nio.ByteOrder; 023import java.util.Arrays; 024 025import org.apache.commons.imaging.ImageWriteException; 026import org.apache.commons.imaging.common.BinaryOutputStream; 027import org.apache.commons.imaging.formats.tiff.fieldtypes.FieldType; 028import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo; 029 030public class TiffOutputField { 031 public final int tag; 032 public final TagInfo tagInfo; 033 public final FieldType fieldType; 034 public final int count; 035 private byte[] bytes; 036 private final TiffOutputItem.Value separateValueItem; 037 private int sortHint = -1; 038 private static final String NEWLINE = System.getProperty("line.separator"); 039 040 public TiffOutputField(final TagInfo tagInfo, final FieldType tagtype, final int count, 041 final byte[] bytes) { 042 this(tagInfo.tag, tagInfo, tagtype, count, bytes); 043 } 044 045 public TiffOutputField(final int tag, final TagInfo tagInfo, final FieldType fieldType, 046 final int count, final byte[] bytes) { 047 this.tag = tag; 048 this.tagInfo = tagInfo; 049 this.fieldType = fieldType; 050 this.count = count; 051 this.bytes = bytes; 052 053 if (isLocalValue()) { 054 separateValueItem = null; 055 } else { 056 final String name = "Field Separate value (" + tagInfo.getDescription() 057 + ")"; 058 separateValueItem = new TiffOutputItem.Value(name, bytes); 059 } 060 } 061 062 protected static TiffOutputField createOffsetField(final TagInfo tagInfo, 063 final ByteOrder byteOrder) throws ImageWriteException { 064 return new TiffOutputField(tagInfo, FieldType.LONG, 1, 065 FieldType.LONG.writeData(0, byteOrder)); 066 } 067 068 protected void writeField(final BinaryOutputStream bos) throws IOException, 069 ImageWriteException { 070 bos.write2Bytes(tag); 071 bos.write2Bytes(fieldType.getType()); 072 bos.write4Bytes(count); 073 074 if (isLocalValue()) { 075 if (separateValueItem != null) { 076 throw new ImageWriteException("Unexpected separate value item."); 077 } 078 if (bytes.length > 4) { 079 throw new ImageWriteException( 080 "Local value has invalid length: " + bytes.length); 081 } 082 083 bos.write(bytes); 084 final int remainder = TIFF_ENTRY_MAX_VALUE_LENGTH - bytes.length; 085 for (int i = 0; i < remainder; i++) { 086 bos.write(0); 087 } 088 } else { 089 if (separateValueItem == null) { 090 throw new ImageWriteException("Missing separate value item."); 091 } 092 093 bos.write4Bytes((int) separateValueItem.getOffset()); 094 } 095 } 096 097 protected TiffOutputItem getSeperateValue() { 098 return separateValueItem; 099 } 100 101 protected final boolean isLocalValue() { 102 return bytes.length <= TIFF_ENTRY_MAX_VALUE_LENGTH; 103 } 104 105 public boolean bytesEqual(final byte[] data) { 106 return Arrays.equals(bytes, data); 107 } 108 109 protected void setData(final byte[] bytes) throws ImageWriteException { 110 // if(tagInfo.isUnknown()) 111 // Debug.debug("unknown tag(0x" + Integer.toHexString(tag) 112 // + ") setData", bytes); 113 114 if (this.bytes.length != bytes.length) { 115 throw new ImageWriteException("Cannot change size of value."); 116 } 117 118 // boolean wasLocalValue = isLocalValue(); 119 this.bytes = bytes; 120 if (separateValueItem != null) { 121 separateValueItem.updateValue(bytes); 122 } 123 // if (isLocalValue() != wasLocalValue) 124 // throw new Error("Bug. Locality disrupted! " 125 // + tagInfo.getDescription()); 126 } 127 128 @Override 129 public String toString() { 130 return toString(null); 131 } 132 133 public String toString(String prefix) { 134 if (prefix == null) { 135 prefix = ""; 136 } 137 final StringBuilder result = new StringBuilder(); 138 139 result.append(prefix); 140 result.append(tagInfo); 141 result.append(NEWLINE); 142 143 result.append(prefix); 144 result.append("count: "); 145 result.append(count); 146 result.append(NEWLINE); 147 148 result.append(prefix); 149 result.append(fieldType); 150 result.append(NEWLINE); 151 152 return result.toString(); 153 } 154 155 public int getSortHint() { 156 return sortHint; 157 } 158 159 public void setSortHint(final int sortHint) { 160 this.sortHint = sortHint; 161 } 162}