1 /* 2 * Copyright 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef IMG_UTILS_TIFF_WRITER_H 18 #define IMG_UTILS_TIFF_WRITER_H 19 20 #include <img_utils/EndianUtils.h> 21 #include <img_utils/StripSource.h> 22 #include <img_utils/TiffEntryImpl.h> 23 #include <img_utils/TagDefinitions.h> 24 #include <img_utils/TiffIfd.h> 25 26 #include <utils/Log.h> 27 #include <utils/Errors.h> 28 #include <utils/StrongPointer.h> 29 #include <utils/KeyedVector.h> 30 #include <utils/Vector.h> 31 32 #include <cutils/compiler.h> 33 #include <stdint.h> 34 35 namespace android { 36 namespace img_utils { 37 38 class TiffEntry; 39 class TiffIfd; 40 class Output; 41 42 /** 43 * This class holds a collection of TIFF IFDs that can be written as a 44 * complete DNG file header. 45 * 46 * This maps to the TIFF header structure that is logically composed of: 47 * - An 8-byte file header containing an endianness indicator, the TIFF 48 * file marker, and the offset to the first IFD. 49 * - A list of TIFF IFD structures. 50 */ 51 class ANDROID_API TiffWriter : public LightRefBase<TiffWriter> { 52 public: 53 enum SubIfdType { 54 SUBIFD = 0, 55 GPSINFO 56 }; 57 58 /** 59 * Constructs a TiffWriter with the default tag mappings. This enables 60 * all of the tags defined in TagDefinitions.h, and uses the following 61 * mapping precedence to resolve collisions: 62 * (highest precedence) TIFF/EP > DNG > EXIF 2.3 > TIFF 6.0 63 */ 64 TiffWriter(); 65 66 /** 67 * Constructs a TiffWriter with the given tag mappings. The mapping 68 * precedence will be in the order that the definition maps are given, 69 * where the lower index map gets precedence. 70 * 71 * This can be used with user-defined definitions, or definitions form 72 * TagDefinitions.h 73 * 74 * The enabledDefinitions mapping object is owned by the caller, and must 75 * stay alive for the lifespan of the constructed TiffWriter object. 76 */ 77 TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions, 78 size_t length); 79 80 virtual ~TiffWriter(); 81 82 /** 83 * Write a TIFF header containing each IFD set. This will recursively 84 * write all SubIFDs and tags. 85 * 86 * Any StripSources passed in will be written to the output as image strips 87 * at the appropriate offests. The StripByteCounts, RowsPerStrip, and 88 * StripOffsets tags must be set to use this. To set these tags in a 89 * given IFD, use the addStrip method. 90 * 91 * Returns OK on success, or a negative error code on failure. 92 */ 93 virtual status_t write(Output* out, StripSource** sources, size_t sourcesCount, 94 Endianness end = LITTLE); 95 96 /** 97 * Write a TIFF header containing each IFD set. This will recursively 98 * write all SubIFDs and tags. 99 * 100 * Image data for strips or tiles must be written separately at the 101 * appropriate offsets. These offsets must not fall within the file 102 * header written this way. The size of the header written is given 103 * by the getTotalSize() method. 104 * 105 * Returns OK on success, or a negative error code on failure. 106 */ 107 virtual status_t write(Output* out, Endianness end = LITTLE); 108 109 /** 110 * Get the total size in bytes of the TIFF header. This includes all 111 * IFDs, tags, and values set for this TiffWriter. 112 */ 113 virtual uint32_t getTotalSize() const; 114 115 /** 116 * Add an entry to the IFD with the given ID. 117 * 118 * Returns OK on success, or a negative error code on failure. Valid 119 * error codes for this method are: 120 * - BAD_INDEX - The given tag doesn't exist. 121 * - BAD_VALUE - The given count doesn't match the required count for 122 * this tag. 123 * - BAD_TYPE - The type of the given data isn't compatible with the 124 * type required for this tag. 125 * - NAME_NOT_FOUND - No ifd exists with the given ID. 126 */ 127 virtual status_t addEntry(const sp<TiffEntry>& entry, uint32_t ifd); 128 129 /** 130 * Build an entry for a known tag and add it to the IFD with the given ID. 131 * This tag must be defined in one of the definition vectors this TIFF writer 132 * was constructed with. The count and type are validated. 133 * 134 * Returns OK on success, or a negative error code on failure. Valid 135 * error codes for this method are: 136 * - BAD_INDEX - The given tag doesn't exist. 137 * - BAD_VALUE - The given count doesn't match the required count for 138 * this tag. 139 * - BAD_TYPE - The type of the given data isn't compatible with the 140 * type required for this tag. 141 * - NAME_NOT_FOUND - No ifd exists with the given ID. 142 */ 143 template<typename T> 144 status_t addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd); 145 146 /** 147 * Build an entry for a known tag. This tag must be one of the tags 148 * defined in one of the definition vectors this TIFF writer was constructed 149 * with. The count and type are validated. If this succeeds, the resulting 150 * entry will be placed in the outEntry pointer. 151 * 152 * Returns OK on success, or a negative error code on failure. Valid 153 * error codes for this method are: 154 * - BAD_INDEX - The given tag doesn't exist. 155 * - BAD_VALUE - The given count doesn't match the required count for 156 * this tag. 157 * - BAD_TYPE - The type of the given data isn't compatible with the 158 * type required for this tag. 159 */ 160 template<typename T> 161 status_t buildEntry(uint16_t tag, uint32_t count, const T* data, 162 /*out*/sp<TiffEntry>* outEntry) const; 163 164 /** 165 * Convenience function to set the strip related tags for a given IFD. 166 * 167 * Call this before using a StripSource as an input to write. 168 * The following tags must be set before calling this method: 169 * - ImageWidth 170 * - ImageLength 171 * - SamplesPerPixel 172 * - BitsPerSample 173 * 174 * Returns OK on success, or a negative error code. 175 */ 176 virtual status_t addStrip(uint32_t ifd); 177 178 /** 179 * Return the TIFF entry with the given tag ID in the IFD with the given ID, 180 * or an empty pointer if none exists. 181 */ 182 virtual sp<TiffEntry> getEntry(uint16_t tag, uint32_t ifd) const; 183 184 /** 185 * Remove the TIFF entry with the given tag ID in the given IFD if it exists. 186 */ 187 virtual void removeEntry(uint16_t tag, uint32_t ifd); 188 189 /** 190 * Create an empty IFD with the given ID and add it to the end of the 191 * list of IFDs. 192 */ 193 virtual status_t addIfd(uint32_t ifd); 194 195 /** 196 * Create an empty IFD with the given ID and add it as a SubIfd of the 197 * parent IFD. 198 */ 199 virtual status_t addSubIfd(uint32_t parentIfd, uint32_t ifd, SubIfdType type = SUBIFD); 200 201 /** 202 * Returns the default type for the given tag ID. 203 */ 204 virtual TagType getDefaultType(uint16_t tag) const; 205 206 /** 207 * Returns the default count for a given tag ID, or 0 if this 208 * tag normally has a variable count. 209 */ 210 virtual uint32_t getDefaultCount(uint16_t tag) const; 211 212 /** 213 * Returns true if an IFD with the given ID exists. 214 */ 215 virtual bool hasIfd(uint32_t ifd) const; 216 217 /** 218 * Returns true if a definition exist for the given tag ID. 219 */ 220 virtual bool checkIfDefined(uint16_t tag) const; 221 222 /** 223 * Returns the name of the tag if a definition exists for the given tag 224 * ID, or null if no definition exists. 225 */ 226 virtual const char* getTagName(uint16_t tag) const; 227 228 /** 229 * Print the currently configured IFDs and entries to logcat. 230 */ 231 virtual void log() const; 232 233 /** 234 * Build an entry. No validation is done. 235 * 236 * WARNING: Using this method can result in creating poorly formatted 237 * TIFF files. 238 * 239 * Returns a TiffEntry with the given tag, type, count, endianness, 240 * and data. 241 */ 242 template<typename T> 243 static sp<TiffEntry> uncheckedBuildEntry(uint16_t tag, TagType type, 244 uint32_t count, Endianness end, const T* data); 245 246 /** 247 * Utility function to build atag-to-definition mapping from a given 248 * array of tag definitions. 249 */ 250 static KeyedVector<uint16_t, const TagDefinition_t*> buildTagMap( 251 const TagDefinition_t* definitions, size_t length); 252 253 protected: 254 enum { 255 DEFAULT_NUM_TAG_MAPS = 4, 256 }; 257 258 sp<TiffIfd> findLastIfd(); 259 status_t writeFileHeader(EndianOutput& out); 260 const TagDefinition_t* lookupDefinition(uint16_t tag) const; 261 status_t calculateOffsets(); 262 263 sp<TiffIfd> mIfd; 264 KeyedVector<uint32_t, sp<TiffIfd> > mNamedIfds; 265 KeyedVector<uint16_t, const TagDefinition_t*>* mTagMaps; 266 size_t mNumTagMaps; 267 268 static KeyedVector<uint16_t, const TagDefinition_t*> sTagMaps[]; 269 }; 270 271 template<typename T> 272 status_t TiffWriter::buildEntry(uint16_t tag, uint32_t count, const T* data, 273 /*out*/sp<TiffEntry>* outEntry) const { 274 const TagDefinition_t* definition = lookupDefinition(tag); 275 276 if (definition == NULL) { 277 ALOGE("%s: No such tag exists for id %x.", __FUNCTION__, tag); 278 return BAD_INDEX; 279 } 280 281 uint32_t fixedCount = definition->fixedCount; 282 if (fixedCount > 0 && fixedCount != count) { 283 ALOGE("%s: Invalid count %d for tag %x (expects %d).", __FUNCTION__, count, tag, 284 fixedCount); 285 return BAD_VALUE; 286 } 287 288 TagType fixedType = definition->defaultType; 289 if (TiffEntry::forceValidType(fixedType, data) == NULL) { 290 ALOGE("%s: Invalid type used for tag value for tag %x.", __FUNCTION__, tag); 291 return BAD_TYPE; 292 } 293 294 *outEntry = new TiffEntryImpl<T>(tag, fixedType, count, 295 definition->fixedEndian, data); 296 297 return OK; 298 } 299 300 template<typename T> 301 status_t TiffWriter::addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd) { 302 sp<TiffEntry> outEntry; 303 304 status_t ret = buildEntry<T>(tag, count, data, &outEntry); 305 if (ret != OK) { 306 ALOGE("%s: Could not build entry for tag %x.", __FUNCTION__, tag); 307 return ret; 308 } 309 310 return addEntry(outEntry, ifd); 311 } 312 313 template<typename T> 314 sp<TiffEntry> TiffWriter::uncheckedBuildEntry(uint16_t tag, TagType type, uint32_t count, 315 Endianness end, const T* data) { 316 TiffEntryImpl<T>* entry = new TiffEntryImpl<T>(tag, type, count, end, data); 317 return sp<TiffEntry>(entry); 318 } 319 320 } /*namespace img_utils*/ 321 } /*namespace android*/ 322 323 324 #endif /*IMG_UTILS_TIFF_WRITER_H*/ 325