From 727894d57561cfdac76b74e2469ce86cde9cbec5 Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Tue, 27 Jul 2021 13:13:55 -0700 Subject: [PATCH] DngCreator: Add thumbnail TIFF tags in subIFD1 Always keep the main image TIFF tags as part of IFD0. If thumbnail is present, then insert and use subIFD1 for all additional thumbnail related tags. Bug: 194703299 Test: atest -c cts/tests/camera/src/android/hardware/camera2/cts/DngCreatorTest.java Change-Id: Ia50ff98f16871abf6d774506133803c251b46d69 --- .../android_hardware_camera2_DngCreator.cpp | 130 +++++------------- 1 file changed, 37 insertions(+), 93 deletions(-) diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index b4b727bcdcf2f..db33863ddd772 100644 --- a/core/jni/android_hardware_camera2_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -920,26 +920,6 @@ static bool validateDngHeader(JNIEnv* env, sp writer, return true; } -static status_t moveEntries(sp writer, uint32_t ifdFrom, uint32_t ifdTo, - const Vector& entries) { - for (size_t i = 0; i < entries.size(); ++i) { - uint16_t tagId = entries[i]; - sp entry = writer->getEntry(tagId, ifdFrom); - if (entry.get() == nullptr) { - ALOGE("%s: moveEntries failed, entry %u not found in IFD %u", __FUNCTION__, tagId, - ifdFrom); - return BAD_VALUE; - } - if (writer->addEntry(entry, ifdTo) != OK) { - ALOGE("%s: moveEntries failed, could not add entry %u to IFD %u", __FUNCTION__, tagId, - ifdFrom); - return BAD_VALUE; - } - writer->removeEntry(tagId, ifdFrom); - } - return OK; -} - /** * Write CFA pattern for given CFA enum into cfaOut. cfaOut must have length >= 4. * Returns OK on success, or a negative error code if the CFA enum was invalid. @@ -2255,66 +2235,27 @@ static sp DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image } } - Vector tagsToMove; - tagsToMove.add(TAG_NEWSUBFILETYPE); - tagsToMove.add(TAG_ACTIVEAREA); - tagsToMove.add(TAG_BITSPERSAMPLE); - tagsToMove.add(TAG_COMPRESSION); - tagsToMove.add(TAG_IMAGEWIDTH); - tagsToMove.add(TAG_IMAGELENGTH); - tagsToMove.add(TAG_PHOTOMETRICINTERPRETATION); - tagsToMove.add(TAG_BLACKLEVEL); - tagsToMove.add(TAG_BLACKLEVELREPEATDIM); - tagsToMove.add(TAG_SAMPLESPERPIXEL); - tagsToMove.add(TAG_PLANARCONFIGURATION); - if (isBayer) { - tagsToMove.add(TAG_CFAREPEATPATTERNDIM); - tagsToMove.add(TAG_CFAPATTERN); - tagsToMove.add(TAG_CFAPLANECOLOR); - tagsToMove.add(TAG_CFALAYOUT); - } - tagsToMove.add(TAG_XRESOLUTION); - tagsToMove.add(TAG_YRESOLUTION); - tagsToMove.add(TAG_RESOLUTIONUNIT); - tagsToMove.add(TAG_WHITELEVEL); - tagsToMove.add(TAG_DEFAULTSCALE); - tagsToMove.add(TAG_DEFAULTCROPORIGIN); - tagsToMove.add(TAG_DEFAULTCROPSIZE); - - if (nullptr != writer->getEntry(TAG_OPCODELIST2, TIFF_IFD_0).get()) { - tagsToMove.add(TAG_OPCODELIST2); - } - - if (nullptr != writer->getEntry(TAG_OPCODELIST3, TIFF_IFD_0).get()) { - tagsToMove.add(TAG_OPCODELIST3); - } - - if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) { - jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries"); - return nullptr; - } - // Setup thumbnail tags { // Set photometric interpretation uint16_t interpretation = 2; // RGB BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, - &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer); + &interpretation, TIFF_IFD_SUB1), env, TAG_PHOTOMETRICINTERPRETATION, writer); } { // Set planar configuration uint16_t config = 1; // Chunky BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, - TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer); + TIFF_IFD_SUB1), env, TAG_PLANARCONFIGURATION, writer); } { // Set samples per pixel uint16_t samples = SAMPLES_PER_RGB_PIXEL; BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, - TIFF_IFD_0), env, TAG_SAMPLESPERPIXEL, writer); + TIFF_IFD_SUB1), env, TAG_SAMPLESPERPIXEL, writer); } { @@ -2322,7 +2263,7 @@ static sp DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image uint16_t bits[SAMPLES_PER_RGB_PIXEL]; for (int i = 0; i < SAMPLES_PER_RGB_PIXEL; i++) bits[i] = BITS_PER_RGB_SAMPLE; BAIL_IF_INVALID_RET_NULL_SP( - writer->addEntry(TAG_BITSPERSAMPLE, SAMPLES_PER_RGB_PIXEL, bits, TIFF_IFD_0), + writer->addEntry(TAG_BITSPERSAMPLE, SAMPLES_PER_RGB_PIXEL, bits, TIFF_IFD_SUB1), env, TAG_BITSPERSAMPLE, writer); } @@ -2330,55 +2271,55 @@ static sp DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image // Set subfiletype uint32_t subfileType = 1; // Thumbnail image BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, - TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer); + TIFF_IFD_SUB1), env, TAG_NEWSUBFILETYPE, writer); } { // Set compression uint16_t compression = 1; // None BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression, - TIFF_IFD_0), env, TAG_COMPRESSION, writer); + TIFF_IFD_SUB1), env, TAG_COMPRESSION, writer); } { // Set dimensions uint32_t uWidth = nativeContext->getThumbnailWidth(); uint32_t uHeight = nativeContext->getThumbnailHeight(); - BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_0), + BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_SUB1), env, TAG_IMAGEWIDTH, writer); - BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0), - env, TAG_IMAGELENGTH, writer); + BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, + TIFF_IFD_SUB1), env, TAG_IMAGELENGTH, writer); } { // x resolution uint32_t xres[] = { 72, 1 }; // default 72 ppi - BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0), + BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_SUB1), env, TAG_XRESOLUTION, writer); // y resolution uint32_t yres[] = { 72, 1 }; // default 72 ppi - BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0), + BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_SUB1), env, TAG_YRESOLUTION, writer); uint16_t unit = 2; // inches - BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0), - env, TAG_RESOLUTIONUNIT, writer); + BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, + TIFF_IFD_SUB1), env, TAG_RESOLUTIONUNIT, writer); } } if (writer->addStrip(TIFF_IFD_0) != OK) { - ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__); + ALOGE("%s: Could not setup main image strip tags.", __FUNCTION__); jniThrowException(env, "java/lang/IllegalStateException", - "Failed to setup thumbnail strip tags."); + "Failed to setup main image strip tags."); return nullptr; } if (writer->hasIfd(TIFF_IFD_SUB1)) { if (writer->addStrip(TIFF_IFD_SUB1) != OK) { - ALOGE("%s: Could not main image strip tags.", __FUNCTION__); + ALOGE("%s: Could not thumbnail image strip tags.", __FUNCTION__); jniThrowException(env, "java/lang/IllegalStateException", - "Failed to setup main image strip tags."); + "Failed to setup thumbnail image strip tags."); return nullptr; } } @@ -2548,19 +2489,15 @@ static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outSt Vector sources; sp thumbnailSource; uint32_t targetIfd = TIFF_IFD_0; - bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); - if (hasThumbnail) { ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; uint32_t thumbWidth = context->getThumbnailWidth(); - thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0, + thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_SUB1, thumbWidth, context->getThumbnailHeight(), bytesPerPixel, bytesPerPixel * thumbWidth, /*offset*/0, BYTES_PER_RGB_SAMPLE, SAMPLES_PER_RGB_PIXEL); - sources.add(thumbnailSource.get()); - targetIfd = TIFF_IFD_SUB1; } if (isDirect) { @@ -2584,6 +2521,9 @@ static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outSt DirectStripSource stripSource(env, pixelBytes, targetIfd, uWidth, uHeight, pStride, rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); sources.add(&stripSource); + if (thumbnailSource.get() != nullptr) { + sources.add(thumbnailSource.get()); + } status_t ret = OK; if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { @@ -2601,6 +2541,9 @@ static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outSt InputStripSource stripSource(env, *inBuf, targetIfd, uWidth, uHeight, pStride, rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); sources.add(&stripSource); + if (thumbnailSource.get() != nullptr) { + sources.add(thumbnailSource.get()); + } status_t ret = OK; if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { @@ -2612,6 +2555,7 @@ static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outSt return; } } + } static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream, @@ -2654,20 +2598,8 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject sp thumbnailSource; uint32_t targetIfd = TIFF_IFD_0; - bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); Vector sources; - if (hasThumbnail) { - ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); - uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; - uint32_t width = context->getThumbnailWidth(); - thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0, - width, context->getThumbnailHeight(), bytesPerPixel, - bytesPerPixel * width, /*offset*/0, BYTES_PER_RGB_SAMPLE, - SAMPLES_PER_RGB_PIXEL); - sources.add(thumbnailSource.get()); - targetIfd = TIFF_IFD_SUB1; - } sp in = new JniInputStream(env, inStream); @@ -2676,6 +2608,18 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject rowStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); sources.add(&stripSource); + bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); + if (hasThumbnail) { + ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); + uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; + uint32_t width = context->getThumbnailWidth(); + thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_SUB1, + width, context->getThumbnailHeight(), bytesPerPixel, + bytesPerPixel * width, /*offset*/0, BYTES_PER_RGB_SAMPLE, + SAMPLES_PER_RGB_PIXEL); + sources.add(thumbnailSource.get()); + } + status_t ret = OK; if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { ALOGE("%s: write failed with error %d.", __FUNCTION__, ret);