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
This commit is contained in:
Emilian Peev
2021-07-27 13:13:55 -07:00
parent 3daec282d7
commit 727894d575

View File

@@ -920,26 +920,6 @@ static bool validateDngHeader(JNIEnv* env, sp<TiffWriter> writer,
return true;
}
static status_t moveEntries(sp<TiffWriter> writer, uint32_t ifdFrom, uint32_t ifdTo,
const Vector<uint16_t>& entries) {
for (size_t i = 0; i < entries.size(); ++i) {
uint16_t tagId = entries[i];
sp<TiffEntry> 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<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
}
}
Vector<uint16_t> 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<TiffWriter> 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<TiffWriter> 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<StripSource*> sources;
sp<DirectStripSource> 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<DirectStripSource> thumbnailSource;
uint32_t targetIfd = TIFF_IFD_0;
bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1);
Vector<StripSource*> 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<JniInputStream> 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);