android_hardware_camera2_DngCreator.cpp revision 46d8444631b4b1253a76bfcc78a29d26014d022f
1f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk/*
2f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * Copyright 2014 The Android Open Source Project
3f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk *
4f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * you may not use this file except in compliance with the License.
6f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * You may obtain a copy of the License at
7f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk *
8f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk *
10f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * Unless required by applicable law or agreed to in writing, software
11f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * See the License for the specific language governing permissions and
14f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk * limitations under the License.
15f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk */
16f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
17f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk//#define LOG_NDEBUG 0
18f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#define LOG_TAG "DngCreator_JNI"
1946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <inttypes.h>
2046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <string.h>
2146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert
2246d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Log.h>
2346d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Errors.h>
2446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/StrongPointer.h>
2546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/RefBase.h>
2646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Vector.h>
2746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <cutils/properties.h>
28f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
29f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <system/camera_metadata.h>
30f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <camera/CameraMetadata.h>
31f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/DngUtils.h>
32f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TagDefinitions.h>
33f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffIfd.h>
34f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffWriter.h>
35f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/Output.h>
3647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/Input.h>
3747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/StripSource.h>
38f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
39f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/AndroidRuntime.h"
40f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
41f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
42f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <jni.h>
43f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <JNIHelp.h>
44f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
45f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace android;
46f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace img_utils;
47f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
4847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#define BAIL_IF_INVALID(expr, jnienv, tagId, writer) \
49f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    if ((expr) != OK) { \
50f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
5147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
52f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return; \
53f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
54f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
5547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#define BAIL_IF_EMPTY(entry, jnienv, tagId, writer) \
56f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    if (entry.count == 0) { \
57f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
5847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Missing metadata fields for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
59f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return; \
60f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
61f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
62b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk#define ANDROID_DNGCREATOR_CTX_JNI_ID     "mNativeContext"
63f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
64f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct {
65f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jfieldID mNativeContext;
66f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gDngCreatorClassInfo;
67f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
68f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct {
69f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jmethodID mWriteMethod;
70f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gOutputStreamClassInfo;
71f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
7247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct {
7347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jmethodID mReadMethod;
7447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jmethodID mSkipMethod;
7547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputStreamClassInfo;
7647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
7747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct {
7847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jmethodID mGetMethod;
7947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputByteBufferClassInfo;
8047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
81f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkenum {
82f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    BITS_PER_SAMPLE = 16,
83f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    BYTES_PER_SAMPLE = 2,
8447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    BYTES_PER_RGB_PIXEL = 3,
8547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    BITS_PER_RGB_SAMPLE = 8,
8647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    BYTES_PER_RGB_SAMPLE = 1,
8747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    SAMPLES_PER_RGB_PIXEL = 3,
8847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    SAMPLES_PER_RAW_PIXEL = 1,
8947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TIFF_IFD_0 = 0,
9047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TIFF_IFD_SUB1 = 1,
9147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TIFF_IFD_GPSINFO = 2,
92f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk};
93f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
94f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ----------------------------------------------------------------------------
95f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
9647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
9747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Container class for the persistent native context.
9847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
9947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
10047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass NativeContext : public LightRefBase<NativeContext> {
10147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
10247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
10347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    NativeContext();
10447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~NativeContext();
10547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
10647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter* getWriter();
10747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
10847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t getThumbnailWidth();
10947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t getThumbnailHeight();
11047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    const uint8_t* getThumbnail();
11147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
11247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    bool setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height);
11347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
11447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate:
11547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    Vector<uint8_t> mCurrentThumbnail;
11647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter mWriter;
11747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mThumbnailWidth;
11847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mThumbnailHeight;
11947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
12047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
12147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkNativeContext::NativeContext() : mThumbnailWidth(0), mThumbnailHeight(0) {}
12247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
12347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkNativeContext::~NativeContext() {}
12447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
12547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkTiffWriter* NativeContext::getWriter() {
12647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return &mWriter;
12747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
12847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
12947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t NativeContext::getThumbnailWidth() {
13047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mThumbnailWidth;
13147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
13247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
13347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t NativeContext::getThumbnailHeight() {
13447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mThumbnailHeight;
13547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
13647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
13747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkconst uint8_t* NativeContext::getThumbnail() {
13847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mCurrentThumbnail.array();
13947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
14047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
14147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkbool NativeContext::setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height) {
14247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mThumbnailWidth = width;
14347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mThumbnailHeight = height;
14447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
14547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    size_t size = BYTES_PER_RGB_PIXEL * width * height;
14647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mCurrentThumbnail.resize(size) < 0) {
14747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Could not resize thumbnail buffer.", __FUNCTION__);
14847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return false;
14947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
15047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
15147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint8_t* thumb = mCurrentThumbnail.editArray();
15247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    memcpy(thumb, buffer, size);
15347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return true;
15447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
15547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
15647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of NativeContext
15747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
15847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
15947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
16047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java OutputStream.
16147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
16247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
16347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
164f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkclass JniOutputStream : public Output, public LightRefBase<JniOutputStream> {
165f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkpublic:
166f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    JniOutputStream(JNIEnv* env, jobject outStream);
167f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
168f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    virtual ~JniOutputStream();
169f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
170f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    status_t open();
17147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
172f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    status_t write(const uint8_t* buf, size_t offset, size_t count);
17347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
174f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    status_t close();
175f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkprivate:
176f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    enum {
17747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BYTE_ARRAY_LENGTH = 4096
178f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    };
179f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jobject mOutputStream;
180f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    JNIEnv* mEnv;
181f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jbyteArray mByteArray;
182f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk};
183f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
184f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
185f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        mEnv(env) {
186f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
187f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    if (mByteArray == NULL) {
188f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
189f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
190f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
191f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
192f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::~JniOutputStream() {
193f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    mEnv->DeleteLocalRef(mByteArray);
194f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
195f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
196f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::open() {
197f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    // Do nothing
198f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    return OK;
199f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
200f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
201f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) {
202f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    while(count > 0) {
203f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        size_t len = BYTE_ARRAY_LENGTH;
204f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        len = (count > len) ? len : count;
205f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset));
206f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
207f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (mEnv->ExceptionCheck()) {
208f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            return BAD_VALUE;
209f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
210f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
211f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray,
212f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                0, len);
213f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
214f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (mEnv->ExceptionCheck()) {
215f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            return BAD_VALUE;
216f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
217f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
218f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        count -= len;
219f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        offset += len;
220f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
221f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    return OK;
222f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
223f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
224f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::close() {
225f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    // Do nothing
226f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    return OK;
227f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
228f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
22947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniOutputStream
230f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ----------------------------------------------------------------------------
231f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
23247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
23347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java InputStream.
23447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
23547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
23647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
23747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputStream : public Input, public LightRefBase<JniInputStream> {
23847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
23947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JniInputStream(JNIEnv* env, jobject inStream);
24047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
24147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t open();
24247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
24347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t close();
24447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
24547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ssize_t read(uint8_t* buf, size_t offset, size_t count);
24647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
24747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ssize_t skip(size_t count);
24847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
24947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~JniInputStream();
25047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate:
25147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    enum {
25247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BYTE_ARRAY_LENGTH = 4096
25347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    };
25447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jobject mInStream;
25547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JNIEnv* mEnv;
25647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jbyteArray mByteArray;
25747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
25847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
25947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
26047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::JniInputStream(JNIEnv* env, jobject inStream) : mInStream(inStream), mEnv(env) {
26147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
26247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mByteArray == NULL) {
26347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
26447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
26547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
26647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
26747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::~JniInputStream() {
26847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->DeleteLocalRef(mByteArray);
26947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
27047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
27147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::read(uint8_t* buf, size_t offset, size_t count) {
27247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
27347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jint realCount = BYTE_ARRAY_LENGTH;
27447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (count < BYTE_ARRAY_LENGTH) {
27547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        realCount = count;
27647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
27747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jint actual = mEnv->CallIntMethod(mInStream, gInputStreamClassInfo.mReadMethod, mByteArray, 0,
27847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            realCount);
27947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
28047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (actual < 0) {
28147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return NOT_ENOUGH_DATA;
28247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
28347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
28447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
28547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
28647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
28747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
28847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->GetByteArrayRegion(mByteArray, 0, actual, reinterpret_cast<jbyte*>(buf + offset));
28947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
29047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
29147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
29247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return actual;
29347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
29447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
29547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::skip(size_t count) {
29647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jlong actual = mEnv->CallLongMethod(mInStream, gInputStreamClassInfo.mSkipMethod,
29747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            static_cast<jlong>(count));
29847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
29947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
30047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
30147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
30247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (actual < 0) {
30347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return NOT_ENOUGH_DATA;
30447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
30547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return actual;
30647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
30747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
30847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::open() {
30947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Do nothing
31047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
31147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
31247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
31347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::close() {
31447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Do nothing
31547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
31647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
31747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
31847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputStream
31947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
32047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
32147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
32247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a non-direct Java ByteBuffer.
32347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
32447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
32547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
32647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputByteBuffer : public Input, public LightRefBase<JniInputByteBuffer> {
32747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
32847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JniInputByteBuffer(JNIEnv* env, jobject inBuf);
32947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
33047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t open();
33147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
33247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t close();
33347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
33447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ssize_t read(uint8_t* buf, size_t offset, size_t count);
33547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
33647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~JniInputByteBuffer();
33747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate:
33847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    enum {
33947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BYTE_ARRAY_LENGTH = 4096
34047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    };
34147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jobject mInBuf;
34247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JNIEnv* mEnv;
34347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jbyteArray mByteArray;
34447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
34547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
34647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::JniInputByteBuffer(JNIEnv* env, jobject inBuf) : mInBuf(inBuf), mEnv(env) {
34747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
34847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mByteArray == NULL) {
34947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
35047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
35147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
35247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
35347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::~JniInputByteBuffer() {
35447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->DeleteLocalRef(mByteArray);
35547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
35647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
35747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputByteBuffer::read(uint8_t* buf, size_t offset, size_t count) {
35847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jint realCount = BYTE_ARRAY_LENGTH;
35947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (count < BYTE_ARRAY_LENGTH) {
36047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        realCount = count;
36147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
36247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
36347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, mByteArray, 0,
36447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            realCount);
36547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
36647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
36747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
36847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
36947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
37047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    mEnv->GetByteArrayRegion(mByteArray, 0, realCount, reinterpret_cast<jbyte*>(buf + offset));
37147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mEnv->ExceptionCheck()) {
37247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
37347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
37447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return realCount;
37547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
37647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
37747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::open() {
37847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Do nothing
37947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
38047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
38147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
38247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::close() {
38347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Do nothing
38447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
38547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
38647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
38747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputByteBuffer
38847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
38947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
39047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
39147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for Input types.
39247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
39347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
39447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
39547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
39647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass InputStripSource : public StripSource, public LightRefBase<InputStripSource> {
39747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
39847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width, uint32_t height,
39947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t pixStride, uint32_t rowStride, uint64_t offset, uint32_t bytesPerSample,
40047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t samplesPerPixel);
40147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
40247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~InputStripSource();
40347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
40447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual status_t writeToStream(Output& stream, uint32_t count);
40547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
40647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual uint32_t getIfd() const;
40747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected:
40847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mIfd;
40947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    Input* mInput;
41047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mWidth;
41147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mHeight;
41247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mPixStride;
41347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mRowStride;
41447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint64_t mOffset;
41547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JNIEnv* mEnv;
41647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mBytesPerSample;
41747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mSamplesPerPixel;
41847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
41947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
42047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width,
42147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset,
42247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd), mInput(&input),
42347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        mWidth(width), mHeight(height), mPixStride(pixStride), mRowStride(rowStride),
42447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample),
42547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        mSamplesPerPixel(samplesPerPixel) {}
42647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
42747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::~InputStripSource() {}
42847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
42947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t InputStripSource::writeToStream(Output& stream, uint32_t count) {
4303e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk    uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel;
43147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jlong offset = mOffset;
43247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
43347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (fullSize != count) {
43447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count,
43547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                fullSize);
43647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write");
43747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
43847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
43947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
44047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Skip offset
44147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    while (offset > 0) {
44247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ssize_t skipped = mInput->skip(offset);
44347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (skipped <= 0) {
44447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (skipped == NOT_ENOUGH_DATA || skipped == 0) {
44547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                jniThrowExceptionFmt(mEnv, "java/io/IOException",
44647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        "Early EOF encountered in skip, not enough pixel data for image of size %u",
44747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        fullSize);
44847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                skipped = NOT_ENOUGH_DATA;
44947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            } else {
45047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                if (!mEnv->ExceptionCheck()) {
45147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    jniThrowException(mEnv, "java/io/IOException",
45247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                            "Error encountered while skip bytes in input stream.");
45347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                }
45447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
45547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
45647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return skipped;
45747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
45847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        offset -= skipped;
45947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
46047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
46147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    Vector<uint8_t> row;
46247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (row.resize(mRowStride) < 0) {
46347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(mEnv, "java/lang/OutOfMemoryError", "Could not allocate row vector.");
46447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
46547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
46647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
46747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint8_t* rowBytes = row.editArray();
46847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
46947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    for (uint32_t i = 0; i < mHeight; ++i) {
47047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        size_t rowFillAmt = 0;
47147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        size_t rowSize = mPixStride;
47247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
47347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        while (rowFillAmt < mRowStride) {
47447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ssize_t bytesRead = mInput->read(rowBytes, rowFillAmt, rowSize);
47547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (bytesRead <= 0) {
47647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                if (bytesRead == NOT_ENOUGH_DATA || bytesRead == 0) {
47747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    jniThrowExceptionFmt(mEnv, "java/io/IOException",
47847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                            "Early EOF encountered, not enough pixel data for image of size %u",
47947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                            fullSize);
48047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    bytesRead = NOT_ENOUGH_DATA;
48147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                } else {
48247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    if (!mEnv->ExceptionCheck()) {
48347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        jniThrowException(mEnv, "java/io/IOException",
48447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                                "Error encountered while reading");
48547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    }
48647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                }
48747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                return bytesRead;
48847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
48947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            rowFillAmt += bytesRead;
49047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            rowSize -= bytesRead;
49147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
49247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
49347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (mPixStride == mBytesPerSample * mSamplesPerPixel) {
49447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGV("%s: Using stream per-row write for strip.", __FUNCTION__);
49547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
49647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (stream.write(rowBytes, 0, mBytesPerSample * mSamplesPerPixel * mWidth) != OK ||
49747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    mEnv->ExceptionCheck()) {
49847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                if (!mEnv->ExceptionCheck()) {
49947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data");
50047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                }
50147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                return BAD_VALUE;
50247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
50347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        } else {
50447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGV("%s: Using stream per-pixel write for strip.", __FUNCTION__);
50547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(mEnv, "java/lang/IllegalStateException",
50647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous");
50747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return BAD_VALUE;
50847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
50947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            // TODO: Add support for non-contiguous pixels if needed.
51047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
51147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
51247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
51347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
51447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
51547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t InputStripSource::getIfd() const {
51647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mIfd;
51747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
51847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
51947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of InputStripSource
52047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
52147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
52247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/**
52347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for direct buffer types.
52447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk *
52547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls.
52647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */
52747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
52847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass DirectStripSource : public StripSource, public LightRefBase<DirectStripSource> {
52947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic:
53047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd, uint32_t width,
53147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset,
53247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t bytesPerSample, uint32_t samplesPerPixel);
53347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
53447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual ~DirectStripSource();
53547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
53647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual status_t writeToStream(Output& stream, uint32_t count);
53747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
53847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    virtual uint32_t getIfd() const;
53947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected:
54047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mIfd;
54147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    const uint8_t* mPixelBytes;
54247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mWidth;
54347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mHeight;
54447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mPixStride;
54547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mRowStride;
54647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint16_t mOffset;
54747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    JNIEnv* mEnv;
54847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mBytesPerSample;
54947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t mSamplesPerPixel;
55047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk};
55147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
55247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd,
55347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint32_t width, uint32_t height, uint32_t pixStride, uint32_t rowStride,
55447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            uint64_t offset, uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd),
55547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            mPixelBytes(pixelBytes), mWidth(width), mHeight(height), mPixStride(pixStride),
55647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            mRowStride(rowStride), mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample),
55747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            mSamplesPerPixel(samplesPerPixel) {}
55847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
55947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::~DirectStripSource() {}
56047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
56147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t DirectStripSource::writeToStream(Output& stream, uint32_t count) {
5623e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk    uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel;
56347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
56447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (fullSize != count) {
56547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count,
56647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                fullSize);
56747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write");
56847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
56947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
57047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
57147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (mPixStride == mBytesPerSample * mSamplesPerPixel
57247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            && mRowStride == mWidth * mBytesPerSample * mSamplesPerPixel) {
57347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Using direct single-pass write for strip.", __FUNCTION__);
57447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
57547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (stream.write(mPixelBytes, mOffset, fullSize) != OK || mEnv->ExceptionCheck()) {
57647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (!mEnv->ExceptionCheck()) {
57747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data");
57847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
57947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return BAD_VALUE;
58047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
58147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    } else if (mPixStride == mBytesPerSample * mSamplesPerPixel) {
58247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Using direct per-row write for strip.", __FUNCTION__);
58347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
58447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        for (size_t i = 0; i < mHeight; ++i) {
58547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (stream.write(mPixelBytes, mOffset + i * mRowStride, mPixStride * mWidth) != OK ||
58647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        mEnv->ExceptionCheck()) {
58747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                if (!mEnv->ExceptionCheck()) {
58847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data");
58947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                }
59047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                return BAD_VALUE;
59147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            }
59247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
59347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    } else {
59447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Using direct per-pixel write for strip.", __FUNCTION__);
59547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
59647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(mEnv, "java/lang/IllegalStateException",
59747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous");
59847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return BAD_VALUE;
59947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
60047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // TODO: Add support for non-contiguous pixels if needed.
60147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
60247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
60347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
60447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
60547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
60647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t DirectStripSource::getIfd() const {
60747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return mIfd;
60847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
60947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
61047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of DirectStripSource
61147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
61247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
61347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic bool validateDngHeader(JNIEnv* env, TiffWriter* writer, jint width, jint height) {
61447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1);
61547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
61647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
61747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, (hasThumbnail) ? TIFF_IFD_SUB1 : TIFF_IFD_0)->getData<uint32_t>());
61847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, (hasThumbnail) ? TIFF_IFD_SUB1 : TIFF_IFD_0)->getData<uint32_t>());
61947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
62047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (width < 0 || metadataWidth != static_cast<uint32_t>(width)) {
62147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
62247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        "Metadata width %d doesn't match image width %d", metadataWidth, width);
62347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return false;
62447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
62547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
62647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (height < 0 || metadataHeight != static_cast<uint32_t>(height)) {
62747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \
62847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        "Metadata height %d doesn't match image height %d", metadataHeight, height);
62947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return false;
63047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
63147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
63247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return true;
63347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
63447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
63547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic status_t moveEntries(TiffWriter* writer, uint32_t ifdFrom, uint32_t ifdTo,
63647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        const Vector<uint16_t>& entries) {
63747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    for (size_t i = 0; i < entries.size(); ++i) {
63847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint16_t tagId = entries[i];
63947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        sp<TiffEntry> entry = writer->getEntry(tagId, ifdFrom);
64047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (entry == NULL) {
64147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: moveEntries failed, entry %u not found in IFD %u", __FUNCTION__, tagId,
64247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    ifdFrom);
64347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return BAD_VALUE;
64447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
64547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (writer->addEntry(entry, ifdTo) != OK) {
64647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: moveEntries failed, could not add entry %u to IFD %u", __FUNCTION__, tagId,
64747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    ifdFrom);
64847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return BAD_VALUE;
64947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
65047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        writer->removeEntry(tagId, ifdFrom);
65147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
65247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return OK;
65347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
65447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
655d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/**
656d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Write CFA pattern for given CFA enum into cfaOut.  cfaOut must have length >= 4.
657d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Returns OK on success, or a negative error code if the CFA enum was invalid.
658d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */
659d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic status_t convertCFA(uint8_t cfaEnum, /*out*/uint8_t* cfaOut) {
660d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
661d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
662d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaEnum);
663d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    switch(cfa) {
664d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
665d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[0] = 0;
666d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[1] = 1;
667d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[2] = 1;
668d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[3] = 2;
669d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            break;
670d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
671d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
672d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[0] = 1;
673d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[1] = 0;
674d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[2] = 2;
675d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[3] = 1;
676d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            break;
677d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
678d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
679d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[0] = 1;
680d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[1] = 2;
681d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[2] = 0;
682d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[3] = 1;
683d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            break;
684d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
685d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
686d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[0] = 2;
687d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[1] = 1;
688d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[2] = 1;
689d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaOut[3] = 0;
690d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            break;
691d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
692d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        default: {
693d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            return BAD_VALUE;
694d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
695d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    }
696d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    return OK;
697d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk}
698d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
699d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/**
700d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Convert the CFA layout enum to an OpcodeListBuilder::CfaLayout enum, defaults to
701d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * RGGB for an unknown enum.
702d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */
703d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic OpcodeListBuilder::CfaLayout convertCFAEnumToOpcodeLayout(uint8_t cfaEnum) {
704d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
705d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
706d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            cfaEnum);
707d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    switch(cfa) {
708d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
709d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            return OpcodeListBuilder::CFA_RGGB;
710d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
711d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
712d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            return OpcodeListBuilder::CFA_GRBG;
713d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
714d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
715d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            return OpcodeListBuilder::CFA_GBRG;
716d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
717d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
718d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            return OpcodeListBuilder::CFA_BGGR;
719d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
720d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        default: {
721d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            return OpcodeListBuilder::CFA_RGGB;
722d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
723d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    }
724d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk}
725d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
726d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/**
727d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * For each color plane, find the corresponding noise profile coefficients given in the
728d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * per-channel noise profile.  If multiple channels in the CFA correspond to a color in the color
729d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * plane, this method takes the pair of noise profile coefficients with the higher S coefficient.
730d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk *
731d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * perChannelNoiseProfile - numChannels * 2 noise profile coefficients.
732d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * cfa - numChannels color channels corresponding to each of the per-channel noise profile
733d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk *       coefficients.
734d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * numChannels - the number of noise profile coefficient pairs and color channels given in
735d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk *       the perChannelNoiseProfile and cfa arguments, respectively.
736d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * planeColors - the color planes in the noise profile output.
737d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * numPlanes - the number of planes in planeColors and pairs of coefficients in noiseProfile.
738d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * noiseProfile - 2 * numPlanes doubles containing numPlanes pairs of noise profile coefficients.
739d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk *
740d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * returns OK, or a negative error code on failure.
741d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */
742d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic status_t generateNoiseProfile(const double* perChannelNoiseProfile, uint8_t* cfa,
743d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        size_t numChannels, const uint8_t* planeColors, size_t numPlanes,
744d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        /*out*/double* noiseProfile) {
745d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
746d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    for (size_t p = 0; p < numPlanes; ++p) {
747d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        size_t S = p * 2;
748d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        size_t O = p * 2 + 1;
749d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
750d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        noiseProfile[S] = 0;
751d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        noiseProfile[O] = 0;
752d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        bool uninitialized = true;
753d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        for (size_t c = 0; c < numChannels; ++c) {
754d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            if (cfa[c] == planeColors[p] && perChannelNoiseProfile[c * 2] > noiseProfile[S]) {
755d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                noiseProfile[S] = perChannelNoiseProfile[c * 2];
756d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                noiseProfile[O] = perChannelNoiseProfile[c * 2 + 1];
757d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                uninitialized = false;
758d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            }
759d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
760d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        if (uninitialized) {
76146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert            ALOGE("%s: No valid NoiseProfile coefficients for color plane %zu",
76246d8444631b4b1253a76bfcc78a29d26014d022fDan Albert                  __FUNCTION__, p);
763d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            return BAD_VALUE;
764d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
765d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    }
766d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    return OK;
767d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk}
768d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
76947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ----------------------------------------------------------------------------
770f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkextern "C" {
771f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
77247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic NativeContext* DngCreator_getNativeContext(JNIEnv* env, jobject thiz) {
773f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
77447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return reinterpret_cast<NativeContext*>(env->GetLongField(thiz,
775f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            gDngCreatorClassInfo.mNativeContext));
776f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
777f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
77847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_setNativeContext(JNIEnv* env, jobject thiz, sp<NativeContext> context) {
779f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
78047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    NativeContext* current = DngCreator_getNativeContext(env, thiz);
78147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
78247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (context != NULL) {
78347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        context->incStrong((void*) DngCreator_setNativeContext);
784f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
78547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
786f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    if (current) {
78747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        current->decStrong((void*) DngCreator_setNativeContext);
788f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
78947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
790f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext,
79147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            reinterpret_cast<jlong>(context.get()));
79247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
79347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
79447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) {
79547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ALOGV("%s:", __FUNCTION__);
79647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    NativeContext* current = DngCreator_getNativeContext(env, thiz);
79747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (current) {
79847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return current->getWriter();
79947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
80047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    return NULL;
801f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
802f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
803f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
804f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
805f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
806f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz,
807b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk            ANDROID_DNGCREATOR_CTX_JNI_ID, "J");
808f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL,
809b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk            "can't find android/hardware/camera2/DngCreator.%s",
810b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk            ANDROID_DNGCREATOR_CTX_JNI_ID);
811f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
812f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    jclass outputStreamClazz = env->FindClass("java/io/OutputStream");
813f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class");
814f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    gOutputStreamClassInfo.mWriteMethod = env->GetMethodID(outputStreamClazz, "write", "([BII)V");
815f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    LOG_ALWAYS_FATAL_IF(gOutputStreamClassInfo.mWriteMethod == NULL, "Can't find write method");
81647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
81747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jclass inputStreamClazz = env->FindClass("java/io/InputStream");
81847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    LOG_ALWAYS_FATAL_IF(inputStreamClazz == NULL, "Can't find java/io/InputStream class");
81947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    gInputStreamClassInfo.mReadMethod = env->GetMethodID(inputStreamClazz, "read", "([BII)I");
82047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    LOG_ALWAYS_FATAL_IF(gInputStreamClassInfo.mReadMethod == NULL, "Can't find read method");
82147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    gInputStreamClassInfo.mSkipMethod = env->GetMethodID(inputStreamClazz, "skip", "(J)J");
82247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    LOG_ALWAYS_FATAL_IF(gInputStreamClassInfo.mSkipMethod == NULL, "Can't find skip method");
82347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
82447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jclass inputBufferClazz = env->FindClass("java/nio/ByteBuffer");
82547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    LOG_ALWAYS_FATAL_IF(inputBufferClazz == NULL, "Can't find java/nio/ByteBuffer class");
82647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    gInputByteBufferClassInfo.mGetMethod = env->GetMethodID(inputBufferClazz, "get",
82747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            "([BII)Ljava/nio/ByteBuffer;");
82847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    LOG_ALWAYS_FATAL_IF(gInputByteBufferClassInfo.mGetMethod == NULL, "Can't find get method");
829f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
830f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
831f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr,
832b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        jobject resultsPtr, jstring formattedCaptureTime) {
833f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
834f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    CameraMetadata characteristics;
835f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    CameraMetadata results;
836f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) {
837f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk         jniThrowException(env, "java/lang/AssertionError",
838f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                "No native metadata defined for camera characteristics.");
839f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk         return;
840f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
841f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) {
842f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        jniThrowException(env, "java/lang/AssertionError",
843f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                "No native metadata defined for capture results.");
844f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return;
845f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
846f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
84747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    sp<NativeContext> nativeContext = new NativeContext();
84847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter* writer = nativeContext->getWriter();
849f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
850f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    writer->addIfd(TIFF_IFD_0);
851f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
852f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    status_t err = OK;
853f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
854f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    const uint32_t samplesPerPixel = 1;
855f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    const uint32_t bitsPerSample = BITS_PER_SAMPLE;
856f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    uint32_t imageWidth = 0;
857f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    uint32_t imageHeight = 0;
858f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
859f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
860d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    uint8_t cfaPlaneColor[3] = {0, 1, 2};
861d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk    uint8_t cfaEnum = -1;
862f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
863f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    // TODO: Greensplit.
864f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    // TODO: Add remaining non-essential tags
86547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
86647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Setup main image tags
86747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
868f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
869f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set orientation
870f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t orientation = 1; // Normal
871f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
87247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_ORIENTATION, writer);
873f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
874f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
875f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
876f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set subfiletype
877f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint32_t subfileType = 0; // Main image
878f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
87947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_NEWSUBFILETYPE, writer);
880f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
881f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
882f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
883f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set bits per sample
884f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t bits = static_cast<uint16_t>(bitsPerSample);
885f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
88647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_BITSPERSAMPLE, writer);
887f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
888f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
889f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
890f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set compression
891f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t compression = 1; // None
892f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
89347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_COMPRESSION, writer);
894f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
895f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
896f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
897f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set dimensions
898f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry =
899f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
90047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH, writer);
901f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
902f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
903f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env,
90447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_IMAGEWIDTH, writer);
905f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env,
90647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_IMAGELENGTH, writer);
907f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        imageWidth = width;
908f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        imageHeight = height;
909f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
910f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
911f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
912f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set photometric interpretation
91347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint16_t interpretation = 32803; // CFA
914f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
91547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
916f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
917f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
918f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
919f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set blacklevel tags
920f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry =
921f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
92247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL, writer);
923f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
924f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env,
92547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_BLACKLEVEL, writer);
926f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
927f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t repeatDim[2] = {2, 2};
928f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env,
92947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_BLACKLEVELREPEATDIM, writer);
930f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
931f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
932f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
933f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set samples per pixel
934f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t samples = static_cast<uint16_t>(samplesPerPixel);
935f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
93647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_SAMPLESPERPIXEL, writer);
937f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
938f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
939f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
940f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set planar configuration
941f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t config = 1; // Chunky
942f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
94347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_PLANARCONFIGURATION, writer);
944f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
945f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
946f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
947f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set CFA pattern dimensions
948f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t repeatDim[2] = {2, 2};
949f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0),
95047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_CFAREPEATPATTERNDIM, writer);
951f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
952f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
953f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
954f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set CFA pattern
955f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry =
956f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                        characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
95747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN, writer);
958d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
959d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        const int cfaLength = 4;
960d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        cfaEnum = entry.data.u8[0];
961d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        uint8_t cfa[cfaLength];
962d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        if ((err = convertCFA(cfaEnum, /*out*/cfa)) != OK) {
963d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
964d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                        "Invalid metadata for tag %d", TAG_CFAPATTERN);
965f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
966d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
967d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0), env,
968d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                TAG_CFAPATTERN, writer);
969d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
970d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        opcodeCfaLayout = convertCFAEnumToOpcodeLayout(cfaEnum);
971f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
972f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
973f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
974f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set CFA plane color
975f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
97647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_CFAPLANECOLOR, writer);
977f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
978f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
979f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
980f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set CFA layout
981f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t cfaLayout = 1;
982f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
98347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_CFALAYOUT, writer);
984f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
985f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
986f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
987b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // image description
988b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint8_t imageDescription = '\0'; // empty
989b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription, TIFF_IFD_0),
99047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_IMAGEDESCRIPTION, writer);
991b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
992b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
993b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
994b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // make
995b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        char manufacturer[PROPERTY_VALUE_MAX];
996b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
997b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // Use "" to represent unknown make as suggested in TIFF/EP spec.
998b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        property_get("ro.product.manufacturer", manufacturer, "");
999b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1;
1000b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1001b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_MAKE, count, reinterpret_cast<uint8_t*>(manufacturer),
100247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_MAKE, writer);
1003b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1004b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1005b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1006b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // model
1007b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        char model[PROPERTY_VALUE_MAX];
1008b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1009b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // Use "" to represent unknown model as suggested in TIFF/EP spec.
1010b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        property_get("ro.product.model", model, "");
1011b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t count = static_cast<uint32_t>(strlen(model)) + 1;
1012b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1013b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_MODEL, count, reinterpret_cast<uint8_t*>(model),
101447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_MODEL, writer);
1015b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1016b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1017b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1018b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // x resolution
1019b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t xres[] = { 72, 1 }; // default 72 ppi
1020b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
102147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_XRESOLUTION, writer);
1022b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1023b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // y resolution
1024b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t yres[] = { 72, 1 }; // default 72 ppi
1025b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
102647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_YRESOLUTION, writer);
1027b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1028b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint16_t unit = 2; // inches
1029b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
103047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_RESOLUTIONUNIT, writer);
1031b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1032b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1033b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1034b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // software
1035b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        char software[PROPERTY_VALUE_MAX];
1036b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        property_get("ro.build.fingerprint", software, "");
1037b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t count = static_cast<uint32_t>(strlen(software)) + 1;
1038b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_SOFTWARE, count, reinterpret_cast<uint8_t*>(software),
103947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_SOFTWARE, writer);
1040b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1041b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1042b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1043b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // datetime
1044b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        const size_t DATETIME_COUNT = 20;
1045b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, NULL);
1046b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1047b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        size_t len = strlen(captureTime) + 1;
1048b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        if (len != DATETIME_COUNT) {
1049b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            jniThrowException(env, "java/lang/IllegalArgumentException",
1050b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk                    "Timestamp string length is not required 20 characters");
1051b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            return;
1052b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        }
1053b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
105447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (writer->addEntry(TAG_DATETIME, DATETIME_COUNT,
105547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0) != OK) {
105647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
105747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
105847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Invalid metadata for tag %x", TAG_DATETIME);
105947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
106047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
1061b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1062b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // datetime original
106347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (writer->addEntry(TAG_DATETIMEORIGINAL, DATETIME_COUNT,
106447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                reinterpret_cast<const uint8_t*>(captureTime), TIFF_IFD_0) != OK) {
106547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
106647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
106747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Invalid metadata for tag %x", TAG_DATETIMEORIGINAL);
106847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
106947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
1070b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        env->ReleaseStringUTFChars(formattedCaptureTime, captureTime);
1071b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1072b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1073b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1074b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // TIFF/EP standard id
1075b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint8_t standardId[] = { 1, 0, 0, 0 };
1076b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId,
107747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_TIFFEPSTANDARDID, writer);
1078b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1079b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1080b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1081b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // copyright
1082b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint8_t copyright = '\0'; // empty
1083b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_COPYRIGHT, 1, &copyright,
108447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_COPYRIGHT, writer);
1085b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1086b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1087b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1088b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // exposure time
1089b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        camera_metadata_entry entry =
1090b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            results.find(ANDROID_SENSOR_EXPOSURE_TIME);
109147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_EXPOSURETIME, writer);
1092b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1093b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        int64_t exposureTime = *(entry.data.i64);
1094b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1095b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        if (exposureTime < 0) {
1096b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            // Should be unreachable
1097b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            jniThrowException(env, "java/lang/IllegalArgumentException",
1098b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk                    "Negative exposure time in metadata");
1099b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            return;
1100b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        }
1101b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1102b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // Ensure exposure time doesn't overflow (for exposures > 4s)
1103b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t denominator = 1000000000;
1104b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        while (exposureTime > UINT32_MAX) {
1105b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            exposureTime >>= 1;
1106b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            denominator >>= 1;
1107b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            if (denominator == 0) {
1108b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk                // Should be unreachable
1109b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk                jniThrowException(env, "java/lang/IllegalArgumentException",
1110b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk                        "Exposure time too long");
1111b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk                return;
1112b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            }
1113b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        }
1114b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1115b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t exposure[] = { static_cast<uint32_t>(exposureTime), denominator };
1116b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_EXPOSURETIME, 1, exposure,
111747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_EXPOSURETIME, writer);
1118b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1119b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1120b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1121b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1122b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // ISO speed ratings
1123b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        camera_metadata_entry entry =
1124b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            results.find(ANDROID_SENSOR_SENSITIVITY);
112547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_ISOSPEEDRATINGS, writer);
1126b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1127b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        int32_t tempIso = *(entry.data.i32);
1128b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        if (tempIso < 0) {
1129b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            jniThrowException(env, "java/lang/IllegalArgumentException",
1130b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk                                    "Negative ISO value");
1131b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            return;
1132b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        }
1133b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1134b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        if (tempIso > UINT16_MAX) {
1135b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            ALOGW("%s: ISO value overflows UINT16_MAX, clamping to max", __FUNCTION__);
1136b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            tempIso = UINT16_MAX;
1137b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        }
1138b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1139b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint16_t iso = static_cast<uint16_t>(tempIso);
1140b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso,
114147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_ISOSPEEDRATINGS, writer);
1142b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1143b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1144b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1145b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // focal length
1146b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        camera_metadata_entry entry =
1147b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            results.find(ANDROID_LENS_FOCAL_LENGTH);
114847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_FOCALLENGTH, writer);
1149b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1150b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t focalLength[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
1151b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength,
115247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_FOCALLENGTH, writer);
1153b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1154b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1155b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1156b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        // f number
1157b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        camera_metadata_entry entry =
1158b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            results.find(ANDROID_LENS_APERTURE);
115947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_FNUMBER, writer);
1160b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1161b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        uint32_t fnum[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 };
1162b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_FNUMBER, 1, fnum,
116347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_FNUMBER, writer);
1164b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    }
1165b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk
1166b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk    {
1167f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set DNG version information
1168f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint8_t version[4] = {1, 4, 0, 0};
1169f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
117047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_DNGVERSION, writer);
1171f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1172f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint8_t backwardVersion[4] = {1, 1, 0, 0};
1173f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0),
117447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_DNGBACKWARDVERSION, writer);
1175f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1176f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1177f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1178f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set whitelevel
1179f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry =
1180f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL);
118147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL, writer);
1182f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]);
1183f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env,
118447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_WHITELEVEL, writer);
1185f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1186f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1187f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1188f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set default scale
1189f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint32_t defaultScale[4] = {1, 1, 1, 1};
1190f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0),
119147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_DEFAULTSCALE, writer);
1192f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1193f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1194f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    bool singleIlluminant = false;
1195f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1196f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set calibration illuminants
1197f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry1 =
1198f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
119947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1, writer);
1200f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry2 =
1201f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
1202f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (entry2.count == 0) {
1203f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            singleIlluminant = true;
1204f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1205f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint16_t ref1 = entry1.data.u8[0];
1206f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1207f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
120847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1, writer);
1209f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1210f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (!singleIlluminant) {
1211f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            uint16_t ref2 = entry2.data.u8[0];
1212f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
121347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2, writer);
1214f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1215f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1216f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1217f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1218f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set color transforms
1219f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry1 =
1220f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1);
122147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1, writer);
1222f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1223f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        int32_t colorTransform1[entry1.count * 2];
1224f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1225f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        size_t ctr = 0;
1226f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        for(size_t i = 0; i < entry1.count; ++i) {
1227f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            colorTransform1[ctr++] = entry1.data.r[i].numerator;
1228f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            colorTransform1[ctr++] = entry1.data.r[i].denominator;
1229f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1230f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
123147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1,
123247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_COLORMATRIX1, writer);
1233f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1234f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (!singleIlluminant) {
1235f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2);
123647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2, writer);
1237f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            int32_t colorTransform2[entry2.count * 2];
1238f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1239f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            ctr = 0;
1240f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            for(size_t i = 0; i < entry2.count; ++i) {
1241f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                colorTransform2[ctr++] = entry2.data.r[i].numerator;
1242f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                colorTransform2[ctr++] = entry2.data.r[i].denominator;
1243f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            }
1244f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
124547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2,
124647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    TIFF_IFD_0), env, TAG_COLORMATRIX2, writer);
1247f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1248f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1249f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1250f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1251f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set calibration transforms
1252f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry1 =
1253f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
125447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1, writer);
1255f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1256f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        int32_t calibrationTransform1[entry1.count * 2];
1257f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1258f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        size_t ctr = 0;
1259f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        for(size_t i = 0; i < entry1.count; ++i) {
1260f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            calibrationTransform1[ctr++] = entry1.data.r[i].numerator;
1261f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
1262f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1263f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1264b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count,
1265b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk                calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer);
1266f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1267f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (!singleIlluminant) {
1268f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            camera_metadata_entry entry2 =
1269f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
127047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2, writer);
1271f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            int32_t calibrationTransform2[entry2.count * 2];
1272f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1273f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            ctr = 0;
1274f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            for(size_t i = 0; i < entry2.count; ++i) {
1275f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                calibrationTransform2[ctr++] = entry2.data.r[i].numerator;
1276f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
1277f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            }
1278f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1279b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk            BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count,
12802377cd319f8a77f147f3d70a7ddc75fa9e9fe87cAndreas Gampe                    calibrationTransform2, TIFF_IFD_0),  env, TAG_CAMERACALIBRATION2, writer);
1281f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1282f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1283f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1284f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1285f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set forward transforms
1286f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry1 =
1287f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1);
128847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1, writer);
1289f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1290f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        int32_t forwardTransform1[entry1.count * 2];
1291f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1292f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        size_t ctr = 0;
1293f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        for(size_t i = 0; i < entry1.count; ++i) {
1294f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            forwardTransform1[ctr++] = entry1.data.r[i].numerator;
1295f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            forwardTransform1[ctr++] = entry1.data.r[i].denominator;
1296f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1297f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1298f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1,
129947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_FORWARDMATRIX1, writer);
1300f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1301f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (!singleIlluminant) {
1302f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            camera_metadata_entry entry2 =
1303f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2);
130447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2, writer);
1305f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            int32_t forwardTransform2[entry2.count * 2];
1306f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1307f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            ctr = 0;
1308f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            for(size_t i = 0; i < entry2.count; ++i) {
1309f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                forwardTransform2[ctr++] = entry2.data.r[i].numerator;
1310f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                forwardTransform2[ctr++] = entry2.data.r[i].denominator;
1311f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            }
1312f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1313f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2,
131447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    TIFF_IFD_0),  env, TAG_FORWARDMATRIX2, writer);
1315f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1316f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1317f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1318f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1319f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Set camera neutral
1320f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry =
1321f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
132247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL, writer);
1323f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint32_t cameraNeutral[entry.count * 2];
1324f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1325f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        size_t ctr = 0;
1326f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        for(size_t i = 0; i < entry.count; ++i) {
1327f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            cameraNeutral[ctr++] =
1328f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                    static_cast<uint32_t>(entry.data.r[i].numerator);
1329f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            cameraNeutral[ctr++] =
1330f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                    static_cast<uint32_t>(entry.data.r[i].denominator);
1331f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1332f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1333f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
133447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL, writer);
1335f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1336f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1337f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1338f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Setup data strips
1339f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // TODO: Switch to tiled implementation.
134047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (writer->addStrip(TIFF_IFD_0) != OK) {
134147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: Could not setup strip tags.", __FUNCTION__);
134247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(env, "java/lang/IllegalStateException",
134347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Failed to setup strip tags.");
134447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
134547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
1346f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1347f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1348f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1349f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Setup default crop + crop origin tags
1350f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
1351f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from.
1352f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) {
1353f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            uint32_t defaultCropOrigin[] = {margin, margin};
1354f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            uint32_t defaultCropSize[] = {imageWidth - margin, imageHeight - margin};
1355f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
135647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
1357f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
135847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer);
1359f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1360f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1361f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1362f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1363f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Setup unique camera model tag
1364f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        char model[PROPERTY_VALUE_MAX];
1365f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        property_get("ro.product.model", model, "");
1366f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1367f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        char manufacturer[PROPERTY_VALUE_MAX];
1368f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        property_get("ro.product.manufacturer", manufacturer, "");
1369f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1370f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        char brand[PROPERTY_VALUE_MAX];
1371f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        property_get("ro.product.brand", brand, "");
1372f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1373f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        String8 cameraModel(model);
1374f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        cameraModel += "-";
1375f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        cameraModel += manufacturer;
1376f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        cameraModel += "-";
1377f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        cameraModel += brand;
1378f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1379f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
1380f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
138147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_UNIQUECAMERAMODEL, writer);
1382f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1383f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1384f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {
1385b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk        // Setup sensor noise model
1386b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk        camera_metadata_entry entry =
1387b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk            results.find(ANDROID_SENSOR_NOISE_PROFILE);
1388b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk
1389d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        const status_t numPlaneColors = 3;
1390d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        const status_t numCfaChannels = 4;
1391d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
1392d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        uint8_t cfaOut[numCfaChannels];
1393d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        if ((err = convertCFA(cfaEnum, /*out*/cfaOut)) != OK) {
1394d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            jniThrowException(env, "java/lang/IllegalArgumentException",
1395d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                    "Invalid CFA from camera characteristics");
1396d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            return;
1397d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        }
1398d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
1399d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk        double noiseProfile[numPlaneColors * 2];
1400d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
1401b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk        if (entry.count > 0) {
1402d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            if (entry.count != numCfaChannels * 2) {
140346d8444631b4b1253a76bfcc78a29d26014d022fDan Albert                ALOGW("%s: Invalid entry count %zu for noise profile returned "
140446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert                      "in characteristics, no noise profile tag written...",
140546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert                      __FUNCTION__, entry.count);
1406d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            } else {
1407d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                if ((err = generateNoiseProfile(entry.data.d, cfaOut, numCfaChannels,
1408d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                        cfaPlaneColor, numPlaneColors, /*out*/ noiseProfile)) == OK) {
1409d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk
1410d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                    BAIL_IF_INVALID(writer->addEntry(TAG_NOISEPROFILE, numPlaneColors * 2,
1411d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                            noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE, writer);
1412d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                } else {
1413d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                    ALOGW("%s: Error converting coefficients for noise profile, no noise profile"
1414d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                            " tag written...", __FUNCTION__);
1415d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk                }
1416d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk            }
1417b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk        } else {
1418b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk            ALOGW("%s: No noise profile found in result metadata.  Image quality may be reduced.",
1419b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk                    __FUNCTION__);
1420b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk        }
1421b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk    }
1422b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk
1423b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk    {
1424f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        // Setup opcode List 2
1425f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry1 =
1426f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
142747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
142847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t lsmWidth = 0;
142947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t lsmHeight = 0;
143047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
143147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (entry1.count != 0) {
143247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]);
143347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]);
143447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
1435f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1436f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        camera_metadata_entry entry2 =
1437f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
143847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
143947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (entry2.count > 0 && entry2.count == lsmWidth * lsmHeight * 4) {
1440f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1441f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            OpcodeListBuilder builder;
1442f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            status_t err = builder.addGainMapsForMetadata(lsmWidth,
1443f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                                                          lsmHeight,
1444f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                                                          0,
1445f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                                                          0,
1446f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                                                          imageHeight,
1447f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                                                          imageWidth,
1448f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                                                          opcodeCfaLayout,
1449f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                                                          entry2.data.f);
1450f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            if (err == OK) {
1451f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                size_t listSize = builder.getSize();
1452f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                uint8_t opcodeListBuf[listSize];
1453f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                err = builder.buildOpList(opcodeListBuf);
1454f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                if (err == OK) {
1455f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                    BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
145647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                            TIFF_IFD_0), env, TAG_OPCODELIST2, writer);
1457f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                } else {
1458f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                    ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__);
1459f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                    jniThrowRuntimeException(env, "failed to construct lens shading map opcode.");
1460f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                }
1461f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            } else {
1462f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
1463f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk                jniThrowRuntimeException(env, "failed to add lens shading map.");
1464f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            }
1465f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        } else {
146647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGW("%s: No lens shading map found in result metadata. Image quality may be reduced.",
146747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    __FUNCTION__);
1468f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1469f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1470f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
147147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    DngCreator_setNativeContext(env, thiz, nativeContext);
1472f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
1473f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1474f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_destroy(JNIEnv* env, jobject thiz) {
1475f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
147647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    DngCreator_setNativeContext(env, thiz, NULL);
1477f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
1478f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
147947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) {
1480f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
1481f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
148247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter* writer = DngCreator_getCreator(env, thiz);
148347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (writer == NULL) {
148447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
148547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/AssertionError",
148647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "setOrientation called with uninitialized DngCreator");
148747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
148847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
148947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
149047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint16_t orientation = static_cast<uint16_t>(orient);
149147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
149247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_ORIENTATION, writer);
149347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
149447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Set main image orientation also if in a separate IFD
149547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (writer->hasIfd(TIFF_IFD_SUB1)) {
149647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_SUB1), env,
149747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    TAG_ORIENTATION, writer);
149847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
1499f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
1500f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
150147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) {
1502f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
150347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
150447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter* writer = DngCreator_getCreator(env, thiz);
150547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (writer == NULL) {
150647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
150747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/AssertionError",
150847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "setDescription called with uninitialized DngCreator");
150947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
151047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
151147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
151247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    const char* desc = env->GetStringUTFChars(description, NULL);
151347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    size_t len = strlen(desc) + 1;
151447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
151547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (writer->addEntry(TAG_IMAGEDESCRIPTION, len,
151647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            reinterpret_cast<const uint8_t*>(desc), TIFF_IFD_0) != OK) {
151747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
151847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION);
151947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
152047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
152147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    env->ReleaseStringUTFChars(description, desc);
1522f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
1523f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
152447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetGpsTags(JNIEnv* env, jobject thiz, jintArray latTag, jstring latRef,
152547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jintArray longTag, jstring longRef, jstring dateTag, jintArray timeTag) {
1526f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
1527f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
152847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter* writer = DngCreator_getCreator(env, thiz);
152947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (writer == NULL) {
153047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
153147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/AssertionError",
153247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "setGpsTags called with uninitialized DngCreator");
1533f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return;
1534f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1535f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
153647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (!writer->hasIfd(TIFF_IFD_GPSINFO)) {
153747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_GPSINFO, TiffWriter::GPSINFO) != OK) {
153847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: Failed to add GpsInfo IFD %u to IFD %u", __FUNCTION__, TIFF_IFD_GPSINFO,
153947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    TIFF_IFD_0);
154047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(env, "java/lang/IllegalStateException", "Failed to add GPSINFO");
154147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
154247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
154347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
154447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
154547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    const jsize GPS_VALUE_LENGTH = 6;
154647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jsize latLen = env->GetArrayLength(latTag);
154747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jsize longLen = env->GetArrayLength(longTag);
154847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jsize timeLen = env->GetArrayLength(timeTag);
154947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (latLen != GPS_VALUE_LENGTH) {
155047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/IllegalArgumentException",
155147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "invalid latitude tag length");
155247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
155347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    } else if (longLen != GPS_VALUE_LENGTH) {
155447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/IllegalArgumentException",
155547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "invalid longitude tag length");
1556f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return;
155747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    } else if (timeLen != GPS_VALUE_LENGTH) {
155847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/IllegalArgumentException",
155947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "invalid time tag length");
156047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
156147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
156247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
156347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t latitude[GPS_VALUE_LENGTH];
156447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t longitude[GPS_VALUE_LENGTH];
156547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t timestamp[GPS_VALUE_LENGTH];
156647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
156747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    env->GetIntArrayRegion(latTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
156847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            reinterpret_cast<jint*>(&latitude));
156947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    env->GetIntArrayRegion(longTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
157047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            reinterpret_cast<jint*>(&longitude));
157147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    env->GetIntArrayRegion(timeTag, 0, static_cast<jsize>(GPS_VALUE_LENGTH),
157247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            reinterpret_cast<jint*>(&timestamp));
157347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
157447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    const jsize GPS_REF_LENGTH = 2;
157547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    const jsize GPS_DATE_LENGTH = 11;
157647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint8_t latitudeRef[GPS_REF_LENGTH];
157747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint8_t longitudeRef[GPS_REF_LENGTH];
157847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint8_t date[GPS_DATE_LENGTH];
157947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
158047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    env->GetStringUTFRegion(latRef, 0, 1, reinterpret_cast<char*>(&latitudeRef));
158147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    latitudeRef[GPS_REF_LENGTH - 1] = '\0';
158247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    env->GetStringUTFRegion(longRef, 0, 1, reinterpret_cast<char*>(&longitudeRef));
158347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    longitudeRef[GPS_REF_LENGTH - 1] = '\0';
158447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
158547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    env->GetStringUTFRegion(dateTag, 0, GPS_DATE_LENGTH - 1, reinterpret_cast<char*>(&date));
158647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    date[GPS_DATE_LENGTH - 1] = '\0';
158747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
158847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
158947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint8_t version[] = {2, 3, 0, 0};
159047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_GPSVERSIONID, 4, version,
159147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_GPSINFO), env, TAG_GPSVERSIONID, writer);
159247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
159347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
159447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
159547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_GPSLATITUDEREF, GPS_REF_LENGTH, latitudeRef,
159647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDEREF, writer);
159747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
159847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
159947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
160047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_GPSLONGITUDEREF, GPS_REF_LENGTH, longitudeRef,
160147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDEREF, writer);
1602f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1603f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
160447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
160547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_GPSLATITUDE, 3, latitude,
160647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDE, writer);
160747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
160847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
160947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
161047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_GPSLONGITUDE, 3, longitude,
161147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDE, writer);
161247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
161347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
161447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
161547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_GPSTIMESTAMP, 3, timestamp,
161647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_GPSINFO), env, TAG_GPSTIMESTAMP, writer);
161747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
161847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
161947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
162047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_GPSDATESTAMP, GPS_DATE_LENGTH, date,
162147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_GPSINFO), env, TAG_GPSDATESTAMP, writer);
162247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
162347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
162447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
162547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width,
162647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jint height) {
162747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ALOGV("%s:", __FUNCTION__);
162847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
162947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    NativeContext* context = DngCreator_getNativeContext(env, thiz);
1630f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    TiffWriter* writer = DngCreator_getCreator(env, thiz);
163147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (writer == NULL || context == NULL) {
1632f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
1633f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        jniThrowException(env, "java/lang/AssertionError",
163447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "setThumbnail called with uninitialized DngCreator");
1635f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return;
1636f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
163747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
163847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    size_t fullSize = width * height * BYTES_PER_RGB_PIXEL;
163947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    jlong capacity = env->GetDirectBufferCapacity(buffer);
16400f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampe    if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) {
164147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowExceptionFmt(env, "java/lang/AssertionError",
164247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Invalid size %d for thumbnail, expected size was %d",
164347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                capacity, fullSize);
1644f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return;
1645f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1646f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
164747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
164847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (pixelBytes == NULL) {
164947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__);
165047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer");
1651f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return;
1652f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1653f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
165447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (!writer->hasIfd(TIFF_IFD_SUB1)) {
165547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_SUB1) != OK) {
165647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: Failed to add SubIFD %u to IFD %u", __FUNCTION__, TIFF_IFD_SUB1,
165747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    TIFF_IFD_0);
165847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(env, "java/lang/IllegalStateException", "Failed to add SubIFD");
165947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
166047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
1661f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
166247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        Vector<uint16_t> tagsToMove;
166347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_ORIENTATION);
166447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_NEWSUBFILETYPE);
166547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_BITSPERSAMPLE);
166647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_COMPRESSION);
166747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_IMAGEWIDTH);
166847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_IMAGELENGTH);
166947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_PHOTOMETRICINTERPRETATION);
167047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_BLACKLEVEL);
167147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_BLACKLEVELREPEATDIM);
167247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_SAMPLESPERPIXEL);
167347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_PLANARCONFIGURATION);
167447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_CFAREPEATPATTERNDIM);
167547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_CFAPATTERN);
167647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_CFAPLANECOLOR);
167747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_CFALAYOUT);
167847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_XRESOLUTION);
167947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_YRESOLUTION);
168047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_RESOLUTIONUNIT);
168147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_WHITELEVEL);
168247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_DEFAULTSCALE);
168347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_ROWSPERSTRIP);
168447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_STRIPBYTECOUNTS);
168547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_STRIPOFFSETS);
168647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_DEFAULTCROPORIGIN);
168747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_DEFAULTCROPSIZE);
168847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        tagsToMove.add(TAG_OPCODELIST2);
168947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
169047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) {
169147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries");
169247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
169347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
1694f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
169547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Make sure both IFDs get the same orientation tag
169647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        sp<TiffEntry> orientEntry = writer->getEntry(TAG_ORIENTATION, TIFF_IFD_SUB1);
169747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (orientEntry != NULL) {
169847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            writer->addEntry(orientEntry, TIFF_IFD_0);
1699f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
170047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
170147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
170247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Setup thumbnail tags
170347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
170447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
170547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Set photometric interpretation
170647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint16_t interpretation = 2; // RGB
170747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
170847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer);
170947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
171047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
171147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
171247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Set planar configuration
171347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint16_t config = 1; // Chunky
171447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
171547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_PLANARCONFIGURATION, writer);
171647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
171747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
171847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
171947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Set samples per pixel
172047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint16_t samples = SAMPLES_PER_RGB_PIXEL;
172147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
172247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_SAMPLESPERPIXEL, writer);
172347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
172447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
172547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
172647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Set bits per sample
172747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint16_t bits = BITS_PER_RGB_SAMPLE;
172847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
172947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_BITSPERSAMPLE, writer);
173047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
173147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
173247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
173347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Set subfiletype
173447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t subfileType = 1; // Thumbnail image
173547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
173647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_NEWSUBFILETYPE, writer);
173747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
173847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
173947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
174047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Set compression
174147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint16_t compression = 1; // None
174247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
174347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_COMPRESSION, writer);
174447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
174547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
174647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
174747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Set dimensions
174847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t uWidth = static_cast<uint32_t>(width);
174947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t uHeight = static_cast<uint32_t>(height);
175047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_0), env,
175147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_IMAGEWIDTH, writer);
175247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0), env,
175347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                TAG_IMAGELENGTH, writer);
175447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
175547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
175647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
175747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // x resolution
175847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t xres[] = { 72, 1 }; // default 72 ppi
175947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0),
176047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_XRESOLUTION, writer);
176147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
176247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // y resolution
176347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t yres[] = { 72, 1 }; // default 72 ppi
176447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0),
176547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_YRESOLUTION, writer);
176647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
176747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint16_t unit = 2; // inches
176847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        BAIL_IF_INVALID(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0),
176947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                env, TAG_RESOLUTIONUNIT, writer);
177047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
177147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
177247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {
177347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        // Setup data strips
177447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (writer->addStrip(TIFF_IFD_0) != OK) {
177547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__);
177647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(env, "java/lang/IllegalStateException",
177747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Failed to setup thumbnail strip tags.");
177847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
177947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
178047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (writer->addStrip(TIFF_IFD_SUB1) != OK) {
178147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: Could not main image strip tags.", __FUNCTION__);
178247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(env, "java/lang/IllegalStateException",
178347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Failed to setup main image strip tags.");
178447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
178547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
178647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
178747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
178847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (!context->setThumbnail(pixelBytes, width, height)) {
178947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/IllegalStateException",
179047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Failed to set thumbnail.");
1791f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return;
1792f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
179347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}
1794f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
179547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// TODO: Refactor out common preamble for the two nativeWrite methods.
179647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width,
179747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jint height, jobject inBuffer, jint rowStride, jint pixStride, jlong offset,
179847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jboolean isDirect) {
179947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ALOGV("%s:", __FUNCTION__);
180046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert    ALOGV("%s: nativeWriteImage called with: width=%d, height=%d, "
180146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert          "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width,
180246d8444631b4b1253a76bfcc78a29d26014d022fDan Albert          height, rowStride, pixStride, offset);
180347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t rStride = static_cast<uint32_t>(rowStride);
180447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t pStride = static_cast<uint32_t>(pixStride);
180547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t uWidth = static_cast<uint32_t>(width);
180647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t uHeight = static_cast<uint32_t>(height);
180747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint64_t uOffset = static_cast<uint64_t>(offset);
180847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
180947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    sp<JniOutputStream> out = new JniOutputStream(env, outStream);
181047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if(env->ExceptionCheck()) {
181147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__);
1812f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        return;
1813f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1814f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
181547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter* writer = DngCreator_getCreator(env, thiz);
181647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    NativeContext* context = DngCreator_getNativeContext(env, thiz);
181747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (writer == NULL || context == NULL) {
181847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
181947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/AssertionError",
182047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Write called with uninitialized DngCreator");
182147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
182247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
182347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
182447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Validate DNG header
182547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (!validateDngHeader(env, writer, width, height)) {
182647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
182747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
182847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
182947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    sp<JniInputByteBuffer> inBuf;
183047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    Vector<StripSource*> sources;
183147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    sp<DirectStripSource> thumbnailSource;
183247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t targetIfd = TIFF_IFD_0;
183347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
183447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1);
183547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
183647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (hasThumbnail) {
183747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__);
183847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE;
183947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t thumbWidth = context->getThumbnailWidth();
184047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0,
184147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                thumbWidth, context->getThumbnailHeight(), bytesPerPixel,
184247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                bytesPerPixel * thumbWidth, /*offset*/0, BYTES_PER_RGB_SAMPLE,
184347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                SAMPLES_PER_RGB_PIXEL);
184447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        sources.add(thumbnailSource.get());
184547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        targetIfd = TIFF_IFD_SUB1;
184647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
184747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
184847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (isDirect) {
184947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        size_t fullSize = rStride * uHeight;
185047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jlong capacity = env->GetDirectBufferCapacity(inBuffer);
185147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (capacity < 0 || fullSize + uOffset > static_cast<uint64_t>(capacity)) {
185247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
185347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Invalid size %d for Image, size given in metadata is %d at current stride",
185447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    capacity, fullSize);
1855f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            return;
1856f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
185747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
185847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer));
185947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (pixelBytes == NULL) {
186047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__);
186147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer");
186247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
186347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
186447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
186547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Using direct-type strip source.", __FUNCTION__);
186647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        DirectStripSource stripSource(env, pixelBytes, targetIfd, uWidth, uHeight, pStride,
186747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL);
186847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        sources.add(&stripSource);
186947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
187047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        status_t ret = OK;
187147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) {
187247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: write failed with error %d.", __FUNCTION__, ret);
187347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (!env->ExceptionCheck()) {
187447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                jniThrowExceptionFmt(env, "java/io/IOException",
187547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        "Encountered error %d while writing file.", ret);
1876f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            }
187747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
1878f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1879f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    } else {
188047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        inBuf = new JniInputByteBuffer(env, inBuffer);
188147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
188247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Using input-type strip source.", __FUNCTION__);
188347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        InputStripSource stripSource(env, *inBuf, targetIfd, uWidth, uHeight, pStride,
188447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                 rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL);
188547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        sources.add(&stripSource);
188647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
188747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        status_t ret = OK;
188847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) {
188947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            ALOGE("%s: write failed with error %d.", __FUNCTION__, ret);
189047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            if (!env->ExceptionCheck()) {
189147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                jniThrowExceptionFmt(env, "java/io/IOException",
189247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                        "Encountered error %d while writing file.", ret);
1893f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            }
189447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            return;
1895f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk        }
1896f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    }
1897f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
1898f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1899f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream,
190047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jobject inStream, jint width, jint height, jlong offset) {
1901f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    ALOGV("%s:", __FUNCTION__);
190247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
190347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t rowStride = width * BYTES_PER_SAMPLE;
190447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t pixStride = BYTES_PER_SAMPLE;
190547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t uWidth = static_cast<uint32_t>(width);
190647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t uHeight = static_cast<uint32_t>(height);
190747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint64_t uOffset = static_cast<uint32_t>(offset);
190847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
190946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert    ALOGV("%s: nativeWriteInputStream called with: width=%d, height=%d, "
191046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert          "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width,
191146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert          height, rowStride, pixStride, offset);
191247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
191347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    sp<JniOutputStream> out = new JniOutputStream(env, outStream);
191446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert    if (env->ExceptionCheck()) {
191547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__);
191647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
191747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
191847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
191947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    TiffWriter* writer = DngCreator_getCreator(env, thiz);
192047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    NativeContext* context = DngCreator_getNativeContext(env, thiz);
192147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (writer == NULL || context == NULL) {
192247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
192347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        jniThrowException(env, "java/lang/AssertionError",
192447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                "Write called with uninitialized DngCreator");
192547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
192647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
192747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
192847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    // Validate DNG header
192947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (!validateDngHeader(env, writer, width, height)) {
193047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
193147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
193247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
193347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    sp<DirectStripSource> thumbnailSource;
193447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    uint32_t targetIfd = TIFF_IFD_0;
193547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1);
193647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    Vector<StripSource*> sources;
193747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
193847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if (hasThumbnail) {
193947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__);
194047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE;
194147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        uint32_t width = context->getThumbnailWidth();
194247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0,
194347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                width, context->getThumbnailHeight(), bytesPerPixel,
194447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                bytesPerPixel * width, /*offset*/0, BYTES_PER_RGB_SAMPLE,
194547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                SAMPLES_PER_RGB_PIXEL);
194647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        sources.add(thumbnailSource.get());
194747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        targetIfd = TIFF_IFD_SUB1;
194847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
194947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
195047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    sp<JniInputStream> in = new JniInputStream(env, inStream);
195147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
195247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    ALOGV("%s: Using input-type strip source.", __FUNCTION__);
195347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    InputStripSource stripSource(env, *in, targetIfd, uWidth, uHeight, pixStride,
195447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk             rowStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL);
195547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    sources.add(&stripSource);
195647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk
195747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    status_t ret = OK;
195847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) {
195947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        ALOGE("%s: write failed with error %d.", __FUNCTION__, ret);
196047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        if (!env->ExceptionCheck()) {
196147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            jniThrowExceptionFmt(env, "java/io/IOException",
196247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk                    "Encountered error %d while writing file.", ret);
196347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        }
196447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk        return;
196547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    }
1966f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
1967f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1968f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} /*extern "C" */
1969f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1970f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic JNINativeMethod gDngCreatorMethods[] = {
1971f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {"nativeClassInit",        "()V", (void*) DngCreator_nativeClassInit},
1972f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
1973b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V",
1974b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk            (void*) DngCreator_init},
1975f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {"nativeDestroy",           "()V",      (void*) DngCreator_destroy},
1976f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    {"nativeSetOrientation",    "(I)V",     (void*) DngCreator_nativeSetOrientation},
197747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {"nativeSetDescription",    "(Ljava/lang/String;)V", (void*) DngCreator_nativeSetDescription},
197847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {"nativeSetGpsTags",    "([ILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;[I)V",
197947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk            (void*) DngCreator_nativeSetGpsTags},
198047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {"nativeSetThumbnail","(Ljava/nio/ByteBuffer;II)V", (void*) DngCreator_nativeSetThumbnail},
198147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {"nativeWriteImage",        "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;IIJZ)V",
1982f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            (void*) DngCreator_nativeWriteImage},
198347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk    {"nativeWriteInputStream",    "(Ljava/io/OutputStream;Ljava/io/InputStream;IIJ)V",
1984f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk            (void*) DngCreator_nativeWriteInputStream},
1985f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk};
1986f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk
1987b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunkint register_android_hardware_camera2_DngCreator(JNIEnv *env) {
1988f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk    return AndroidRuntime::registerNativeMethods(env,
1989b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk                   "android/hardware/camera2/DngCreator", gDngCreatorMethods,
1990b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk                   NELEM(gDngCreatorMethods));
1991f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}
1992