From 4510de26e5361f3a9f07057ec6f26483c888c1fa Mon Sep 17 00:00:00 2001 From: Ruben Brunk Date: Wed, 28 May 2014 18:42:37 -0700 Subject: DNG: Update TiffWriter to handle thumbnails and SubIfds. - Fix SubIfd handling. - Add StripSources, convenience functions for writing image strips. - Update Input classes to use with JNI. - Add skip method. - Add tag definitions for GPS tags. - Add name string to tag definitions. Bug: 15112503 Change-Id: I9535b21261027f6c06a041c1621de8f865a0ad32 --- media/img_utils/src/Android.mk | 1 + media/img_utils/src/FileInput.cpp | 13 +- media/img_utils/src/Input.cpp | 28 +++++ media/img_utils/src/StripSource.cpp | 25 ++++ media/img_utils/src/TiffEntry.cpp | 10 -- media/img_utils/src/TiffEntryImpl.cpp | 19 --- media/img_utils/src/TiffIfd.cpp | 208 +++++++++++++++++++++++++++++++- media/img_utils/src/TiffWriter.cpp | 219 +++++++++++++++++++++++++++++----- 8 files changed, 459 insertions(+), 64 deletions(-) create mode 100644 media/img_utils/src/StripSource.cpp (limited to 'media/img_utils/src') diff --git a/media/img_utils/src/Android.mk b/media/img_utils/src/Android.mk index 80893be..4074849 100644 --- a/media/img_utils/src/Android.mk +++ b/media/img_utils/src/Android.mk @@ -31,6 +31,7 @@ LOCAL_SRC_FILES := \ TiffEntryImpl.cpp \ ByteArrayOutput.cpp \ DngUtils.cpp \ + StripSource.cpp \ LOCAL_SHARED_LIBRARIES := \ libexpat \ diff --git a/media/img_utils/src/FileInput.cpp b/media/img_utils/src/FileInput.cpp index e43fd53..498e715 100644 --- a/media/img_utils/src/FileInput.cpp +++ b/media/img_utils/src/FileInput.cpp @@ -45,19 +45,24 @@ status_t FileInput::open() { return OK; } -size_t FileInput::read(uint8_t* buf, size_t offset, size_t count, status_t* err) { +ssize_t FileInput::read(uint8_t* buf, size_t offset, size_t count) { if (!mOpen) { ALOGE("%s: Could not read file %s, file not open.", __FUNCTION__, mPath.string()); - if (err != NULL) *err = BAD_VALUE; - return 0; + return BAD_VALUE; } size_t bytesRead = ::fread(buf + offset, sizeof(uint8_t), count, mFp); int error = ::ferror(mFp); if (error != 0) { ALOGE("%s: Error %d occurred while reading file %s.", __FUNCTION__, error, mPath.string()); - if (err != NULL) *err = BAD_VALUE; + return BAD_VALUE; } + + // End of file reached + if (::feof(mFp) != 0 && bytesRead == 0) { + return NOT_ENOUGH_DATA; + } + return bytesRead; } diff --git a/media/img_utils/src/Input.cpp b/media/img_utils/src/Input.cpp index 1e51e10..3782014 100644 --- a/media/img_utils/src/Input.cpp +++ b/media/img_utils/src/Input.cpp @@ -20,9 +20,37 @@ namespace android { namespace img_utils { Input::~Input() {} + status_t Input::open() { return OK; } + status_t Input::close() { return OK; } +ssize_t Input::skip(size_t count) { + const size_t SKIP_BUF_SIZE = 1024; + uint8_t skipBuf[SKIP_BUF_SIZE]; + + size_t remaining = count; + while (remaining > 0) { + size_t amt = (SKIP_BUF_SIZE > remaining) ? remaining : SKIP_BUF_SIZE; + ssize_t ret = read(skipBuf, 0, amt); + if (ret < 0) { + if(ret == NOT_ENOUGH_DATA) { + // End of file encountered + if (remaining == count) { + // Read no bytes, return EOF + return NOT_ENOUGH_DATA; + } else { + // Return num bytes read + return count - remaining; + } + } + // Return error code. + return ret; + } + remaining -= ret; + } + return count; +} } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/img_utils/src/StripSource.cpp b/media/img_utils/src/StripSource.cpp new file mode 100644 index 0000000..57b6082 --- /dev/null +++ b/media/img_utils/src/StripSource.cpp @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#include + +namespace android { +namespace img_utils { + +StripSource::~StripSource() {} + +} /*namespace img_utils*/ +} /*namespace android*/ diff --git a/media/img_utils/src/TiffEntry.cpp b/media/img_utils/src/TiffEntry.cpp index e028827..9cea721 100644 --- a/media/img_utils/src/TiffEntry.cpp +++ b/media/img_utils/src/TiffEntry.cpp @@ -32,16 +32,6 @@ TiffEntry::~TiffEntry() {} * * Values with types other than the ones given here should not compile. */ -template<> -const Vector >* TiffEntry::forceValidType > >(TagType type, - const Vector >* value) { - if (type == LONG) { - return value; - } - ALOGE("%s: Value of type 'ifd vector' is not valid for tag with TIFF type %d.", - __FUNCTION__, type); - return NULL; -} template<> const sp* TiffEntry::forceValidType >(TagType type, const sp* value) { diff --git a/media/img_utils/src/TiffEntryImpl.cpp b/media/img_utils/src/TiffEntryImpl.cpp index 6efa458..257c266 100644 --- a/media/img_utils/src/TiffEntryImpl.cpp +++ b/media/img_utils/src/TiffEntryImpl.cpp @@ -15,30 +15,11 @@ */ #include -#include #include namespace android { namespace img_utils { -template<> -size_t TiffEntryImpl::getSize() const { - uint32_t total = 0; - for (uint32_t i = 0; i < mCount; ++i) { - total += mData[i].getSize(); - } - return total; -} - -template<> -status_t TiffEntryImpl::writeData(uint32_t offset, EndianOutput* out) const { - status_t ret = OK; - for (uint32_t i = 0; i < mCount; ++i) { - BAIL_ON_FAIL(mData[i].writeData(offset, out), ret); - } - return ret; -} - } /*namespace img_utils*/ } /*namespace android*/ diff --git a/media/img_utils/src/TiffIfd.cpp b/media/img_utils/src/TiffIfd.cpp index 1b3b40d..3fb00cc 100644 --- a/media/img_utils/src/TiffIfd.cpp +++ b/media/img_utils/src/TiffIfd.cpp @@ -14,8 +14,12 @@ * limitations under the License. */ -#include +#define LOG_TAG "TiffIfd" + +#include #include +#include +#include #include @@ -23,7 +27,7 @@ namespace android { namespace img_utils { TiffIfd::TiffIfd(uint32_t ifdId) - : mNextIfd(), mIfdId(ifdId) {} + : mNextIfd(), mIfdId(ifdId), mStripOffsetsInitialized(false) {} TiffIfd::~TiffIfd() {} @@ -52,6 +56,14 @@ sp TiffIfd::getEntry(uint16_t tag) const { return mEntries[index]; } +void TiffIfd::removeEntry(uint16_t tag) { + ssize_t index = mEntries.indexOfTag(tag); + if (index >= 0) { + mEntries.removeAt(index); + } +} + + void TiffIfd::setNextIfd(const sp& ifd) { mNextIfd = ifd; } @@ -156,6 +168,198 @@ uint32_t TiffIfd::getComparableValue() const { return mIfdId; } +status_t TiffIfd::validateAndSetStripTags() { + sp widthEntry = getEntry(TAG_IMAGEWIDTH); + if (widthEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a ImageWidth tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp heightEntry = getEntry(TAG_IMAGELENGTH); + if (heightEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a ImageLength tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp samplesEntry = getEntry(TAG_SAMPLESPERPIXEL); + if (samplesEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a SamplesPerPixel tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp bitsEntry = getEntry(TAG_BITSPERSAMPLE); + if (bitsEntry == NULL) { + ALOGE("%s: IFD %u doesn't have a BitsPerSample tag set", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t width = *(widthEntry->getData()); + uint32_t height = *(heightEntry->getData()); + uint16_t bitsPerSample = *(bitsEntry->getData()); + uint16_t samplesPerPixel = *(samplesEntry->getData()); + + if ((bitsPerSample % 8) != 0) { + ALOGE("%s: BitsPerSample %d in IFD %u is not byte-aligned.", __FUNCTION__, + bitsPerSample, mIfdId); + return BAD_VALUE; + } + + uint32_t bytesPerSample = bitsPerSample / 8; + + // Choose strip size as close to 8kb as possible without splitting rows. + // If the row length is >8kb, each strip will only contain a single row. + const uint32_t rowLengthBytes = bytesPerSample * samplesPerPixel * width; + const uint32_t idealChunkSize = (1 << 13); // 8kb + uint32_t rowsPerChunk = idealChunkSize / rowLengthBytes; + rowsPerChunk = (rowsPerChunk == 0) ? 1 : rowsPerChunk; + const uint32_t actualChunkSize = rowLengthBytes * rowsPerChunk; + + const uint32_t lastChunkRows = height % rowsPerChunk; + const uint32_t lastChunkSize = lastChunkRows * rowLengthBytes; + + if (actualChunkSize > /*max strip size for TIFF/EP*/65536) { + ALOGE("%s: Strip length too long.", __FUNCTION__); + return BAD_VALUE; + } + + size_t numStrips = height / rowsPerChunk; + + // Add another strip for the incomplete chunk. + if (lastChunkRows > 0) { + numStrips += 1; + } + + // Put each row in it's own strip + uint32_t rowsPerStripVal = rowsPerChunk; + sp rowsPerStrip = TiffWriter::uncheckedBuildEntry(TAG_ROWSPERSTRIP, LONG, 1, + UNDEFINED_ENDIAN, &rowsPerStripVal); + + if (rowsPerStrip == NULL) { + ALOGE("%s: Could not build entry for RowsPerStrip tag.", __FUNCTION__); + return BAD_VALUE; + } + + Vector byteCounts; + + for (size_t i = 0; i < numStrips; ++i) { + if (lastChunkRows > 0 && i == (numStrips - 1)) { + byteCounts.add(lastChunkSize); + } else { + byteCounts.add(actualChunkSize); + } + } + + // Set byte counts for each strip + sp stripByteCounts = TiffWriter::uncheckedBuildEntry(TAG_STRIPBYTECOUNTS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, byteCounts.array()); + + if (stripByteCounts == NULL) { + ALOGE("%s: Could not build entry for StripByteCounts tag.", __FUNCTION__); + return BAD_VALUE; + } + + Vector stripOffsetsVector; + stripOffsetsVector.resize(numStrips); + + // Set uninitialized offsets + sp stripOffsets = TiffWriter::uncheckedBuildEntry(TAG_STRIPOFFSETS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, stripOffsetsVector.array()); + + if (stripOffsets == NULL) { + ALOGE("%s: Could not build entry for StripOffsets tag.", __FUNCTION__); + return BAD_VALUE; + } + + if(addEntry(stripByteCounts) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if(addEntry(rowsPerStrip) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if(addEntry(stripOffsets) != OK) { + ALOGE("%s: Could not add entry for StripByteCounts to IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + mStripOffsetsInitialized = true; + return OK; +} + +bool TiffIfd::uninitializedOffsets() const { + return mStripOffsetsInitialized; +} + +status_t TiffIfd::setStripOffset(uint32_t offset) { + + // Get old offsets and bytecounts + sp oldOffsets = getEntry(TAG_STRIPOFFSETS); + if (oldOffsets == NULL) { + ALOGE("%s: IFD %u does not contain StripOffsets entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + sp stripByteCounts = getEntry(TAG_STRIPBYTECOUNTS); + if (stripByteCounts == NULL) { + ALOGE("%s: IFD %u does not contain StripByteCounts entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t offsetsCount = oldOffsets->getCount(); + uint32_t byteCount = stripByteCounts->getCount(); + if (offsetsCount != byteCount) { + ALOGE("%s: StripOffsets count (%u) doesn't match StripByteCounts count (%u) in IFD %u", + __FUNCTION__, offsetsCount, byteCount, mIfdId); + return BAD_VALUE; + } + + const uint32_t* stripByteCountsArray = stripByteCounts->getData(); + + size_t numStrips = offsetsCount; + + Vector stripOffsets; + + // Calculate updated byte offsets + for (size_t i = 0; i < numStrips; ++i) { + stripOffsets.add(offset); + offset += stripByteCountsArray[i]; + } + + sp newOffsets = TiffWriter::uncheckedBuildEntry(TAG_STRIPOFFSETS, LONG, + static_cast(numStrips), UNDEFINED_ENDIAN, stripOffsets.array()); + + if (newOffsets == NULL) { + ALOGE("%s: Coult not build updated offsets entry in IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + if (addEntry(newOffsets) != OK) { + ALOGE("%s: Failed to add updated offsets entry in IFD %u", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + return OK; +} + +uint32_t TiffIfd::getStripSize() const { + sp stripByteCounts = getEntry(TAG_STRIPBYTECOUNTS); + if (stripByteCounts == NULL) { + ALOGE("%s: IFD %u does not contain StripByteCounts entry.", __FUNCTION__, mIfdId); + return BAD_VALUE; + } + + uint32_t count = stripByteCounts->getCount(); + const uint32_t* byteCounts = stripByteCounts->getData(); + + uint32_t total = 0; + for (size_t i = 0; i < static_cast(count); ++i) { + total += byteCounts[i]; + } + return total; +} + String8 TiffIfd::toString() const { size_t s = mEntries.size(); String8 output; diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp index 2439033..d85289e 100644 --- a/media/img_utils/src/TiffWriter.cpp +++ b/media/img_utils/src/TiffWriter.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include +#define LOG_TAG "TiffWriter" + #include #include #include @@ -55,6 +56,82 @@ TiffWriter::TiffWriter(KeyedVector* enabledDef TiffWriter::~TiffWriter() {} +status_t TiffWriter::write(Output* out, StripSource** sources, size_t sourcesCount, + Endianness end) { + status_t ret = OK; + EndianOutput endOut(out, end); + + if (mIfd == NULL) { + ALOGE("%s: Tiff header is empty.", __FUNCTION__); + return BAD_VALUE; + } + + if (LOG_NDEBUG == 0) { + log(); + } + + uint32_t totalSize = getTotalSize(); + + KeyedVector offsetVector; + + for (size_t i = 0; i < mNamedIfds.size(); ++i) { + if (mNamedIfds[i]->uninitializedOffsets()) { + uint32_t stripSize = mNamedIfds[i]->getStripSize(); + if (mNamedIfds[i]->setStripOffset(totalSize) != OK) { + ALOGE("%s: Could not set strip offsets.", __FUNCTION__); + return BAD_VALUE; + } + totalSize += stripSize; + WORD_ALIGN(totalSize); + offsetVector.add(mNamedIfds.keyAt(i), totalSize); + } + } + + size_t offVecSize = offsetVector.size(); + if (offVecSize != sourcesCount) { + ALOGE("%s: Mismatch between number of IFDs with uninitialized strips (%zu) and" + " sources (%zu).", __FUNCTION__, offVecSize, sourcesCount); + return BAD_VALUE; + } + + BAIL_ON_FAIL(writeFileHeader(endOut), ret); + + uint32_t offset = FILE_HEADER_SIZE; + sp ifd = mIfd; + while(ifd != NULL) { + BAIL_ON_FAIL(ifd->writeData(offset, &endOut), ret); + offset += ifd->getSize(); + ifd = ifd->getNextIfd(); + } + + log(); + + for (size_t i = 0; i < offVecSize; ++i) { + uint32_t ifdKey = offsetVector.keyAt(i); + uint32_t nextOffset = offsetVector[i]; + uint32_t sizeToWrite = mNamedIfds[ifdKey]->getStripSize(); + bool found = false; + for (size_t j = 0; j < sourcesCount; ++j) { + if (sources[j]->getIfd() == ifdKey) { + if ((ret = sources[i]->writeToStream(endOut, sizeToWrite)) != OK) { + ALOGE("%s: Could not write to stream, received %d.", __FUNCTION__, ret); + return ret; + } + ZERO_TILL_WORD(&endOut, sizeToWrite, ret); + found = true; + break; + } + } + if (!found) { + ALOGE("%s: No stream for byte strips for IFD %u", __FUNCTION__, ifdKey); + return BAD_VALUE; + } + assert(nextOffset == endOut.getCurrentOffset()); + } + + return ret; +} + status_t TiffWriter::write(Output* out, Endianness end) { status_t ret = OK; EndianOutput endOut(out, end); @@ -101,48 +178,43 @@ sp TiffWriter::getEntry(uint16_t tag, uint32_t ifd) const { return mNamedIfds[index]->getEntry(tag); } +void TiffWriter::removeEntry(uint16_t tag, uint32_t ifd) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index >= 0) { + mNamedIfds[index]->removeEntry(tag); + } +} -// TODO: Fix this to handle IFD position in chain/sub-IFD tree -status_t TiffWriter::addEntry(const sp& entry) { +status_t TiffWriter::addEntry(const sp& entry, uint32_t ifd) { uint16_t tag = entry->getTag(); const TagDefinition_t* definition = lookupDefinition(tag); if (definition == NULL) { + ALOGE("%s: No definition exists for tag 0x%x.", __FUNCTION__, tag); return BAD_INDEX; } - uint32_t ifdId = 0; // TODO: all in IFD0 for now. - ssize_t index = mNamedIfds.indexOfKey(ifdId); + ssize_t index = mNamedIfds.indexOfKey(ifd); // Add a new IFD if necessary if (index < 0) { - sp ifdEntry = new TiffIfd(ifdId); - if (mIfd == NULL) { - mIfd = ifdEntry; - } - index = mNamedIfds.add(ifdId, ifdEntry); - assert(index >= 0); + ALOGE("%s: No IFD %u exists.", __FUNCTION__, ifd); + return NAME_NOT_FOUND; } sp selectedIfd = mNamedIfds[index]; return selectedIfd->addEntry(entry); } -status_t TiffWriter::uncheckedAddIfd(const sp& ifd) { - mNamedIfds.add(ifd->getId(), ifd); - sp last = findLastIfd(); - if (last == NULL) { - mIfd = ifd; - } else { - last->setNextIfd(ifd); - } - last = ifd->getNextIfd(); - while (last != NULL) { - mNamedIfds.add(last->getId(), last); - last = last->getNextIfd(); +status_t TiffWriter::addStrip(uint32_t ifd) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index < 0) { + ALOGE("%s: Ifd %u doesn't exist, cannot add strip entries.", __FUNCTION__, ifd); + return BAD_VALUE; } - return OK; + sp selected = mNamedIfds[index]; + return selected->validateAndSetStripTags(); } status_t TiffWriter::addIfd(uint32_t ifd) { @@ -151,6 +223,7 @@ status_t TiffWriter::addIfd(uint32_t ifd) { ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd); return BAD_VALUE; } + sp newIfd = new TiffIfd(ifd); if (mIfd == NULL) { mIfd = newIfd; @@ -158,7 +231,83 @@ status_t TiffWriter::addIfd(uint32_t ifd) { sp last = findLastIfd(); last->setNextIfd(newIfd); } - mNamedIfds.add(ifd, newIfd); + + if(mNamedIfds.add(ifd, newIfd) < 0) { + ALOGE("%s: Failed to add new IFD 0x%x.", __FUNCTION__, ifd); + return BAD_VALUE; + } + + return OK; +} + +status_t TiffWriter::addSubIfd(uint32_t parentIfd, uint32_t ifd, SubIfdType type) { + ssize_t index = mNamedIfds.indexOfKey(ifd); + if (index >= 0) { + ALOGE("%s: Ifd with ID 0x%x already exists.", __FUNCTION__, ifd); + return BAD_VALUE; + } + + ssize_t parentIndex = mNamedIfds.indexOfKey(parentIfd); + if (parentIndex < 0) { + ALOGE("%s: Parent IFD with ID 0x%x does not exist.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + sp parent = mNamedIfds[parentIndex]; + sp newIfd = new TiffIfd(ifd); + + uint16_t subIfdTag; + if (type == SUBIFD) { + subIfdTag = TAG_SUBIFDS; + } else if (type == GPSINFO) { + subIfdTag = TAG_GPSINFO; + } else { + ALOGE("%s: Unknown SubIFD type %d.", __FUNCTION__, type); + return BAD_VALUE; + } + + sp subIfds = parent->getEntry(subIfdTag); + if (subIfds == NULL) { + if (buildEntry(subIfdTag, 1, &newIfd, &subIfds) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + } else { + if (type == GPSINFO) { + ALOGE("%s: Cannot add GPSInfo SubIFD to IFD %u, one already exists.", __FUNCTION__, + ifd); + return BAD_VALUE; + } + + Vector > subIfdList; + const sp* oldIfdArray = subIfds->getData >(); + if (subIfdList.appendArray(oldIfdArray, subIfds->getCount()) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + if (subIfdList.add(newIfd) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + uint32_t count = subIfdList.size(); + if (buildEntry(subIfdTag, count, subIfdList.array(), &subIfds) < 0) { + ALOGE("%s: Failed to build SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + } + + if (parent->addEntry(subIfds) < 0) { + ALOGE("%s: Failed to add SubIfd entry in IFD 0x%x.", __FUNCTION__, parentIfd); + return BAD_VALUE; + } + + if(mNamedIfds.add(ifd, newIfd) < 0) { + ALOGE("%s: Failed to add new IFD 0x%x.", __FUNCTION__, ifd); + return BAD_VALUE; + } + return OK; } @@ -180,10 +329,23 @@ uint32_t TiffWriter::getDefaultCount(uint16_t tag) const { return definition->fixedCount; } +bool TiffWriter::hasIfd(uint32_t ifd) const { + ssize_t index = mNamedIfds.indexOfKey(ifd); + return index >= 0; +} + bool TiffWriter::checkIfDefined(uint16_t tag) const { return lookupDefinition(tag) != NULL; } +const char* TiffWriter::getTagName(uint16_t tag) const { + const TagDefinition_t* definition = lookupDefinition(tag); + if (definition == NULL) { + return NULL; + } + return definition->tagName; +} + sp TiffWriter::findLastIfd() { sp ifd = mIfd; while(ifd != NULL) { @@ -221,10 +383,9 @@ uint32_t TiffWriter::getTotalSize() const { void TiffWriter::log() const { ALOGI("%s: TiffWriter:", __FUNCTION__); - sp ifd = mIfd; - while(ifd != NULL) { - ifd->log(); - ifd = ifd->getNextIfd(); + size_t length = mNamedIfds.size(); + for (size_t i = 0; i < length; ++i) { + mNamedIfds[i]->log(); } } -- cgit v1.1