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