* commit '5b9021f2fadca22cd423fbe4965e5c9b94e4bb2a': Update DngCreator to handle pre-correction dimens.
This commit is contained in:
@@ -284,6 +284,8 @@ public final class DngCreator implements AutoCloseable {
|
|||||||
* {@code offset + 2 * width * height)} bytes. The width and height of
|
* {@code offset + 2 * width * height)} bytes. The width and height of
|
||||||
* the input are taken from the width and height set in the {@link DngCreator} metadata tags,
|
* the input are taken from the width and height set in the {@link DngCreator} metadata tags,
|
||||||
* and will typically be equal to the width and height of
|
* and will typically be equal to the width and height of
|
||||||
|
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE}. Prior to
|
||||||
|
* API level 23, this was always the same as
|
||||||
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
|
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
|
||||||
* The pixel layout in the input is determined from the reported color filter arrangement (CFA)
|
* The pixel layout in the input is determined from the reported color filter arrangement (CFA)
|
||||||
* set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}. If insufficient
|
* set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}. If insufficient
|
||||||
@@ -332,6 +334,8 @@ public final class DngCreator implements AutoCloseable {
|
|||||||
* {@code offset + 2 * width * height)} bytes. The width and height of
|
* {@code offset + 2 * width * height)} bytes. The width and height of
|
||||||
* the input are taken from the width and height set in the {@link DngCreator} metadata tags,
|
* the input are taken from the width and height set in the {@link DngCreator} metadata tags,
|
||||||
* and will typically be equal to the width and height of
|
* and will typically be equal to the width and height of
|
||||||
|
* {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE}. Prior to
|
||||||
|
* API level 23, this was always the same as
|
||||||
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
|
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
|
||||||
* The pixel layout in the input is determined from the reported color filter arrangement (CFA)
|
* The pixel layout in the input is determined from the reported color filter arrangement (CFA)
|
||||||
* set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}. If insufficient
|
* set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}. If insufficient
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#define LOG_TAG "DngCreator_JNI"
|
#define LOG_TAG "DngCreator_JNI"
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <utils/Log.h>
|
#include <utils/Log.h>
|
||||||
#include <utils/Errors.h>
|
#include <utils/Errors.h>
|
||||||
@@ -25,7 +27,6 @@
|
|||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
#include <utils/Vector.h>
|
#include <utils/Vector.h>
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
#include <system/camera_metadata.h>
|
#include <system/camera_metadata.h>
|
||||||
#include <camera/CameraMetadata.h>
|
#include <camera/CameraMetadata.h>
|
||||||
#include <img_utils/DngUtils.h>
|
#include <img_utils/DngUtils.h>
|
||||||
@@ -37,15 +38,6 @@
|
|||||||
#include <img_utils/StripSource.h>
|
#include <img_utils/StripSource.h>
|
||||||
|
|
||||||
#include "core_jni_helpers.h"
|
#include "core_jni_helpers.h"
|
||||||
#include <utils/Log.h>
|
|
||||||
#include <utils/Errors.h>
|
|
||||||
#include <utils/StrongPointer.h>
|
|
||||||
#include <utils/RefBase.h>
|
|
||||||
#include <utils/Vector.h>
|
|
||||||
#include <cutils/properties.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include "android_runtime/AndroidRuntime.h"
|
#include "android_runtime/AndroidRuntime.h"
|
||||||
#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
|
#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
|
||||||
@@ -63,6 +55,14 @@ using namespace img_utils;
|
|||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \
|
||||||
|
if ((expr) != OK) { \
|
||||||
|
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
|
||||||
|
"Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
|
||||||
|
return -1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define BAIL_IF_EMPTY(entry, jnienv, tagId, writer) \
|
#define BAIL_IF_EMPTY(entry, jnienv, tagId, writer) \
|
||||||
if (entry.count == 0) { \
|
if (entry.count == 0) { \
|
||||||
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
|
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
|
||||||
@@ -111,11 +111,14 @@ enum {
|
|||||||
class NativeContext : public LightRefBase<NativeContext> {
|
class NativeContext : public LightRefBase<NativeContext> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NativeContext();
|
NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result);
|
||||||
virtual ~NativeContext();
|
virtual ~NativeContext();
|
||||||
|
|
||||||
TiffWriter* getWriter();
|
TiffWriter* getWriter();
|
||||||
|
|
||||||
|
std::shared_ptr<const CameraMetadata> getCharacteristics() const;
|
||||||
|
std::shared_ptr<const CameraMetadata> getResult() const;
|
||||||
|
|
||||||
uint32_t getThumbnailWidth();
|
uint32_t getThumbnailWidth();
|
||||||
uint32_t getThumbnailHeight();
|
uint32_t getThumbnailHeight();
|
||||||
const uint8_t* getThumbnail();
|
const uint8_t* getThumbnail();
|
||||||
@@ -125,11 +128,16 @@ public:
|
|||||||
private:
|
private:
|
||||||
Vector<uint8_t> mCurrentThumbnail;
|
Vector<uint8_t> mCurrentThumbnail;
|
||||||
TiffWriter mWriter;
|
TiffWriter mWriter;
|
||||||
|
std::shared_ptr<CameraMetadata> mCharacteristics;
|
||||||
|
std::shared_ptr<CameraMetadata> mResult;
|
||||||
uint32_t mThumbnailWidth;
|
uint32_t mThumbnailWidth;
|
||||||
uint32_t mThumbnailHeight;
|
uint32_t mThumbnailHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
NativeContext::NativeContext() : mThumbnailWidth(0), mThumbnailHeight(0) {}
|
NativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) :
|
||||||
|
mCharacteristics(std::make_shared<CameraMetadata>(characteristics)),
|
||||||
|
mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0),
|
||||||
|
mThumbnailHeight(0) {}
|
||||||
|
|
||||||
NativeContext::~NativeContext() {}
|
NativeContext::~NativeContext() {}
|
||||||
|
|
||||||
@@ -137,6 +145,14 @@ TiffWriter* NativeContext::getWriter() {
|
|||||||
return &mWriter;
|
return &mWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const CameraMetadata> NativeContext::getCharacteristics() const {
|
||||||
|
return mCharacteristics;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const CameraMetadata> NativeContext::getResult() const {
|
||||||
|
return mResult;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t NativeContext::getThumbnailWidth() {
|
uint32_t NativeContext::getThumbnailWidth() {
|
||||||
return mThumbnailWidth;
|
return mThumbnailWidth;
|
||||||
}
|
}
|
||||||
@@ -626,25 +642,92 @@ uint32_t DirectStripSource::getIfd() const {
|
|||||||
// End of DirectStripSource
|
// End of DirectStripSource
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
static bool validateDngHeader(JNIEnv* env, TiffWriter* writer, jint width, jint height) {
|
/**
|
||||||
bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1);
|
* Given a buffer crop rectangle relative to the pixel array size, and the active array crop
|
||||||
|
* rectangle for the camera characteristics, set the default crop rectangle in the TiffWriter
|
||||||
|
* relative to the buffer crop rectangle origin.
|
||||||
|
*/
|
||||||
|
static status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics,
|
||||||
|
uint32_t bufXMin, uint32_t bufYMin, uint32_t bufWidth, uint32_t bufHeight,
|
||||||
|
TiffWriter* writer) {
|
||||||
|
|
||||||
|
camera_metadata_ro_entry entry =
|
||||||
|
characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
|
||||||
|
uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
|
||||||
|
uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
|
||||||
|
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
|
||||||
|
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
|
||||||
|
|
||||||
|
uint32_t aLeft = xmin;
|
||||||
|
uint32_t aTop = ymin;
|
||||||
|
uint32_t aRight = xmin + width;
|
||||||
|
uint32_t aBottom = ymin + height;
|
||||||
|
|
||||||
|
const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
|
||||||
|
|
||||||
|
uint32_t bLeft = bufXMin + margin;
|
||||||
|
uint32_t bTop = bufYMin + margin;
|
||||||
|
uint32_t bRight = bufXMin + bufWidth - margin;
|
||||||
|
uint32_t bBottom = bufYMin + bufHeight - margin;
|
||||||
|
|
||||||
|
uint32_t defaultCropOrigin[] = {std::max(aLeft, bLeft), std::max(aTop, bTop)};
|
||||||
|
uint32_t defaultCropSize[] = {std::min(aRight, bRight) - defaultCropOrigin[0],
|
||||||
|
std::min(aBottom, bBottom) - defaultCropOrigin[1]};
|
||||||
|
|
||||||
|
BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
|
||||||
|
TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
|
||||||
|
BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
|
||||||
|
TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool validateDngHeader(JNIEnv* env, TiffWriter* writer,
|
||||||
|
const CameraMetadata& characteristics, jint width, jint height) {
|
||||||
// TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
|
// TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
|
||||||
uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, (hasThumbnail) ? TIFF_IFD_SUB1 :
|
if (width <= 0) {
|
||||||
TIFF_IFD_0)->getData<uint32_t>());
|
|
||||||
uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, (hasThumbnail) ? TIFF_IFD_SUB1 :
|
|
||||||
TIFF_IFD_0)->getData<uint32_t>());
|
|
||||||
|
|
||||||
if (width < 0 || metadataWidth != static_cast<uint32_t>(width)) {
|
|
||||||
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
|
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
|
||||||
"Metadata width %d doesn't match image width %d", metadataWidth, width);
|
"Image width %d is invalid", width);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (height < 0 || metadataHeight != static_cast<uint32_t>(height)) {
|
if (height <= 0) {
|
||||||
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
|
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
|
||||||
"Metadata height %d doesn't match image height %d",
|
"Image height %d is invalid", height);
|
||||||
metadataHeight, height);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
camera_metadata_ro_entry preCorrectionEntry =
|
||||||
|
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
|
||||||
|
camera_metadata_ro_entry pixelArrayEntry =
|
||||||
|
characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE);
|
||||||
|
|
||||||
|
int pWidth = static_cast<int>(pixelArrayEntry.data.i32[0]);
|
||||||
|
int pHeight = static_cast<int>(pixelArrayEntry.data.i32[1]);
|
||||||
|
int cWidth = static_cast<int>(preCorrectionEntry.data.i32[2]);
|
||||||
|
int cHeight = static_cast<int>(preCorrectionEntry.data.i32[3]);
|
||||||
|
|
||||||
|
bool matchesPixelArray = (pWidth == width && pHeight == height);
|
||||||
|
bool matchesPreCorrectionArray = (cWidth == width && cHeight == height);
|
||||||
|
|
||||||
|
if (matchesPixelArray) {
|
||||||
|
if (calculateAndSetCrop(env, characteristics, 0, 0, static_cast<uint32_t>(pWidth),
|
||||||
|
static_cast<uint32_t>(pHeight), writer) != OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (matchesPreCorrectionArray) {
|
||||||
|
if (calculateAndSetCrop(env, characteristics,
|
||||||
|
static_cast<uint32_t>(preCorrectionEntry.data.i32[0]),
|
||||||
|
static_cast<uint32_t>(preCorrectionEntry.data.i32[1]),
|
||||||
|
static_cast<uint32_t>(preCorrectionEntry.data.i32[2]),
|
||||||
|
static_cast<uint32_t>(preCorrectionEntry.data.i32[3]), writer) != OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
|
||||||
|
"Image dimensions (w=%d,h=%d) are invalid, must match either the pixel "
|
||||||
|
"array size (w=%d, h=%d) or the pre-correction array size (w=%d, h=%d)",
|
||||||
|
width, height, pWidth, pHeight, cWidth, cHeight);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,7 +937,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<NativeContext> nativeContext = new NativeContext();
|
sp<NativeContext> nativeContext = new NativeContext(characteristics, results);
|
||||||
TiffWriter* writer = nativeContext->getWriter();
|
TiffWriter* writer = nativeContext->getWriter();
|
||||||
|
|
||||||
writer->addIfd(TIFF_IFD_0);
|
writer->addIfd(TIFF_IFD_0);
|
||||||
@@ -906,7 +989,7 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
|
|||||||
{
|
{
|
||||||
// Set dimensions
|
// Set dimensions
|
||||||
camera_metadata_entry entry =
|
camera_metadata_entry entry =
|
||||||
characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
|
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
|
||||||
BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH, writer);
|
BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH, writer);
|
||||||
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
|
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
|
||||||
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
|
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
|
||||||
@@ -1356,16 +1439,16 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Setup default crop + crop origin tags
|
// Set dimensions
|
||||||
uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
|
camera_metadata_entry entry =
|
||||||
uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from.
|
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
|
||||||
if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) {
|
BAIL_IF_EMPTY(entry, env, TAG_DEFAULTCROPSIZE, writer);
|
||||||
uint32_t defaultCropOrigin[] = {margin, margin};
|
uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
|
||||||
uint32_t defaultCropSize[] = {imageWidth - 2 * margin, imageHeight - 2 * margin};
|
uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
|
||||||
BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
|
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
|
||||||
TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
|
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
|
||||||
BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
|
if (calculateAndSetCrop(env, characteristics, xmin, ymin, width, height, writer) != OK) {
|
||||||
TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer);
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1874,7 +1957,7 @@ static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate DNG header
|
// Validate DNG header
|
||||||
if (!validateDngHeader(env, writer, width, height)) {
|
if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1978,7 +2061,7 @@ static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate DNG header
|
// Validate DNG header
|
||||||
if (!validateDngHeader(env, writer, width, height)) {
|
if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user