blob: b7af23995d9695518f78ff8ac70dd1eda3f55102 [file] [log] [blame]
/*
* 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*/