TiffWriter.h revision 4510de26e5361f3a9f07057ec6f26483c888c1fa
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
35namespace android {
36namespace img_utils {
37
38class TiffEntry;
39class TiffIfd;
40class 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 */
51class 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
271template<typename T>
272status_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
300template<typename T>
301status_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
313template<typename T>
314sp<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