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>
buildEntry(uint16_t tag,uint32_t count,const T * data,sp<TiffEntry> * outEntry)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>
addEntry(uint16_t tag,uint32_t count,const T * data,uint32_t ifd)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>
uncheckedBuildEntry(uint16_t tag,TagType type,uint32_t count,Endianness end,const T * data)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