1e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk/*
2e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * Copyright 2014 The Android Open Source Project
3e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk *
4e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * you may not use this file except in compliance with the License.
6e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * You may obtain a copy of the License at
7e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk *
8e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk *
10e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * Unless required by applicable law or agreed to in writing, software
11e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * See the License for the specific language governing permissions and
14e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk * limitations under the License.
15e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk */
16e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
174510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk#define LOG_TAG "TiffIfd"
184510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
194510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk#include <img_utils/TagDefinitions.h>
20e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk#include <img_utils/TiffHelpers.h>
214510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk#include <img_utils/TiffIfd.h>
224510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk#include <img_utils/TiffWriter.h>
23e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
24e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk#include <utils/Log.h>
25e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
26e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunknamespace android {
27e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunknamespace img_utils {
28e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
29e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkTiffIfd::TiffIfd(uint32_t ifdId)
304510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        : mNextIfd(), mIfdId(ifdId), mStripOffsetsInitialized(false) {}
31e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
32e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkTiffIfd::~TiffIfd() {}
33e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
34e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkstatus_t TiffIfd::addEntry(const sp<TiffEntry>& entry) {
35e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    size_t size = mEntries.size();
36e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (size >= MAX_IFD_ENTRIES) {
37272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk        ALOGW("%s: Failed to add entry for tag 0x%x to IFD %u, too many entries in IFD!",
38e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk                __FUNCTION__, entry->getTag(), mIfdId);
39e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_INDEX;
40e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
41e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
42e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (mEntries.add(entry) < 0) {
43272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk        ALOGW("%s: Failed to add entry for tag 0x%x to ifd %u.", __FUNCTION__, entry->getTag(),
44e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk                mIfdId);
45e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_INDEX;
46e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
47e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return OK;
48e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
49e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
50e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunksp<TiffEntry> TiffIfd::getEntry(uint16_t tag) const {
51e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    ssize_t index = mEntries.indexOfTag(tag);
52e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (index < 0) {
53272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk        ALOGW("%s: No entry for tag 0x%x in ifd %u.", __FUNCTION__, tag, mIfdId);
54e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return NULL;
55e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
56e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return mEntries[index];
57e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
58e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
594510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkvoid TiffIfd::removeEntry(uint16_t tag) {
604510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    ssize_t index = mEntries.indexOfTag(tag);
614510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (index >= 0) {
624510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        mEntries.removeAt(index);
634510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
644510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
654510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
664510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
67e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkvoid TiffIfd::setNextIfd(const sp<TiffIfd>& ifd) {
68e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    mNextIfd = ifd;
69e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
70e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
71e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunksp<TiffIfd> TiffIfd::getNextIfd() const {
72e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return mNextIfd;
73e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
74e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
75e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkuint32_t TiffIfd::checkAndGetOffset(uint32_t offset) const {
76e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    size_t size = mEntries.size();
77e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
78e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (size > MAX_IFD_ENTRIES) {
79272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk        ALOGW("%s: Could not calculate IFD offsets, IFD %u contains too many entries.",
80e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk                __FUNCTION__, mIfdId);
81e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_OFFSET;
82e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
83e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
84e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (size <= 0) {
85272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk        ALOGW("%s: Could not calculate IFD offsets, IFD %u contains no entries.", __FUNCTION__,
86e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk                mIfdId);
87e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_OFFSET;
88e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
89e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
90e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (offset == BAD_OFFSET) {
91272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk        ALOGW("%s: Could not calculate IFD offsets, IFD %u had a bad initial offset.",
92e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk                __FUNCTION__, mIfdId);
93e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_OFFSET;
94e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
95e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
96e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint32_t ifdSize = calculateIfdSize(size);
97e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    WORD_ALIGN(ifdSize);
98e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return offset + ifdSize;
99e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
100e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
101e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkstatus_t TiffIfd::writeData(uint32_t offset, /*out*/EndianOutput* out) const {
102e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    assert((offset % TIFF_WORD_SIZE) == 0);
103e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    status_t ret = OK;
104e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
105e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    ALOGV("%s: IFD %u written to offset %u", __FUNCTION__, mIfdId, offset );
106e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint32_t valueOffset = checkAndGetOffset(offset);
107e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    if (valueOffset == 0) {
108e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        return BAD_VALUE;
109e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
110e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
111e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    size_t size = mEntries.size();
112e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
113e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    // Writer IFD header (2 bytes, number of entries).
114e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint16_t header = static_cast<uint16_t>(size);
115e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    BAIL_ON_FAIL(out->write(&header, 0, 1), ret);
116e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
117e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    // Write tag entries
118e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    for (size_t i = 0; i < size; ++i) {
119e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        BAIL_ON_FAIL(mEntries[i]->writeTagInfo(valueOffset, out), ret);
120e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        valueOffset += mEntries[i]->getSize();
121e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
122e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
123e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    // Writer IFD footer (4 bytes, offset to next IFD).
124e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint32_t footer = (mNextIfd != NULL) ? offset + getSize() : 0;
125e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    BAIL_ON_FAIL(out->write(&footer, 0, 1), ret);
126e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
127e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    assert(out->getCurrentOffset() == offset + calculateIfdSize(size));
128e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
129e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    // Write zeroes till word aligned
130e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    ZERO_TILL_WORD(out, calculateIfdSize(size), ret);
131e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
132e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    // Write values for each tag entry
133e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    for (size_t i = 0; i < size; ++i) {
134e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        size_t last = out->getCurrentOffset();
135e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        // Only write values that are too large to fit in the 12-byte TIFF entry
136e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        if (mEntries[i]->getSize() > OFFSET_SIZE) {
137e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk            BAIL_ON_FAIL(mEntries[i]->writeData(out->getCurrentOffset(), out), ret);
138e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        }
139e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        size_t next = out->getCurrentOffset();
140e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        size_t diff = (next - last);
141e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        size_t actual = mEntries[i]->getSize();
142e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        if (diff != actual) {
143272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk            ALOGW("Sizes do not match for tag %x. Expected %zu, received %zu",
144e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk                    mEntries[i]->getTag(), actual, diff);
145e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        }
146e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
147e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
148e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    assert(out->getCurrentOffset() == offset + getSize());
149e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
150e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return ret;
151e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
152e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
153272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunksize_t TiffIfd::getSize() const {
154e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    size_t size = mEntries.size();
155e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    uint32_t total = calculateIfdSize(size);
156e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    WORD_ALIGN(total);
157e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    for (size_t i = 0; i < size; ++i) {
158e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        total += mEntries[i]->getSize();
159e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
160e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return total;
161e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
162e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
163e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkuint32_t TiffIfd::getId() const {
164e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return mIfdId;
165e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
166e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
167e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkuint32_t TiffIfd::getComparableValue() const {
168e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return mIfdId;
169e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
170e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
1714510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkstatus_t TiffIfd::validateAndSetStripTags() {
1724510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> widthEntry = getEntry(TAG_IMAGEWIDTH);
1734510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (widthEntry == NULL) {
1744510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: IFD %u doesn't have a ImageWidth tag set", __FUNCTION__, mIfdId);
1754510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
1764510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
1774510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
1784510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> heightEntry = getEntry(TAG_IMAGELENGTH);
1794510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (heightEntry == NULL) {
1804510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: IFD %u doesn't have a ImageLength tag set", __FUNCTION__, mIfdId);
1814510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
1824510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
1834510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
1844510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> samplesEntry = getEntry(TAG_SAMPLESPERPIXEL);
1854510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (samplesEntry == NULL) {
1864510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: IFD %u doesn't have a SamplesPerPixel tag set", __FUNCTION__, mIfdId);
1874510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
1884510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
1894510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
1904510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> bitsEntry = getEntry(TAG_BITSPERSAMPLE);
1914510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (bitsEntry == NULL) {
1924510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: IFD %u doesn't have a BitsPerSample tag set", __FUNCTION__, mIfdId);
1934510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
1944510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
1954510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
1964510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t width = *(widthEntry->getData<uint32_t>());
1974510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t height = *(heightEntry->getData<uint32_t>());
1984510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint16_t bitsPerSample = *(bitsEntry->getData<uint16_t>());
1994510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint16_t samplesPerPixel = *(samplesEntry->getData<uint16_t>());
2004510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2014510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if ((bitsPerSample % 8) != 0) {
2024510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: BitsPerSample %d in IFD %u is not byte-aligned.", __FUNCTION__,
2034510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk                bitsPerSample, mIfdId);
2044510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2054510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2064510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2074510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t bytesPerSample = bitsPerSample / 8;
2084510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2094510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    // Choose strip size as close to 8kb as possible without splitting rows.
2104510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    // If the row length is >8kb, each strip will only contain a single row.
2114510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    const uint32_t rowLengthBytes = bytesPerSample * samplesPerPixel * width;
2124510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    const uint32_t idealChunkSize = (1 << 13); // 8kb
2134510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t rowsPerChunk = idealChunkSize / rowLengthBytes;
2144510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    rowsPerChunk = (rowsPerChunk == 0) ? 1 : rowsPerChunk;
2154510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    const uint32_t actualChunkSize = rowLengthBytes * rowsPerChunk;
2164510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2174510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    const uint32_t lastChunkRows = height % rowsPerChunk;
2184510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    const uint32_t lastChunkSize = lastChunkRows * rowLengthBytes;
2194510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2204510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (actualChunkSize > /*max strip size for TIFF/EP*/65536) {
2214510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Strip length too long.", __FUNCTION__);
2224510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2234510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2244510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2254510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    size_t numStrips = height / rowsPerChunk;
2264510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2274510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    // Add another strip for the incomplete chunk.
2284510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (lastChunkRows > 0) {
2294510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        numStrips += 1;
2304510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2314510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2324510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    // Put each row in it's own strip
2334510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t rowsPerStripVal = rowsPerChunk;
2344510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> rowsPerStrip = TiffWriter::uncheckedBuildEntry(TAG_ROWSPERSTRIP, LONG, 1,
2354510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            UNDEFINED_ENDIAN, &rowsPerStripVal);
2364510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2374510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (rowsPerStrip == NULL) {
2384510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Could not build entry for RowsPerStrip tag.", __FUNCTION__);
2394510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2404510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2414510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2424510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    Vector<uint32_t> byteCounts;
2434510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2444510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    for (size_t i = 0; i < numStrips; ++i) {
2454510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        if (lastChunkRows > 0 && i == (numStrips - 1)) {
2464510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            byteCounts.add(lastChunkSize);
2474510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        } else {
2484510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            byteCounts.add(actualChunkSize);
2494510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        }
2504510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2514510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2524510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    // Set byte counts for each strip
2534510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> stripByteCounts = TiffWriter::uncheckedBuildEntry(TAG_STRIPBYTECOUNTS, LONG,
2544510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            static_cast<uint32_t>(numStrips), UNDEFINED_ENDIAN, byteCounts.array());
2554510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2564510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (stripByteCounts == NULL) {
2574510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Could not build entry for StripByteCounts tag.", __FUNCTION__);
2584510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2594510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2604510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2614510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    Vector<uint32_t> stripOffsetsVector;
2624510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    stripOffsetsVector.resize(numStrips);
2634510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2644510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    // Set uninitialized offsets
2654510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> stripOffsets = TiffWriter::uncheckedBuildEntry(TAG_STRIPOFFSETS, LONG,
2664510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            static_cast<uint32_t>(numStrips), UNDEFINED_ENDIAN, stripOffsetsVector.array());
2674510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2684510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (stripOffsets == NULL) {
2694510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Could not build entry for StripOffsets tag.", __FUNCTION__);
2704510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2714510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2724510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2734510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if(addEntry(stripByteCounts) != OK) {
2744510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId);
2754510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2764510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2774510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2784510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if(addEntry(rowsPerStrip) != OK) {
2794510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId);
2804510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2814510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2824510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2834510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if(addEntry(stripOffsets) != OK) {
2844510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId);
2854510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
2864510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
2874510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2884510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    mStripOffsetsInitialized = true;
2894510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return OK;
2904510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
2914510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2924510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkbool TiffIfd::uninitializedOffsets() const {
2934510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return mStripOffsetsInitialized;
2944510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
2954510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2964510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkstatus_t TiffIfd::setStripOffset(uint32_t offset) {
2974510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
2984510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    // Get old offsets and bytecounts
2994510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> oldOffsets = getEntry(TAG_STRIPOFFSETS);
3004510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (oldOffsets == NULL) {
3014510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: IFD %u does not contain StripOffsets entry.", __FUNCTION__, mIfdId);
3024510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
3034510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3044510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3054510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> stripByteCounts = getEntry(TAG_STRIPBYTECOUNTS);
3064510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (stripByteCounts == NULL) {
3074510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: IFD %u does not contain StripByteCounts entry.", __FUNCTION__, mIfdId);
3084510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
3094510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3104510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3114510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t offsetsCount = oldOffsets->getCount();
3124510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t byteCount = stripByteCounts->getCount();
3134510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (offsetsCount != byteCount) {
3144510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: StripOffsets count (%u) doesn't match StripByteCounts count (%u) in IFD %u",
3154510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            __FUNCTION__, offsetsCount, byteCount, mIfdId);
3164510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
3174510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3184510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3194510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    const uint32_t* stripByteCountsArray = stripByteCounts->getData<uint32_t>();
3204510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3214510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    size_t numStrips = offsetsCount;
3224510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3234510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    Vector<uint32_t> stripOffsets;
3244510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3254510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    // Calculate updated byte offsets
3264510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    for (size_t i = 0; i < numStrips; ++i) {
3274510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        stripOffsets.add(offset);
3284510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        offset += stripByteCountsArray[i];
3294510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3304510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3314510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> newOffsets = TiffWriter::uncheckedBuildEntry(TAG_STRIPOFFSETS, LONG,
3324510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk            static_cast<uint32_t>(numStrips), UNDEFINED_ENDIAN, stripOffsets.array());
3334510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3344510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (newOffsets == NULL) {
3354510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Coult not build updated offsets entry in IFD %u", __FUNCTION__, mIfdId);
3364510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
3374510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3384510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3394510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (addEntry(newOffsets) != OK) {
3404510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: Failed to add updated offsets entry in IFD %u", __FUNCTION__, mIfdId);
3414510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
3424510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3434510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return OK;
3444510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
3454510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3464510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunkuint32_t TiffIfd::getStripSize() const {
3474510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    sp<TiffEntry> stripByteCounts = getEntry(TAG_STRIPBYTECOUNTS);
3484510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    if (stripByteCounts == NULL) {
3494510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        ALOGE("%s: IFD %u does not contain StripByteCounts entry.", __FUNCTION__, mIfdId);
3504510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        return BAD_VALUE;
3514510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3524510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3534510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t count = stripByteCounts->getCount();
3544510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    const uint32_t* byteCounts = stripByteCounts->getData<uint32_t>();
3554510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
3564510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    uint32_t total = 0;
3574510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    for (size_t i = 0; i < static_cast<size_t>(count); ++i) {
3584510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk        total += byteCounts[i];
3594510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    }
3604510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk    return total;
3614510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk}
3624510de26e5361f3a9f07057ec6f26483c888c1faRuben Brunk
363e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben BrunkString8 TiffIfd::toString() const {
364e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    size_t s = mEntries.size();
365e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    String8 output;
366272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk    output.appendFormat("[ifd: %x, num_entries: %zu, entries:\n", getId(), s);
367e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    for(size_t i = 0; i < mEntries.size(); ++i) {
368e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        output.append("\t");
369e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        output.append(mEntries[i]->toString());
370e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        output.append("\n");
371e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
372e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    output.append(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0));
373e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    return output;
374e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
375e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
376e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunkvoid TiffIfd::log() const {
377e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    size_t s = mEntries.size();
378272b7f26c300d2029f278cf2af523cf94e513b89Ruben Brunk    ALOGI("[ifd: %x, num_entries: %zu, entries:\n", getId(), s);
379e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    for(size_t i = 0; i < s; ++i) {
380e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk        ALOGI("\t%s", mEntries[i]->toString().string());
381e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    }
382e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk    ALOGI(", next_ifd: %x]", ((mNextIfd != NULL) ? mNextIfd->getId() : 0));
383e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk}
384e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk
385e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk} /*namespace img_utils*/
386e507721000647a7d8afe44c63ef7fd04ef8971b1Ruben Brunk} /*namespace android*/
387