TiffWriter.cpp revision e507721000647a7d8afe44c63ef7fd04ef8971b1
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#include <img_utils/TiffIfd.h>
18#include <img_utils/TiffHelpers.h>
19#include <img_utils/TiffWriter.h>
20#include <img_utils/TagDefinitions.h>
21
22#include <assert.h>
23
24namespace android {
25namespace img_utils {
26
27KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::buildTagMap(
28            const TagDefinition_t* definitions, size_t length) {
29    KeyedVector<uint16_t, const TagDefinition_t*> map;
30    for(size_t i = 0; i < length; ++i) {
31        map.add(definitions[i].tagId, definitions + i);
32    }
33    return map;
34}
35
36#define COMPARE(op) \
37bool Orderable::operator op (const Orderable& orderable) const { \
38    return getComparableValue() op orderable.getComparableValue(); \
39}
40
41#define ARRAY_SIZE(array) \
42    (sizeof(array) / sizeof(array[0]))
43
44KeyedVector<uint16_t, const TagDefinition_t*> TiffWriter::sTagMaps[] = {
45    buildTagMap(TIFF_EP_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_EP_TAG_DEFINITIONS)),
46    buildTagMap(DNG_TAG_DEFINITIONS, ARRAY_SIZE(DNG_TAG_DEFINITIONS)),
47    buildTagMap(EXIF_2_3_TAG_DEFINITIONS, ARRAY_SIZE(EXIF_2_3_TAG_DEFINITIONS)),
48    buildTagMap(TIFF_6_TAG_DEFINITIONS, ARRAY_SIZE(TIFF_6_TAG_DEFINITIONS))
49};
50
51TiffWriter::TiffWriter() : mTagMaps(sTagMaps), mNumTagMaps(DEFAULT_NUM_TAG_MAPS) {}
52
53TiffWriter::TiffWriter(KeyedVector<uint16_t, const TagDefinition_t*>* enabledDefinitions,
54        size_t length) : mTagMaps(enabledDefinitions), mNumTagMaps(length) {}
55
56TiffWriter::~TiffWriter() {}
57
58status_t TiffWriter::write(Output* out, Endianness end) {
59    status_t ret = OK;
60    EndianOutput endOut(out, end);
61
62    if (mIfd == NULL) {
63        ALOGE("%s: Tiff header is empty.", __FUNCTION__);
64        return BAD_VALUE;
65    }
66    BAIL_ON_FAIL(writeFileHeader(endOut), ret);
67
68    uint32_t offset = FILE_HEADER_SIZE;
69    sp<TiffIfd> ifd = mIfd;
70    while(ifd != NULL) {
71        BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret);
72        offset += ifd->getSize();
73        ifd = ifd->getNextIfd();
74    }
75    return ret;
76}
77
78
79const TagDefinition_t* TiffWriter::lookupDefinition(uint16_t tag) const {
80    const TagDefinition_t* definition = NULL;
81    for (size_t i = 0; i < mNumTagMaps; ++i) {
82        ssize_t index = mTagMaps[i].indexOfKey(tag);
83        if (index >= 0) {
84            definition = mTagMaps[i][index];
85            break;
86        }
87    }
88
89    if (definition == NULL) {
90        ALOGE("%s: No definition exists for tag with id %x.", __FUNCTION__, tag);
91    }
92    return definition;
93}
94
95sp<TiffEntry> TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const {
96    ssize_t index = mNamedIfds.indexOfKey(ifd);
97    if (index < 0) {
98        ALOGE("%s: No IFD %d set for this writer.", __FUNCTION__, ifd);
99        return NULL;
100    }
101    return mNamedIfds[index]->getEntry(tag);
102}
103
104
105// TODO: Fix this to handle IFD position in chain/sub-IFD tree
106status_t TiffWriter::addEntry(const sp<TiffEntry>& entry) {
107    uint16_t tag = entry->getTag();
108
109    const TagDefinition_t* definition = lookupDefinition(tag);
110
111    if (definition == NULL) {
112        return BAD_INDEX;
113    }
114    uint32_t ifdId = 0;  // TODO: all in IFD0 for now.
115
116    ssize_t index = mNamedIfds.indexOfKey(ifdId);
117
118    // Add a new IFD if necessary
119    if (index < 0) {
120        sp<TiffIfd> ifdEntry = new TiffIfd(ifdId);
121        if (mIfd == NULL) {
122            mIfd = ifdEntry;
123        }
124        index = mNamedIfds.add(ifdId, ifdEntry);
125        assert(index >= 0);
126    }
127
128    sp<TiffIfd> selectedIfd  = mNamedIfds[index];
129    return selectedIfd->addEntry(entry);
130}
131
132status_t TiffWriter::uncheckedAddIfd(const sp<TiffIfd>& ifd) {
133    mNamedIfds.add(ifd->getId(), ifd);
134    sp<TiffIfd> last = findLastIfd();
135    if (last == NULL) {
136        mIfd = ifd;
137    } else {
138        last->setNextIfd(ifd);
139    }
140    last = ifd->getNextIfd();
141    while (last != NULL) {
142        mNamedIfds.add(last->getId(), last);
143        last = last->getNextIfd();
144    }
145    return OK;
146}
147
148status_t TiffWriter::addIfd(uint32_t ifd) {
149    ssize_t index = mNamedIfds.indexOfKey(ifd);
150    if (index >= 0) {
151        ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd);
152        return BAD_VALUE;
153    }
154    sp<TiffIfd> newIfd = new TiffIfd(ifd);
155    if (mIfd == NULL) {
156        mIfd = newIfd;
157    } else {
158        sp<TiffIfd> last = findLastIfd();
159        last->setNextIfd(newIfd);
160    }
161    mNamedIfds.add(ifd, newIfd);
162    return OK;
163}
164
165TagType TiffWriter::getDefaultType(uint16_t tag) const {
166    const TagDefinition_t* definition = lookupDefinition(tag);
167    if (definition == NULL) {
168        ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag);
169        return UNKNOWN_TAGTYPE;
170    }
171    return definition->defaultType;
172}
173
174uint32_t TiffWriter::getDefaultCount(uint16_t tag) const {
175    const TagDefinition_t* definition = lookupDefinition(tag);
176    if (definition == NULL) {
177        ALOGE("%s: Could not find definition for tag %x", __FUNCTION__, tag);
178        return 0;
179    }
180    return definition->fixedCount;
181}
182
183bool TiffWriter::checkIfDefined(uint16_t tag) const {
184    return lookupDefinition(tag) != NULL;
185}
186
187sp<TiffIfd> TiffWriter::findLastIfd() {
188    sp<TiffIfd> ifd = mIfd;
189    while(ifd != NULL) {
190        sp<TiffIfd> nextIfd = ifd->getNextIfd();
191        if (nextIfd == NULL) {
192            break;
193        }
194        ifd = nextIfd;
195    }
196    return ifd;
197}
198
199status_t TiffWriter::writeFileHeader(EndianOutput& out) {
200    status_t ret = OK;
201    uint16_t endMarker = (out.getEndianness() == BIG) ? BIG_ENDIAN_MARKER : LITTLE_ENDIAN_MARKER;
202    BAIL_ON_FAIL(out.write(&endMarker, 0, 1), ret);
203
204    uint16_t tiffMarker = TIFF_FILE_MARKER;
205    BAIL_ON_FAIL(out.write(&tiffMarker, 0, 1), ret);
206
207    uint32_t offsetMarker = FILE_HEADER_SIZE;
208    BAIL_ON_FAIL(out.write(&offsetMarker, 0, 1), ret);
209    return ret;
210}
211
212uint32_t TiffWriter::getTotalSize() const {
213    uint32_t totalSize = FILE_HEADER_SIZE;
214    sp<TiffIfd> ifd = mIfd;
215    while(ifd != NULL) {
216        totalSize += ifd->getSize();
217        ifd = ifd->getNextIfd();
218    }
219    return totalSize;
220}
221
222void TiffWriter::log() const {
223    ALOGI("%s: TiffWriter:", __FUNCTION__);
224    sp<TiffIfd> ifd = mIfd;
225    while(ifd != NULL) {
226        ifd->log();
227        ifd = ifd->getNextIfd();
228    }
229}
230
231} /*namespace img_utils*/
232} /*namespace android*/
233