summaryrefslogtreecommitdiffstats
path: root/media/img_utils/include/img_utils/TiffWriter.h
blob: b7af23995d9695518f78ff8ac70dd1eda3f55102 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/*
 * 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*/