Update DngCreator to correctly handle array sizes.
- Allow both pixelArraySize and preCorrectionArraySize
buffer dimensions for input buffers.
- Adjust crop, active area, and dimensions used for
opcode lists based on the input buffer size.
Bug: 22302614
Bug: 22210811
Change-Id: I16fb8921a144b0a251d555037ca45fdc12f7dd18
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 995d39f..ba08237 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
#define LOG_TAG "DngCreator_JNI"
#include <inttypes.h>
#include <string.h>
@@ -26,6 +26,7 @@
#include <utils/StrongPointer.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
+#include <utils/String8.h>
#include <cutils/properties.h>
#include <system/camera_metadata.h>
#include <camera/CameraMetadata.h>
@@ -48,13 +49,22 @@
using namespace android;
using namespace img_utils;
-#define BAIL_IF_INVALID(expr, jnienv, tagId, writer) \
+#define BAIL_IF_INVALID_RET_BOOL(expr, jnienv, tagId, writer) \
if ((expr) != OK) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
"Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
- return; \
+ return false; \
}
+
+#define BAIL_IF_INVALID_RET_NULL_SP(expr, jnienv, tagId, writer) \
+ if ((expr) != OK) { \
+ jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+ "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
+ return nullptr; \
+ }
+
+
#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \
if ((expr) != OK) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
@@ -62,14 +72,14 @@
return -1; \
}
-
-#define BAIL_IF_EMPTY(entry, jnienv, tagId, writer) \
+#define BAIL_IF_EMPTY_RET_NULL_SP(entry, jnienv, tagId, writer) \
if (entry.count == 0) { \
jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
"Missing metadata fields for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
- return; \
+ return nullptr; \
}
+
#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext"
static struct {
@@ -102,6 +112,26 @@
TIFF_IFD_GPSINFO = 2,
};
+
+/**
+ * POD container class for GPS tag data.
+ */
+class GpsData {
+public:
+ enum {
+ GPS_VALUE_LENGTH = 6,
+ GPS_REF_LENGTH = 2,
+ GPS_DATE_LENGTH = 11,
+ };
+
+ uint32_t mLatitude[GPS_VALUE_LENGTH];
+ uint32_t mLongitude[GPS_VALUE_LENGTH];
+ uint32_t mTimestamp[GPS_VALUE_LENGTH];
+ uint8_t mLatitudeRef[GPS_REF_LENGTH];
+ uint8_t mLongitudeRef[GPS_REF_LENGTH];
+ uint8_t mDate[GPS_DATE_LENGTH];
+};
+
// ----------------------------------------------------------------------------
/**
@@ -109,8 +139,11 @@
*/
class NativeContext : public LightRefBase<NativeContext> {
-
public:
+ enum {
+ DATETIME_COUNT = 20,
+ };
+
NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result);
virtual ~NativeContext();
@@ -119,12 +152,28 @@
std::shared_ptr<const CameraMetadata> getCharacteristics() const;
std::shared_ptr<const CameraMetadata> getResult() const;
- uint32_t getThumbnailWidth();
- uint32_t getThumbnailHeight();
- const uint8_t* getThumbnail();
+ uint32_t getThumbnailWidth() const;
+ uint32_t getThumbnailHeight() const;
+ const uint8_t* getThumbnail() const;
+ bool hasThumbnail() const;
bool setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height);
+ void setOrientation(uint16_t orientation);
+ uint16_t getOrientation() const;
+
+ void setDescription(const String8& desc);
+ String8 getDescription() const;
+ bool hasDescription() const;
+
+ void setGpsData(const GpsData& data);
+ GpsData getGpsData() const;
+ bool hasGpsData() const;
+
+ void setCaptureTime(const String8& formattedCaptureTime);
+ String8 getCaptureTime() const;
+ bool hasCaptureTime() const;
+
private:
Vector<uint8_t> mCurrentThumbnail;
TiffWriter mWriter;
@@ -132,12 +181,21 @@
std::shared_ptr<CameraMetadata> mResult;
uint32_t mThumbnailWidth;
uint32_t mThumbnailHeight;
+ uint16_t mOrientation;
+ bool mThumbnailSet;
+ bool mGpsSet;
+ bool mDescriptionSet;
+ bool mCaptureTimeSet;
+ String8 mDescription;
+ GpsData mGpsData;
+ String8 mFormattedCaptureTime;
};
NativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) :
mCharacteristics(std::make_shared<CameraMetadata>(characteristics)),
mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0),
- mThumbnailHeight(0) {}
+ mThumbnailHeight(0), mOrientation(0), mThumbnailSet(false), mGpsSet(false),
+ mDescriptionSet(false), mCaptureTimeSet(false) {}
NativeContext::~NativeContext() {}
@@ -153,18 +211,22 @@
return mResult;
}
-uint32_t NativeContext::getThumbnailWidth() {
+uint32_t NativeContext::getThumbnailWidth() const {
return mThumbnailWidth;
}
-uint32_t NativeContext::getThumbnailHeight() {
+uint32_t NativeContext::getThumbnailHeight() const {
return mThumbnailHeight;
}
-const uint8_t* NativeContext::getThumbnail() {
+const uint8_t* NativeContext::getThumbnail() const {
return mCurrentThumbnail.array();
}
+bool NativeContext::hasThumbnail() const {
+ return mThumbnailSet;
+}
+
bool NativeContext::setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height) {
mThumbnailWidth = width;
mThumbnailHeight = height;
@@ -177,9 +239,57 @@
uint8_t* thumb = mCurrentThumbnail.editArray();
memcpy(thumb, buffer, size);
+ mThumbnailSet = true;
return true;
}
+void NativeContext::setOrientation(uint16_t orientation) {
+ mOrientation = orientation;
+}
+
+uint16_t NativeContext::getOrientation() const {
+ return mOrientation;
+}
+
+void NativeContext::setDescription(const String8& desc) {
+ mDescription = desc;
+ mDescriptionSet = true;
+}
+
+String8 NativeContext::getDescription() const {
+ return mDescription;
+}
+
+bool NativeContext::hasDescription() const {
+ return mDescriptionSet;
+}
+
+void NativeContext::setGpsData(const GpsData& data) {
+ mGpsData = data;
+ mGpsSet = true;
+}
+
+GpsData NativeContext::getGpsData() const {
+ return mGpsData;
+}
+
+bool NativeContext::hasGpsData() const {
+ return mGpsSet;
+}
+
+void NativeContext::setCaptureTime(const String8& formattedCaptureTime) {
+ mFormattedCaptureTime = formattedCaptureTime;
+ mCaptureTimeSet = true;
+}
+
+String8 NativeContext::getCaptureTime() const {
+ return mFormattedCaptureTime;
+}
+
+bool NativeContext::hasCaptureTime() const {
+ return mCaptureTimeSet;
+}
+
// End of NativeContext
// ----------------------------------------------------------------------------
@@ -211,7 +321,7 @@
JniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
mEnv(env) {
mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
- if (mByteArray == NULL) {
+ if (mByteArray == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
}
}
@@ -286,7 +396,7 @@
JniInputStream::JniInputStream(JNIEnv* env, jobject inStream) : mInStream(inStream), mEnv(env) {
mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
- if (mByteArray == NULL) {
+ if (mByteArray == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
}
}
@@ -372,7 +482,7 @@
JniInputByteBuffer::JniInputByteBuffer(JNIEnv* env, jobject inBuf) : mInBuf(inBuf), mEnv(env) {
mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
- if (mByteArray == NULL) {
+ if (mByteArray == nullptr) {
jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
}
}
@@ -600,6 +710,7 @@
return BAD_VALUE;
}
+
if (mPixStride == mBytesPerSample * mSamplesPerPixel
&& mRowStride == mWidth * mBytesPerSample * mSamplesPerPixel) {
ALOGV("%s: Using direct single-pass write for strip.", __FUNCTION__);
@@ -643,37 +754,48 @@
// ----------------------------------------------------------------------------
/**
- * 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.
+ * Given a buffer crop rectangle relative to the pixel array size, and the pre-correction 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) {
+ uint32_t bufWidth, uint32_t bufHeight, sp<TiffWriter> writer) {
camera_metadata_ro_entry entry =
- characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_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]);
+ const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
+
+ // Crop based on pre-correction array for pixel array
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.
+ // 8 pixel border crop for pixel array dimens
+ uint32_t bLeft = margin;
+ uint32_t bTop = margin;
+ uint32_t bRight = bufWidth - margin;
+ uint32_t bBottom = bufHeight - margin;
- uint32_t bLeft = bufXMin + margin;
- uint32_t bTop = bufYMin + margin;
- uint32_t bRight = bufXMin + bufWidth - margin;
- uint32_t bBottom = bufYMin + bufHeight - margin;
-
+ // Set the crop to be the intersection of the two rectangles
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]};
+ // If using buffers with pre-correction array dimens, switch to 8 pixel border crop
+ // relative to the pixel array dimens
+ if (bufWidth == width && bufHeight == height) {
+ defaultCropOrigin[0] = xmin + margin;
+ defaultCropOrigin[1] = ymin + margin;
+ defaultCropSize[0] = width - margin;
+ defaultCropSize[1] = height - margin;
+ }
+
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,
@@ -682,9 +804,8 @@
return OK;
}
-static bool validateDngHeader(JNIEnv* env, TiffWriter* writer,
+static bool validateDngHeader(JNIEnv* env, sp<TiffWriter> writer,
const CameraMetadata& characteristics, jint width, jint height) {
- // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
if (width <= 0) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
"Image width %d is invalid", width);
@@ -710,20 +831,7 @@
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 {
+ if (!(matchesPixelArray || matchesPreCorrectionArray)) {
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)",
@@ -734,12 +842,12 @@
return true;
}
-static status_t moveEntries(TiffWriter* writer, uint32_t ifdFrom, uint32_t ifdTo,
+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 == NULL) {
+ if (entry.get() == nullptr) {
ALOGE("%s: moveEntries failed, entry %u not found in IFD %u", __FUNCTION__, tagId,
ifdFrom);
return BAD_VALUE;
@@ -881,7 +989,7 @@
ALOGV("%s:", __FUNCTION__);
NativeContext* current = DngCreator_getNativeContext(env, thiz);
- if (context != NULL) {
+ if (context != nullptr) {
context->incStrong((void*) DngCreator_setNativeContext);
}
@@ -893,15 +1001,6 @@
reinterpret_cast<jlong>(context.get()));
}
-static TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) {
- ALOGV("%s:", __FUNCTION__);
- NativeContext* current = DngCreator_getNativeContext(env, thiz);
- if (current) {
- return current->getWriter();
- }
- return NULL;
-}
-
static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
ALOGV("%s:", __FUNCTION__);
@@ -938,7 +1037,62 @@
}
sp<NativeContext> nativeContext = new NativeContext(characteristics, results);
- TiffWriter* writer = nativeContext->getWriter();
+
+ const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, nullptr);
+
+ size_t len = strlen(captureTime) + 1;
+ if (len != NativeContext::DATETIME_COUNT) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Formatted capture time string length is not required 20 characters");
+ return;
+ }
+
+ nativeContext->setCaptureTime(String8(captureTime));
+
+ DngCreator_setNativeContext(env, thiz, nativeContext);
+}
+
+static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t imageWidth,
+ uint32_t imageHeight) {
+
+ NativeContext* nativeContext = DngCreator_getNativeContext(env, thiz);
+
+ if (nativeContext == nullptr) {
+ jniThrowException(env, "java/lang/AssertionError",
+ "No native context, must call init before other operations.");
+ return nullptr;
+ }
+
+ CameraMetadata characteristics = *(nativeContext->getCharacteristics());
+ CameraMetadata results = *(nativeContext->getResult());
+
+ sp<TiffWriter> writer = new TiffWriter();
+
+ uint32_t preWidth = 0;
+ uint32_t preHeight = 0;
+ {
+ // Check dimensions
+ camera_metadata_entry entry =
+ characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer);
+ preWidth = static_cast<uint32_t>(entry.data.i32[2]);
+ preHeight = static_cast<uint32_t>(entry.data.i32[3]);
+
+ camera_metadata_entry pixelArrayEntry =
+ characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE);
+ uint32_t pixWidth = static_cast<uint32_t>(pixelArrayEntry.data.i32[0]);
+ uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]);
+
+ if (!((imageWidth == preWidth && imageHeight == preHeight) ||
+ (imageWidth == pixWidth && imageHeight == pixHeight))) {
+ jniThrowException(env, "java/lang/AssertionError",
+ "Height and width of imate buffer did not match height and width of"
+ "either the preCorrectionActiveArraySize or the pixelArraySize.");
+ return nullptr;
+ }
+ }
+
+
writer->addIfd(TIFF_IFD_0);
@@ -946,8 +1100,6 @@
const uint32_t samplesPerPixel = 1;
const uint32_t bitsPerSample = BITS_PER_SAMPLE;
- uint32_t imageWidth = 0;
- uint32_t imageHeight = 0;
OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
uint8_t cfaPlaneColor[3] = {0, 1, 2};
@@ -961,93 +1113,86 @@
{
// Set orientation
uint16_t orientation = 1; // Normal
- BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
- TAG_ORIENTATION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0),
+ env, TAG_ORIENTATION, writer);
}
{
// Set subfiletype
uint32_t subfileType = 0; // Main image
- BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
- TAG_NEWSUBFILETYPE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType,
+ TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer);
}
{
// Set bits per sample
uint16_t bits = static_cast<uint16_t>(bitsPerSample);
- BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
TAG_BITSPERSAMPLE, writer);
}
{
// Set compression
uint16_t compression = 1; // None
- BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
- TAG_COMPRESSION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression,
+ TIFF_IFD_0), env, TAG_COMPRESSION, writer);
}
{
// Set dimensions
- camera_metadata_entry entry =
- characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
- BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH, writer);
- uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
- uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env,
- TAG_IMAGEWIDTH, writer);
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env,
- TAG_IMAGELENGTH, writer);
- imageWidth = width;
- imageHeight = height;
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &imageWidth, TIFF_IFD_0),
+ env, TAG_IMAGEWIDTH, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &imageHeight, TIFF_IFD_0),
+ env, TAG_IMAGELENGTH, writer);
}
{
// Set photometric interpretation
uint16_t interpretation = 32803; // CFA
- BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
- TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1,
+ &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
}
{
// Set blacklevel tags
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
- BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BLACKLEVEL, writer);
const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
- BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env,
- TAG_BLACKLEVEL, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel,
+ TIFF_IFD_0), env, TAG_BLACKLEVEL, writer);
uint16_t repeatDim[2] = {2, 2};
- BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env,
- TAG_BLACKLEVELREPEATDIM, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim,
+ TIFF_IFD_0), env, TAG_BLACKLEVELREPEATDIM, writer);
}
{
// Set samples per pixel
uint16_t samples = static_cast<uint16_t>(samplesPerPixel);
- BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
env, TAG_SAMPLESPERPIXEL, writer);
}
{
// Set planar configuration
uint16_t config = 1; // Chunky
- BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
- env, TAG_PLANARCONFIGURATION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config,
+ TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer);
}
{
// Set CFA pattern dimensions
uint16_t repeatDim[2] = {2, 2};
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0),
- env, TAG_CFAREPEATPATTERNDIM, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim,
+ TIFF_IFD_0), env, TAG_CFAREPEATPATTERNDIM, writer);
}
{
// Set CFA pattern
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
- BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_CFAPATTERN, writer);
const int cfaLength = 4;
cfaEnum = entry.data.u8[0];
@@ -1057,30 +1202,30 @@
"Invalid metadata for tag %d", TAG_CFAPATTERN);
}
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0), env,
- TAG_CFAPATTERN, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0),
+ env, TAG_CFAPATTERN, writer);
opcodeCfaLayout = convertCFAEnumToOpcodeLayout(cfaEnum);
}
{
// Set CFA plane color
- BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
- env, TAG_CFAPLANECOLOR, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor,
+ TIFF_IFD_0), env, TAG_CFAPLANECOLOR, writer);
}
{
// Set CFA layout
uint16_t cfaLayout = 1;
- BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
env, TAG_CFALAYOUT, writer);
}
{
// image description
uint8_t imageDescription = '\0'; // empty
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription, TIFF_IFD_0),
- env, TAG_IMAGEDESCRIPTION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription,
+ TIFF_IFD_0), env, TAG_IMAGEDESCRIPTION, writer);
}
{
@@ -1091,8 +1236,8 @@
property_get("ro.product.manufacturer", manufacturer, "");
uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1;
- BAIL_IF_INVALID(writer->addEntry(TAG_MAKE, count, reinterpret_cast<uint8_t*>(manufacturer),
- TIFF_IFD_0), env, TAG_MAKE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MAKE, count,
+ reinterpret_cast<uint8_t*>(manufacturer), TIFF_IFD_0), env, TAG_MAKE, writer);
}
{
@@ -1103,23 +1248,23 @@
property_get("ro.product.model", model, "");
uint32_t count = static_cast<uint32_t>(strlen(model)) + 1;
- BAIL_IF_INVALID(writer->addEntry(TAG_MODEL, count, reinterpret_cast<uint8_t*>(model),
- TIFF_IFD_0), env, TAG_MODEL, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MODEL, count,
+ reinterpret_cast<uint8_t*>(model), TIFF_IFD_0), env, TAG_MODEL, writer);
}
{
// x resolution
uint32_t xres[] = { 72, 1 }; // default 72 ppi
- BAIL_IF_INVALID(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
env, TAG_XRESOLUTION, writer);
// y resolution
uint32_t yres[] = { 72, 1 }; // default 72 ppi
- BAIL_IF_INVALID(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
env, TAG_YRESOLUTION, writer);
uint16_t unit = 2; // inches
- BAIL_IF_INVALID(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
env, TAG_RESOLUTIONUNIT, writer);
}
@@ -1128,52 +1273,41 @@
char software[PROPERTY_VALUE_MAX];
property_get("ro.build.fingerprint", software, "");
uint32_t count = static_cast<uint32_t>(strlen(software)) + 1;
- BAIL_IF_INVALID(writer->addEntry(TAG_SOFTWARE, count, reinterpret_cast<uint8_t*>(software),
- TIFF_IFD_0), env, TAG_SOFTWARE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SOFTWARE, count,
+ reinterpret_cast<uint8_t*>(software), TIFF_IFD_0), env, TAG_SOFTWARE, writer);
}
- {
+ if (nativeContext->hasCaptureTime()) {
// datetime
- const size_t DATETIME_COUNT = 20;
- const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, NULL);
+ String8 captureTime = nativeContext->getCaptureTime();
- size_t len = strlen(captureTime) + 1;
- if (len != DATETIME_COUNT) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "Timestamp string length is not required 20 characters");
- return;
- }
-
- if (writer->addEntry(TAG_DATETIME, DATETIME_COUNT,
- reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0) != OK) {
- env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
+ if (writer->addEntry(TAG_DATETIME, NativeContext::DATETIME_COUNT,
+ reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
"Invalid metadata for tag %x", TAG_DATETIME);
- return;
+ return nullptr;
}
// datetime original
- if (writer->addEntry(TAG_DATETIMEORIGINAL, DATETIME_COUNT,
- reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0) != OK) {
- env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
+ if (writer->addEntry(TAG_DATETIMEORIGINAL, NativeContext::DATETIME_COUNT,
+ reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) {
jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
"Invalid metadata for tag %x", TAG_DATETIMEORIGINAL);
- return;
+ return nullptr;
}
- env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
}
{
// TIFF/EP standard id
uint8_t standardId[] = { 1, 0, 0, 0 };
- BAIL_IF_INVALID(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId,
TIFF_IFD_0), env, TAG_TIFFEPSTANDARDID, writer);
}
{
// copyright
uint8_t copyright = '\0'; // empty
- BAIL_IF_INVALID(writer->addEntry(TAG_COPYRIGHT, 1, ©right,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COPYRIGHT, 1, ©right,
TIFF_IFD_0), env, TAG_COPYRIGHT, writer);
}
@@ -1181,7 +1315,7 @@
// exposure time
camera_metadata_entry entry =
results.find(ANDROID_SENSOR_EXPOSURE_TIME);
- BAIL_IF_EMPTY(entry, env, TAG_EXPOSURETIME, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_EXPOSURETIME, writer);
int64_t exposureTime = *(entry.data.i64);
@@ -1189,7 +1323,7 @@
// Should be unreachable
jniThrowException(env, "java/lang/IllegalArgumentException",
"Negative exposure time in metadata");
- return;
+ return nullptr;
}
// Ensure exposure time doesn't overflow (for exposures > 4s)
@@ -1201,12 +1335,12 @@
// Should be unreachable
jniThrowException(env, "java/lang/IllegalArgumentException",
"Exposure time too long");
- return;
+ return nullptr;
}
}
uint32_t exposure[] = { static_cast<uint32_t>(exposureTime), denominator };
- BAIL_IF_INVALID(writer->addEntry(TAG_EXPOSURETIME, 1, exposure,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_EXPOSURETIME, 1, exposure,
TIFF_IFD_0), env, TAG_EXPOSURETIME, writer);
}
@@ -1215,13 +1349,13 @@
// ISO speed ratings
camera_metadata_entry entry =
results.find(ANDROID_SENSOR_SENSITIVITY);
- BAIL_IF_EMPTY(entry, env, TAG_ISOSPEEDRATINGS, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ISOSPEEDRATINGS, writer);
int32_t tempIso = *(entry.data.i32);
if (tempIso < 0) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Negative ISO value");
- return;
+ return nullptr;
}
if (tempIso > UINT16_MAX) {
@@ -1230,7 +1364,7 @@
}
uint16_t iso = static_cast<uint16_t>(tempIso);
- BAIL_IF_INVALID(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso,
TIFF_IFD_0), env, TAG_ISOSPEEDRATINGS, writer);
}
@@ -1238,10 +1372,10 @@
// focal length
camera_metadata_entry entry =
results.find(ANDROID_LENS_FOCAL_LENGTH);
- BAIL_IF_EMPTY(entry, env, TAG_FOCALLENGTH, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FOCALLENGTH, writer);
uint32_t focalLength[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
- BAIL_IF_INVALID(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength,
TIFF_IFD_0), env, TAG_FOCALLENGTH, writer);
}
@@ -1249,39 +1383,39 @@
// f number
camera_metadata_entry entry =
results.find(ANDROID_LENS_APERTURE);
- BAIL_IF_EMPTY(entry, env, TAG_FNUMBER, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FNUMBER, writer);
uint32_t fnum[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
- BAIL_IF_INVALID(writer->addEntry(TAG_FNUMBER, 1, fnum,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FNUMBER, 1, fnum,
TIFF_IFD_0), env, TAG_FNUMBER, writer);
}
{
// Set DNG version information
uint8_t version[4] = {1, 4, 0, 0};
- BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
env, TAG_DNGVERSION, writer);
uint8_t backwardVersion[4] = {1, 1, 0, 0};
- BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0),
- env, TAG_DNGBACKWARDVERSION, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion,
+ TIFF_IFD_0), env, TAG_DNGBACKWARDVERSION, writer);
}
{
// Set whitelevel
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL);
- BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_WHITELEVEL, writer);
uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]);
- BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env,
- TAG_WHITELEVEL, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0),
+ env, TAG_WHITELEVEL, writer);
}
{
// Set default scale
uint32_t defaultScale[4] = {1, 1, 1, 1};
- BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0),
- env, TAG_DEFAULTSCALE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale,
+ TIFF_IFD_0), env, TAG_DEFAULTSCALE, writer);
}
bool singleIlluminant = false;
@@ -1289,7 +1423,7 @@
// Set calibration illuminants
camera_metadata_entry entry1 =
characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
- BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CALIBRATIONILLUMINANT1, writer);
camera_metadata_entry entry2 =
characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
if (entry2.count == 0) {
@@ -1297,12 +1431,12 @@
}
uint16_t ref1 = entry1.data.u8[0];
- BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1, writer);
if (!singleIlluminant) {
uint16_t ref2 = entry2.data.u8[0];
- BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2, writer);
}
}
@@ -1311,7 +1445,7 @@
// Set color transforms
camera_metadata_entry entry1 =
characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1);
- BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_COLORMATRIX1, writer);
int32_t colorTransform1[entry1.count * 2];
@@ -1321,12 +1455,12 @@
colorTransform1[ctr++] = entry1.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1,
- TIFF_IFD_0), env, TAG_COLORMATRIX1, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX1, entry1.count,
+ colorTransform1, TIFF_IFD_0), env, TAG_COLORMATRIX1, writer);
if (!singleIlluminant) {
camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2);
- BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_COLORMATRIX2, writer);
int32_t colorTransform2[entry2.count * 2];
ctr = 0;
@@ -1335,8 +1469,8 @@
colorTransform2[ctr++] = entry2.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2,
- TIFF_IFD_0), env, TAG_COLORMATRIX2, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX2, entry2.count,
+ colorTransform2, TIFF_IFD_0), env, TAG_COLORMATRIX2, writer);
}
}
@@ -1344,7 +1478,7 @@
// Set calibration transforms
camera_metadata_entry entry1 =
characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
- BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CAMERACALIBRATION1, writer);
int32_t calibrationTransform1[entry1.count * 2];
@@ -1354,13 +1488,13 @@
calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count,
calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer);
if (!singleIlluminant) {
camera_metadata_entry entry2 =
characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
- BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_CAMERACALIBRATION2, writer);
int32_t calibrationTransform2[entry2.count * 2];
ctr = 0;
@@ -1369,7 +1503,7 @@
calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count,
calibrationTransform2, TIFF_IFD_0), env, TAG_CAMERACALIBRATION2, writer);
}
}
@@ -1378,7 +1512,7 @@
// Set forward transforms
camera_metadata_entry entry1 =
characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1);
- BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_FORWARDMATRIX1, writer);
int32_t forwardTransform1[entry1.count * 2];
@@ -1388,13 +1522,13 @@
forwardTransform1[ctr++] = entry1.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1,
- TIFF_IFD_0), env, TAG_FORWARDMATRIX1, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count,
+ forwardTransform1, TIFF_IFD_0), env, TAG_FORWARDMATRIX1, writer);
if (!singleIlluminant) {
camera_metadata_entry entry2 =
characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2);
- BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_FORWARDMATRIX2, writer);
int32_t forwardTransform2[entry2.count * 2];
ctr = 0;
@@ -1403,8 +1537,8 @@
forwardTransform2[ctr++] = entry2.data.r[i].denominator;
}
- BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2,
- TIFF_IFD_0), env, TAG_FORWARDMATRIX2, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count,
+ forwardTransform2, TIFF_IFD_0), env, TAG_FORWARDMATRIX2, writer);
}
}
@@ -1412,7 +1546,7 @@
// Set camera neutral
camera_metadata_entry entry =
results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
- BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ASSHOTNEUTRAL, writer);
uint32_t cameraNeutral[entry.count * 2];
size_t ctr = 0;
@@ -1423,33 +1557,27 @@
static_cast<uint32_t>(entry.data.r[i].denominator);
}
- BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL, writer);
}
- {
- // Setup data strips
- // TODO: Switch to tiled implementation.
- if (writer->addStrip(TIFF_IFD_0) != OK) {
- ALOGE("%s: Could not setup strip tags.", __FUNCTION__);
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to setup strip tags.");
- return;
- }
- }
{
// Set dimensions
+ if (calculateAndSetCrop(env, characteristics, imageWidth, imageHeight, writer) != OK) {
+ return nullptr;
+ }
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
- BAIL_IF_EMPTY(entry, env, TAG_DEFAULTCROPSIZE, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_DEFAULTCROPSIZE, writer);
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]);
- if (calculateAndSetCrop(env, characteristics, xmin, ymin, width, height, writer) != OK) {
- return;
- }
+
+ uint32_t activeArea[] = {ymin, xmin, ymin + height, xmin + width};
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ACTIVEAREA, 4, activeArea, TIFF_IFD_0),
+ env, TAG_ACTIVEAREA, writer);
}
{
@@ -1469,7 +1597,7 @@
cameraModel += "-";
cameraModel += brand;
- BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
TAG_UNIQUECAMERAMODEL, writer);
}
@@ -1486,7 +1614,7 @@
if ((err = convertCFA(cfaEnum, /*out*/cfaOut)) != OK) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Invalid CFA from camera characteristics");
- return;
+ return nullptr;
}
double noiseProfile[numPlaneColors * 2];
@@ -1500,8 +1628,9 @@
if ((err = generateNoiseProfile(entry.data.d, cfaOut, numCfaChannels,
cfaPlaneColor, numPlaneColors, /*out*/ noiseProfile)) == OK) {
- BAIL_IF_INVALID(writer->addEntry(TAG_NOISEPROFILE, numPlaneColors * 2,
- noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NOISEPROFILE,
+ numPlaneColors * 2, noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE,
+ writer);
} else {
ALOGW("%s: Error converting coefficients for noise profile, no noise profile"
" tag written...", __FUNCTION__);
@@ -1533,19 +1662,26 @@
camera_metadata_entry entry2 =
results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+ camera_metadata_entry entry =
+ characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer);
+ 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]);
if (entry2.count > 0 && entry2.count == lsmWidth * lsmHeight * 4) {
err = builder.addGainMapsForMetadata(lsmWidth,
lsmHeight,
- 0,
- 0,
- imageHeight,
- imageWidth,
+ ymin,
+ xmin,
+ height,
+ width,
opcodeCfaLayout,
entry2.data.f);
if (err != OK) {
ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
jniThrowRuntimeException(env, "failed to add lens shading map.");
- return;
+ return nullptr;
}
}
@@ -1553,14 +1689,14 @@
uint8_t opcodeListBuf[listSize];
err = builder.buildOpList(opcodeListBuf);
if (err == OK) {
- BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
TIFF_IFD_0), env, TAG_OPCODELIST2, writer);
} else {
ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading"
"map.", __FUNCTION__);
jniThrowRuntimeException(env, "failed to construct opcode list for distortion"
" correction and lens shading map");
- return;
+ return nullptr;
}
}
@@ -1578,12 +1714,12 @@
if (entry3.count == 6 && entry4.count == 5) {
float cx = entry4.data.f[/*c_x*/2];
float cy = entry4.data.f[/*c_y*/3];
- err = builder.addWarpRectilinearForMetadata(entry3.data.f, imageWidth, imageHeight, cx,
+ err = builder.addWarpRectilinearForMetadata(entry3.data.f, preWidth, preHeight, cx,
cy);
if (err != OK) {
ALOGE("%s: Could not add distortion correction.", __FUNCTION__);
jniThrowRuntimeException(env, "failed to add distortion correction.");
- return;
+ return nullptr;
}
}
@@ -1591,211 +1727,103 @@
uint8_t opcodeListBuf[listSize];
err = builder.buildOpList(opcodeListBuf);
if (err == OK) {
- BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf,
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf,
TIFF_IFD_0), env, TAG_OPCODELIST3, writer);
} else {
ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading"
"map.", __FUNCTION__);
jniThrowRuntimeException(env, "failed to construct opcode list for distortion"
" correction and lens shading map");
- return;
+ return nullptr;
}
}
- DngCreator_setNativeContext(env, thiz, nativeContext);
-}
+ {
+ // Set up orientation tags.
+ uint16_t orientation = nativeContext->getOrientation();
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0),
+ env, TAG_ORIENTATION, writer);
-static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
- ALOGV("%s:", __FUNCTION__);
- DngCreator_setNativeContext(env, thiz, NULL);
-}
-
-static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) {
- ALOGV("%s:", __FUNCTION__);
-
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL) {
- ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
- jniThrowException(env, "java/lang/AssertionError",
- "setOrientation called with uninitialized DngCreator");
- return;
}
- uint16_t orientation = static_cast<uint16_t>(orient);
- BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
- TAG_ORIENTATION, writer);
-
- // Set main image orientation also if in a separate IFD
- if (writer->hasIfd(TIFF_IFD_SUB1)) {
- BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_SUB1), env,
- TAG_ORIENTATION, writer);
- }
-}
-
-static void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) {
- ALOGV("%s:", __FUNCTION__);
-
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL) {
- ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
- jniThrowException(env, "java/lang/AssertionError",
- "setDescription called with uninitialized DngCreator");
- return;
- }
-
- const char* desc = env->GetStringUTFChars(description, NULL);
- size_t len = strlen(desc) + 1;
-
- if (writer->addEntry(TAG_IMAGEDESCRIPTION, len,
- reinterpret_cast<const uint8_t*>(desc), TIFF_IFD_0) != OK) {
- jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
- "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION);
- }
-
- env->ReleaseStringUTFChars(description, desc);
-}
-
-static void DngCreator_nativeSetGpsTags(JNIEnv* env, jobject thiz, jintArray latTag, jstring latRef,
- jintArray longTag, jstring longRef, jstring dateTag, jintArray timeTag) {
- ALOGV("%s:", __FUNCTION__);
-
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL) {
- ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
- jniThrowException(env, "java/lang/AssertionError",
- "setGpsTags called with uninitialized DngCreator");
- return;
- }
-
- if (!writer->hasIfd(TIFF_IFD_GPSINFO)) {
- if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_GPSINFO, TiffWriter::GPSINFO) != OK) {
- ALOGE("%s: Failed to add GpsInfo IFD %u to IFD %u", __FUNCTION__, TIFF_IFD_GPSINFO,
- TIFF_IFD_0);
- jniThrowException(env, "java/lang/IllegalStateException", "Failed to add GPSINFO");
- return;
+ if (nativeContext->hasDescription()){
+ // Set Description
+ String8 description = nativeContext->getDescription();
+ size_t len = description.bytes() + 1;
+ if (writer->addEntry(TAG_IMAGEDESCRIPTION, len,
+ reinterpret_cast<const uint8_t*>(description.string()), TIFF_IFD_0) != OK) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION);
}
}
- const jsize GPS_VALUE_LENGTH = 6;
- jsize latLen = env->GetArrayLength(latTag);
- jsize longLen = env->GetArrayLength(longTag);
- jsize timeLen = env->GetArrayLength(timeTag);
- if (latLen != GPS_VALUE_LENGTH) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "invalid latitude tag length");
- return;
- } else if (longLen != GPS_VALUE_LENGTH) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "invalid longitude tag length");
- return;
- } else if (timeLen != GPS_VALUE_LENGTH) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "invalid time tag length");
- return;
+ if (nativeContext->hasGpsData()) {
+ // Set GPS tags
+ GpsData gpsData = nativeContext->getGpsData();
+ if (!writer->hasIfd(TIFF_IFD_GPSINFO)) {
+ if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_GPSINFO, TiffWriter::GPSINFO) != OK) {
+ ALOGE("%s: Failed to add GpsInfo IFD %u to IFD %u", __FUNCTION__, TIFF_IFD_GPSINFO,
+ TIFF_IFD_0);
+ jniThrowException(env, "java/lang/IllegalStateException", "Failed to add GPSINFO");
+ return nullptr;
+ }
+ }
+
+ {
+ uint8_t version[] = {2, 3, 0, 0};
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSVERSIONID, 4, version,
+ TIFF_IFD_GPSINFO), env, TAG_GPSVERSIONID, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDEREF,
+ GpsData::GPS_REF_LENGTH, gpsData.mLatitudeRef, TIFF_IFD_GPSINFO), env,
+ TAG_GPSLATITUDEREF, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDEREF,
+ GpsData::GPS_REF_LENGTH, gpsData.mLongitudeRef, TIFF_IFD_GPSINFO), env,
+ TAG_GPSLONGITUDEREF, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDE, 3, gpsData.mLatitude,
+ TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDE, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDE, 3, gpsData.mLongitude,
+ TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDE, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSTIMESTAMP, 3, gpsData.mTimestamp,
+ TIFF_IFD_GPSINFO), env, TAG_GPSTIMESTAMP, writer);
+ }
+
+ {
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSDATESTAMP,
+ GpsData::GPS_DATE_LENGTH, gpsData.mDate, TIFF_IFD_GPSINFO), env,
+ TAG_GPSDATESTAMP, writer);
+ }
}
- uint32_t latitude[GPS_VALUE_LENGTH];
- uint32_t longitude[GPS_VALUE_LENGTH];
- uint32_t timestamp[GPS_VALUE_LENGTH];
- env->GetIntArrayRegion(latTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
- reinterpret_cast<jint*>(&latitude));
- env->GetIntArrayRegion(longTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
- reinterpret_cast<jint*>(&longitude));
- env->GetIntArrayRegion(timeTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
- reinterpret_cast<jint*>(×tamp));
-
- const jsize GPS_REF_LENGTH = 2;
- const jsize GPS_DATE_LENGTH = 11;
- uint8_t latitudeRef[GPS_REF_LENGTH];
- uint8_t longitudeRef[GPS_REF_LENGTH];
- uint8_t date[GPS_DATE_LENGTH];
-
- env->GetStringUTFRegion(latRef, 0, 1, reinterpret_cast<char*>(&latitudeRef));
- latitudeRef[GPS_REF_LENGTH - 1] = '\0';
- env->GetStringUTFRegion(longRef, 0, 1, reinterpret_cast<char*>(&longitudeRef));
- longitudeRef[GPS_REF_LENGTH - 1] = '\0';
-
- env->GetStringUTFRegion(dateTag, 0, GPS_DATE_LENGTH - 1, reinterpret_cast<char*>(&date));
- date[GPS_DATE_LENGTH - 1] = '\0';
-
- {
- uint8_t version[] = {2, 3, 0, 0};
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSVERSIONID, 4, version,
- TIFF_IFD_GPSINFO), env, TAG_GPSVERSIONID, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSLATITUDEREF, GPS_REF_LENGTH, latitudeRef,
- TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDEREF, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSLONGITUDEREF, GPS_REF_LENGTH, longitudeRef,
- TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDEREF, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSLATITUDE, 3, latitude,
- TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDE, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSLONGITUDE, 3, longitude,
- TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDE, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSTIMESTAMP, 3, timestamp,
- TIFF_IFD_GPSINFO), env, TAG_GPSTIMESTAMP, writer);
- }
-
- {
- BAIL_IF_INVALID(writer->addEntry(TAG_GPSDATESTAMP, GPS_DATE_LENGTH, date,
- TIFF_IFD_GPSINFO), env, TAG_GPSDATESTAMP, writer);
- }
-}
-
-static void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width,
- jint height) {
- ALOGV("%s:", __FUNCTION__);
-
- NativeContext* context = DngCreator_getNativeContext(env, thiz);
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
- if (writer == NULL || context == NULL) {
- ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
- jniThrowException(env, "java/lang/AssertionError",
- "setThumbnail called with uninitialized DngCreator");
- return;
- }
-
- size_t fullSize = width * height * BYTES_PER_RGB_PIXEL;
- jlong capacity = env->GetDirectBufferCapacity(buffer);
- if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) {
- jniThrowExceptionFmt(env, "java/lang/AssertionError",
- "Invalid size %d for thumbnail, expected size was %d",
- capacity, fullSize);
- return;
- }
-
- uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
- if (pixelBytes == NULL) {
- ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__);
- jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer");
- return;
- }
-
- if (!writer->hasIfd(TIFF_IFD_SUB1)) {
- if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_SUB1) != OK) {
- ALOGE("%s: Failed to add SubIFD %u to IFD %u", __FUNCTION__, TIFF_IFD_SUB1,
- TIFF_IFD_0);
- jniThrowException(env, "java/lang/IllegalStateException", "Failed to add SubIFD");
- return;
+ if (nativeContext->hasThumbnail()) {
+ if (!writer->hasIfd(TIFF_IFD_SUB1)) {
+ if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_SUB1) != OK) {
+ ALOGE("%s: Failed to add SubIFD %u to IFD %u", __FUNCTION__, TIFF_IFD_SUB1,
+ TIFF_IFD_0);
+ jniThrowException(env, "java/lang/IllegalStateException", "Failed to add SubIFD");
+ return nullptr;
+ }
}
Vector<uint16_t> tagsToMove;
tagsToMove.add(TAG_ORIENTATION);
tagsToMove.add(TAG_NEWSUBFILETYPE);
+ tagsToMove.add(TAG_ACTIVEAREA);
tagsToMove.add(TAG_BITSPERSAMPLE);
tagsToMove.add(TAG_COMPRESSION);
tagsToMove.add(TAG_IMAGEWIDTH);
@@ -1814,9 +1842,6 @@
tagsToMove.add(TAG_RESOLUTIONUNIT);
tagsToMove.add(TAG_WHITELEVEL);
tagsToMove.add(TAG_DEFAULTSCALE);
- tagsToMove.add(TAG_ROWSPERSTRIP);
- tagsToMove.add(TAG_STRIPBYTECOUNTS);
- tagsToMove.add(TAG_STRIPOFFSETS);
tagsToMove.add(TAG_DEFAULTCROPORIGIN);
tagsToMove.add(TAG_DEFAULTCROPSIZE);
tagsToMove.add(TAG_OPCODELIST2);
@@ -1824,101 +1849,217 @@
if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) {
jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries");
- return;
+ return nullptr;
}
// Make sure both IFDs get the same orientation tag
sp<TiffEntry> orientEntry = writer->getEntry(TAG_ORIENTATION, TIFF_IFD_SUB1);
- if (orientEntry != NULL) {
+ if (orientEntry.get() != nullptr) {
writer->addEntry(orientEntry, TIFF_IFD_0);
}
- }
- // Setup thumbnail tags
+ // Setup thumbnail tags
- {
- // Set photometric interpretation
- uint16_t interpretation = 2; // RGB
- BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
- TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
- }
-
- {
- // Set planar configuration
- uint16_t config = 1; // Chunky
- BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
- env, TAG_PLANARCONFIGURATION, writer);
- }
-
- {
- // Set samples per pixel
- uint16_t samples = SAMPLES_PER_RGB_PIXEL;
- BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
- env, TAG_SAMPLESPERPIXEL, writer);
- }
-
- {
- // Set bits per sample
- uint16_t bits = BITS_PER_RGB_SAMPLE;
- BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
- TAG_BITSPERSAMPLE, writer);
- }
-
- {
- // Set subfiletype
- uint32_t subfileType = 1; // Thumbnail image
- BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
- TAG_NEWSUBFILETYPE, writer);
- }
-
- {
- // Set compression
- uint16_t compression = 1; // None
- BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
- TAG_COMPRESSION, writer);
- }
-
- {
- // Set dimensions
- uint32_t uWidth = static_cast<uint32_t>(width);
- uint32_t uHeight = static_cast<uint32_t>(height);
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_0), env,
- TAG_IMAGEWIDTH, writer);
- BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0), env,
- TAG_IMAGELENGTH, writer);
- }
-
- {
- // x resolution
- uint32_t xres[] = { 72, 1 }; // default 72 ppi
- BAIL_IF_INVALID(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
- env, TAG_XRESOLUTION, writer);
-
- // y resolution
- uint32_t yres[] = { 72, 1 }; // default 72 ppi
- BAIL_IF_INVALID(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
- env, TAG_YRESOLUTION, writer);
-
- uint16_t unit = 2; // inches
- BAIL_IF_INVALID(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
- env, TAG_RESOLUTIONUNIT, writer);
- }
-
- {
- // Setup data strips
- if (writer->addStrip(TIFF_IFD_0) != OK) {
- ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__);
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to setup thumbnail strip tags.");
- return;
+ {
+ // 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);
}
+
+ {
+ // 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);
+ }
+
+ {
+ // 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);
+ }
+
+ {
+ // Set bits per sample
+ uint16_t bits = BITS_PER_RGB_SAMPLE;
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0),
+ env, TAG_BITSPERSAMPLE, writer);
+ }
+
+ {
+ // 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);
+ }
+
+ {
+ // 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);
+ }
+
+ {
+ // 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),
+ env, TAG_IMAGEWIDTH, writer);
+ BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0),
+ 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),
+ 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),
+ 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);
+ }
+ }
+
+ if (writer->addStrip(TIFF_IFD_0) != OK) {
+ ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to setup thumbnail 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__);
jniThrowException(env, "java/lang/IllegalStateException",
"Failed to setup main image strip tags.");
- return;
+ return nullptr;
}
}
+ return writer;
+}
+
+static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
+ ALOGV("%s:", __FUNCTION__);
+ DngCreator_setNativeContext(env, thiz, nullptr);
+}
+
+static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) {
+ ALOGV("%s:", __FUNCTION__);
+
+ NativeContext* context = DngCreator_getNativeContext(env, thiz);
+ if (context == nullptr) {
+ ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
+ jniThrowException(env, "java/lang/AssertionError",
+ "setOrientation called with uninitialized DngCreator");
+ return;
+ }
+
+ uint16_t orientation = static_cast<uint16_t>(orient);
+ context->setOrientation(orientation);
+}
+
+static void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) {
+ ALOGV("%s:", __FUNCTION__);
+
+ NativeContext* context = DngCreator_getNativeContext(env, thiz);
+ if (context == nullptr) {
+ ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
+ jniThrowException(env, "java/lang/AssertionError",
+ "setDescription called with uninitialized DngCreator");
+ return;
+ }
+
+ const char* desc = env->GetStringUTFChars(description, nullptr);
+ context->setDescription(String8(desc));
+ env->ReleaseStringUTFChars(description, desc);
+}
+
+static void DngCreator_nativeSetGpsTags(JNIEnv* env, jobject thiz, jintArray latTag,
+ jstring latRef, jintArray longTag, jstring longRef, jstring dateTag, jintArray timeTag) {
+ ALOGV("%s:", __FUNCTION__);
+
+ NativeContext* context = DngCreator_getNativeContext(env, thiz);
+ if (context == nullptr) {
+ ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
+ jniThrowException(env, "java/lang/AssertionError",
+ "setGpsTags called with uninitialized DngCreator");
+ return;
+ }
+
+ GpsData data;
+
+ jsize latLen = env->GetArrayLength(latTag);
+ jsize longLen = env->GetArrayLength(longTag);
+ jsize timeLen = env->GetArrayLength(timeTag);
+ if (latLen != GpsData::GPS_VALUE_LENGTH) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "invalid latitude tag length");
+ return;
+ } else if (longLen != GpsData::GPS_VALUE_LENGTH) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "invalid longitude tag length");
+ return;
+ } else if (timeLen != GpsData::GPS_VALUE_LENGTH) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "invalid time tag length");
+ return;
+ }
+
+ env->GetIntArrayRegion(latTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH),
+ reinterpret_cast<jint*>(&data.mLatitude));
+ env->GetIntArrayRegion(longTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH),
+ reinterpret_cast<jint*>(&data.mLongitude));
+ env->GetIntArrayRegion(timeTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH),
+ reinterpret_cast<jint*>(&data.mTimestamp));
+
+
+ env->GetStringUTFRegion(latRef, 0, 1, reinterpret_cast<char*>(&data.mLatitudeRef));
+ data.mLatitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0';
+ env->GetStringUTFRegion(longRef, 0, 1, reinterpret_cast<char*>(&data.mLongitudeRef));
+ data.mLongitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0';
+ env->GetStringUTFRegion(dateTag, 0, GpsData::GPS_DATE_LENGTH - 1,
+ reinterpret_cast<char*>(&data.mDate));
+ data.mDate[GpsData::GPS_DATE_LENGTH - 1] = '\0';
+
+ context->setGpsData(data);
+}
+
+static void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width,
+ jint height) {
+ ALOGV("%s:", __FUNCTION__);
+
+ NativeContext* context = DngCreator_getNativeContext(env, thiz);
+ if (context == nullptr) {
+ ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
+ jniThrowException(env, "java/lang/AssertionError",
+ "setThumbnail called with uninitialized DngCreator");
+ return;
+ }
+
+ size_t fullSize = width * height * BYTES_PER_RGB_PIXEL;
+ jlong capacity = env->GetDirectBufferCapacity(buffer);
+ if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) {
+ jniThrowExceptionFmt(env, "java/lang/AssertionError",
+ "Invalid size %d for thumbnail, expected size was %d",
+ capacity, fullSize);
+ return;
+ }
+
+ uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
+ if (pixelBytes == nullptr) {
+ ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__);
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer");
+ return;
+ }
if (!context->setThumbnail(pixelBytes, width, height)) {
jniThrowException(env, "java/lang/IllegalStateException",
@@ -1947,16 +2088,20 @@
return;
}
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
NativeContext* context = DngCreator_getNativeContext(env, thiz);
- if (writer == NULL || context == NULL) {
+ if (context == nullptr) {
ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
jniThrowException(env, "java/lang/AssertionError",
"Write called with uninitialized DngCreator");
return;
}
+ sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight);
- // Validate DNG header
+ if (writer.get() == nullptr) {
+ return;
+ }
+
+ // Validate DNG size
if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) {
return;
}
@@ -1991,7 +2136,7 @@
}
uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer));
- if (pixelBytes == NULL) {
+ if (pixelBytes == nullptr) {
ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__);
jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer");
return;
@@ -2051,16 +2196,20 @@
return;
}
- TiffWriter* writer = DngCreator_getCreator(env, thiz);
NativeContext* context = DngCreator_getNativeContext(env, thiz);
- if (writer == NULL || context == NULL) {
+ if (context == nullptr) {
ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
jniThrowException(env, "java/lang/AssertionError",
"Write called with uninitialized DngCreator");
return;
}
+ sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight);
- // Validate DNG header
+ if (writer.get() == nullptr) {
+ return;
+ }
+
+ // Validate DNG size
if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) {
return;
}