| /* |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed 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. |
| */ |
| |
| #ifndef IMG_UTILS_TIFF_WRITER_H |
| #define IMG_UTILS_TIFF_WRITER_H |
| |
| #include <img_utils/EndianUtils.h> |
| #include <img_utils/StripSource.h> |
| #include <img_utils/TiffEntryImpl.h> |
| #include <img_utils/TagDefinitions.h> |
| #include <img_utils/TiffIfd.h> |
| |
| #include <utils/Log.h> |
| #include <utils/Errors.h> |
| #include <utils/StrongPointer.h> |
| #include <utils/KeyedVector.h> |
| #include <utils/Vector.h> |
| |
| #include <cutils/compiler.h> |
| #include <stdint.h> |
| |
| namespace android { |
| namespace img_utils { |
| |
| class TiffEntry; |
| class TiffIfd; |
| class Output; |
| |
| /** |
| * This class holds a collection of TIFF IFDs that can be written as a |
| * complete DNG file header. |
| * |
| * This maps to the TIFF header structure that is logically composed of: |
| * - An 8-byte file header containing an endianness indicator, the TIFF |
| * file marker, and the offset to the first IFD. |
| * - A list of TIFF IFD structures. |
| */ |
| class ANDROID_API TiffWriter : public LightRefBase<TiffWriter> { |
| public: |
| enum SubIfdType { |
| SUBIFD = 0, |
| GPSINFO |
| }; |
| |
| /** |
| * Constructs a TiffWriter with the default tag mappings. This enables |
| * all of the tags defined in TagDefinitions.h, and uses the following |
| * mapping precedence to resolve collisions: |
| * (highest precedence) TIFF/EP > DNG > EXIF 2.3 > TIFF 6.0 |
| */ |
| TiffWriter(); |
| |
| /** |
| * Constructs a TiffWriter with the given tag mappings. The mapping |
| * precedence will be in the order that the definition maps are given, |
| * where the lower index map gets precedence. |
| * |
| * This can be used with user-defined definitions, or definitions form |
| * TagDefinitions.h |
| * |
| * The enabledDefinitions mapping object is owned by the caller, and must |
| * stay alive for the lifespan of the constructed TiffWriter object. |
| */ |
| TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions, |
| size_t length); |
| |
| virtual ~TiffWriter(); |
| |
| /** |
| * Write a TIFF header containing each IFD set. This will recursively |
| * write all SubIFDs and tags. |
| * |
| * Any StripSources passed in will be written to the output as image strips |
| * at the appropriate offests. The StripByteCounts, RowsPerStrip, and |
| * StripOffsets tags must be set to use this. To set these tags in a |
| * given IFD, use the addStrip method. |
| * |
| * Returns OK on success, or a negative error code on failure. |
| */ |
| virtual status_t write(Output* out, StripSource** sources, size_t sourcesCount, |
| Endianness end = LITTLE); |
| |
| /** |
| * Write a TIFF header containing each IFD set. This will recursively |
| * write all SubIFDs and tags. |
| * |
| * Image data for strips or tiles must be written separately at the |
| * appropriate offsets. These offsets must not fall within the file |
| * header written this way. The size of the header written is given |
| * by the getTotalSize() method. |
| * |
| * Returns OK on success, or a negative error code on failure. |
| */ |
| virtual status_t write(Output* out, Endianness end = LITTLE); |
| |
| /** |
| * Get the total size in bytes of the TIFF header. This includes all |
| * IFDs, tags, and values set for this TiffWriter. |
| */ |
| virtual uint32_t getTotalSize() const; |
| |
| /** |
| * Add an entry to the IFD with the given ID. |
| * |
| * Returns OK on success, or a negative error code on failure. Valid |
| * error codes for this method are: |
| * - BAD_INDEX - The given tag doesn't exist. |
| * - BAD_VALUE - The given count doesn't match the required count for |
| * this tag. |
| * - BAD_TYPE - The type of the given data isn't compatible with the |
| * type required for this tag. |
| * - NAME_NOT_FOUND - No ifd exists with the given ID. |
| */ |
| virtual status_t addEntry(const sp<TiffEntry>& entry, uint32_t ifd); |
| |
| /** |
| * Build an entry for a known tag and add it to the IFD with the given ID. |
| * This tag must be defined in one of the definition vectors this TIFF writer |
| * was constructed with. The count and type are validated. |
| * |
| * Returns OK on success, or a negative error code on failure. Valid |
| * error codes for this method are: |
| * - BAD_INDEX - The given tag doesn't exist. |
| * - BAD_VALUE - The given count doesn't match the required count for |
| * this tag. |
| * - BAD_TYPE - The type of the given data isn't compatible with the |
| * type required for this tag. |
| * - NAME_NOT_FOUND - No ifd exists with the given ID. |
| */ |
| template<typename T> |
| status_t addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd); |
| |
| /** |
| * Build an entry for a known tag. This tag must be one of the tags |
| * defined in one of the definition vectors this TIFF writer was constructed |
| * with. The count and type are validated. If this succeeds, the resulting |
| * entry will be placed in the outEntry pointer. |
| * |
| * Returns OK on success, or a negative error code on failure. Valid |
| * error codes for this method are: |
| * - BAD_INDEX - The given tag doesn't exist. |
| * - BAD_VALUE - The given count doesn't match the required count for |
| * this tag. |
| * - BAD_TYPE - The type of the given data isn't compatible with the |
| * type required for this tag. |
| */ |
| template<typename T> |
| status_t buildEntry(uint16_t tag, uint32_t count, const T* data, |
| /*out*/sp<TiffEntry>* outEntry) const; |
| |
| /** |
| * Convenience function to set the strip related tags for a given IFD. |
| * |
| * Call this before using a StripSource as an input to write. |
| * The following tags must be set before calling this method: |
| * - ImageWidth |
| * - ImageLength |
| * - SamplesPerPixel |
| * - BitsPerSample |
| * |
| * Returns OK on success, or a negative error code. |
| */ |
| virtual status_t addStrip(uint32_t ifd); |
| |
| /** |
| * Return the TIFF entry with the given tag ID in the IFD with the given ID, |
| * or an empty pointer if none exists. |
| */ |
| virtual sp<TiffEntry> getEntry(uint16_t tag, uint32_t ifd) const; |
| |
| /** |
| * Remove the TIFF entry with the given tag ID in the given IFD if it exists. |
| */ |
| virtual void removeEntry(uint16_t tag, uint32_t ifd); |
| |
| /** |
| * Create an empty IFD with the given ID and add it to the end of the |
| * list of IFDs. |
| */ |
| virtual status_t addIfd(uint32_t ifd); |
| |
| /** |
| * Create an empty IFD with the given ID and add it as a SubIfd of the |
| * parent IFD. |
| */ |
| virtual status_t addSubIfd(uint32_t parentIfd, uint32_t ifd, SubIfdType type = SUBIFD); |
| |
| /** |
| * Returns the default type for the given tag ID. |
| */ |
| virtual TagType getDefaultType(uint16_t tag) const; |
| |
| /** |
| * Returns the default count for a given tag ID, or 0 if this |
| * tag normally has a variable count. |
| */ |
| virtual uint32_t getDefaultCount(uint16_t tag) const; |
| |
| /** |
| * Returns true if an IFD with the given ID exists. |
| */ |
| virtual bool hasIfd(uint32_t ifd) const; |
| |
| /** |
| * Returns true if a definition exist for the given tag ID. |
| */ |
| virtual bool checkIfDefined(uint16_t tag) const; |
| |
| /** |
| * Returns the name of the tag if a definition exists for the given tag |
| * ID, or null if no definition exists. |
| */ |
| virtual const char* getTagName(uint16_t tag) const; |
| |
| /** |
| * Print the currently configured IFDs and entries to logcat. |
| */ |
| virtual void log() const; |
| |
| /** |
| * Build an entry. No validation is done. |
| * |
| * WARNING: Using this method can result in creating poorly formatted |
| * TIFF files. |
| * |
| * Returns a TiffEntry with the given tag, type, count, endianness, |
| * and data. |
| */ |
| template<typename T> |
| static sp<TiffEntry> uncheckedBuildEntry(uint16_t tag, TagType type, |
| uint32_t count, Endianness end, const T* data); |
| |
| /** |
| * Utility function to build atag-to-definition mapping from a given |
| * array of tag definitions. |
| */ |
| static KeyedVector<uint16_t, const TagDefinition_t*> buildTagMap( |
| const TagDefinition_t* definitions, size_t length); |
| |
| protected: |
| enum { |
| DEFAULT_NUM_TAG_MAPS = 4, |
| }; |
| |
| sp<TiffIfd> findLastIfd(); |
| status_t writeFileHeader(EndianOutput& out); |
| const TagDefinition_t* lookupDefinition(uint16_t tag) const; |
| status_t calculateOffsets(); |
| |
| sp<TiffIfd> mIfd; |
| KeyedVector<uint32_t, sp<TiffIfd> > mNamedIfds; |
| KeyedVector<uint16_t, const TagDefinition_t*>* mTagMaps; |
| size_t mNumTagMaps; |
| |
| static KeyedVector<uint16_t, const TagDefinition_t*> sTagMaps[]; |
| }; |
| |
| template<typename T> |
| status_t TiffWriter::buildEntry(uint16_t tag, uint32_t count, const T* data, |
| /*out*/sp<TiffEntry>* outEntry) const { |
| const TagDefinition_t* definition = lookupDefinition(tag); |
| |
| if (definition == NULL) { |
| ALOGE("%s: No such tag exists for id %x.", __FUNCTION__, tag); |
| return BAD_INDEX; |
| } |
| |
| uint32_t fixedCount = definition->fixedCount; |
| if (fixedCount > 0 && fixedCount != count) { |
| ALOGE("%s: Invalid count %d for tag %x (expects %d).", __FUNCTION__, count, tag, |
| fixedCount); |
| return BAD_VALUE; |
| } |
| |
| TagType fixedType = definition->defaultType; |
| if (TiffEntry::forceValidType(fixedType, data) == NULL) { |
| ALOGE("%s: Invalid type used for tag value for tag %x.", __FUNCTION__, tag); |
| return BAD_TYPE; |
| } |
| |
| *outEntry = new TiffEntryImpl<T>(tag, fixedType, count, |
| definition->fixedEndian, data); |
| |
| return OK; |
| } |
| |
| template<typename T> |
| status_t TiffWriter::addEntry(uint16_t tag, uint32_t count, const T* data, uint32_t ifd) { |
| sp<TiffEntry> outEntry; |
| |
| status_t ret = buildEntry<T>(tag, count, data, &outEntry); |
| if (ret != OK) { |
| ALOGE("%s: Could not build entry for tag %x.", __FUNCTION__, tag); |
| return ret; |
| } |
| |
| return addEntry(outEntry, ifd); |
| } |
| |
| template<typename T> |
| sp<TiffEntry> TiffWriter::uncheckedBuildEntry(uint16_t tag, TagType type, uint32_t count, |
| Endianness end, const T* data) { |
| TiffEntryImpl<T>* entry = new TiffEntryImpl<T>(tag, type, count, end, data); |
| return sp<TiffEntry>(entry); |
| } |
| |
| } /*namespace img_utils*/ |
| } /*namespace android*/ |
| |
| |
| #endif /*IMG_UTILS_TIFF_WRITER_H*/ |