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 172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define LOG_NDEBUG 0 18f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#define LOG_TAG "DngCreator_JNI" 1946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <inttypes.h> 2046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <string.h> 21b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk#include <algorithm> 22b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk#include <memory> 239ce22a095685a581823316457217a318fb40c754Ruben Brunk#include <vector> 2446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert 2546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Log.h> 2646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Errors.h> 2746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/StrongPointer.h> 2846d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/RefBase.h> 2946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <utils/Vector.h> 302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#include <utils/String8.h> 3146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert#include <cutils/properties.h> 32f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <system/camera_metadata.h> 33f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <camera/CameraMetadata.h> 34f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/DngUtils.h> 35f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TagDefinitions.h> 36f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffIfd.h> 37f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/TiffWriter.h> 38f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <img_utils/Output.h> 3947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/Input.h> 4047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk#include <img_utils/StripSource.h> 41f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 42ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h" 43b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 44f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/AndroidRuntime.h" 45f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include "android_runtime/android_hardware_camera2_CameraMetadata.h" 46f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 47f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <jni.h> 48f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk#include <JNIHelp.h> 49f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 50f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace android; 51f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkusing namespace img_utils; 52f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_INVALID_RET_BOOL(expr, jnienv, tagId, writer) \ 54f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if ((expr) != OK) { \ 55f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 5647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return false; \ 58f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 59f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_INVALID_RET_NULL_SP(expr, jnienv, tagId, writer) \ 622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if ((expr) != OK) { \ 632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; \ 662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 69b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \ 70b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if ((expr) != OK) { \ 71b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 72b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 73b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return -1; \ 74b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk } 75b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk#define BAIL_IF_EMPTY_RET_NULL_SP(entry, jnienv, tagId, writer) \ 77f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (entry.count == 0) { \ 78f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 7947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Missing metadata fields for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \ 802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; \ 81f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 82f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 84b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunk#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext" 85f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 86f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct { 87f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jfieldID mNativeContext; 88f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gDngCreatorClassInfo; 89f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 90f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic struct { 91f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jmethodID mWriteMethod; 92f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} gOutputStreamClassInfo; 93f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 9447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct { 9547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mReadMethod; 9647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mSkipMethod; 9747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputStreamClassInfo; 9847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 9947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic struct { 10047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jmethodID mGetMethod; 10147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} gInputByteBufferClassInfo; 10247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 103f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkenum { 104f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk BITS_PER_SAMPLE = 16, 105f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk BYTES_PER_SAMPLE = 2, 10647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTES_PER_RGB_PIXEL = 3, 10747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BITS_PER_RGB_SAMPLE = 8, 10847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTES_PER_RGB_SAMPLE = 1, 10947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL = 3, 11047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RAW_PIXEL = 1, 11147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0 = 0, 11247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_SUB1 = 1, 11347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_GPSINFO = 2, 114f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 115f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk/** 1182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk * POD container class for GPS tag data. 1192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk */ 1202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkclass GpsData { 1212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkpublic: 1222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk enum { 1232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_VALUE_LENGTH = 6, 1242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_REF_LENGTH = 2, 1252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GPS_DATE_LENGTH = 11, 1262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk }; 1272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mLatitude[GPS_VALUE_LENGTH]; 1292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mLongitude[GPS_VALUE_LENGTH]; 1302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t mTimestamp[GPS_VALUE_LENGTH]; 1312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mLatitudeRef[GPS_REF_LENGTH]; 1322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mLongitudeRef[GPS_REF_LENGTH]; 1332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t mDate[GPS_DATE_LENGTH]; 1342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk}; 1352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 136f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ---------------------------------------------------------------------------- 137f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 13847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 13947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Container class for the persistent native context. 14047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 14147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 14247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass NativeContext : public LightRefBase<NativeContext> { 14347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 1442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk enum { 1452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DATETIME_COUNT = 20, 1462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk }; 1472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 148b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result); 14947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~NativeContext(); 15047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 15147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TiffWriter* getWriter(); 15247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 153b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<const CameraMetadata> getCharacteristics() const; 154b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<const CameraMetadata> getResult() const; 155b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 1562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t getThumbnailWidth() const; 1572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t getThumbnailHeight() const; 1582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const uint8_t* getThumbnail() const; 1592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasThumbnail() const; 16047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 16147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height); 16247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 1632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setOrientation(uint16_t orientation); 1642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t getOrientation() const; 1652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setDescription(const String8& desc); 1672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 getDescription() const; 1682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasDescription() const; 1692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setGpsData(const GpsData& data); 1712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData getGpsData() const; 1722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasGpsData() const; 1732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk void setCaptureTime(const String8& formattedCaptureTime); 1752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 getCaptureTime() const; 1762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool hasCaptureTime() const; 1772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 17847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 17947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<uint8_t> mCurrentThumbnail; 18047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TiffWriter mWriter; 181b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<CameraMetadata> mCharacteristics; 182b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk std::shared_ptr<CameraMetadata> mResult; 18347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mThumbnailWidth; 18447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mThumbnailHeight; 1852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t mOrientation; 1862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mThumbnailSet; 1872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mGpsSet; 1882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mDescriptionSet; 1892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk bool mCaptureTimeSet; 1902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 mDescription; 1912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData mGpsData; 1922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 mFormattedCaptureTime; 19347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 19447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 195b8f4c6ab1e99a44a51af26dc522819bb833825abRuben BrunkNativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) : 196b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk mCharacteristics(std::make_shared<CameraMetadata>(characteristics)), 197b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0), 1982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mThumbnailHeight(0), mOrientation(0), mThumbnailSet(false), mGpsSet(false), 1992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mDescriptionSet(false), mCaptureTimeSet(false) {} 20047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkNativeContext::~NativeContext() {} 20247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkTiffWriter* NativeContext::getWriter() { 20447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return &mWriter; 20547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 20647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 207b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstd::shared_ptr<const CameraMetadata> NativeContext::getCharacteristics() const { 208b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return mCharacteristics; 209b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 210b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 211b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstd::shared_ptr<const CameraMetadata> NativeContext::getResult() const { 212b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return mResult; 213b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 214b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 2152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint32_t NativeContext::getThumbnailWidth() const { 21647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mThumbnailWidth; 21747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 21847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint32_t NativeContext::getThumbnailHeight() const { 22047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mThumbnailHeight; 22147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 22247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkconst uint8_t* NativeContext::getThumbnail() const { 22447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mCurrentThumbnail.array(); 22547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 22647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasThumbnail() const { 2282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mThumbnailSet; 2292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 23147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkbool NativeContext::setThumbnail(const uint8_t* buffer, uint32_t width, uint32_t height) { 23247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mThumbnailWidth = width; 23347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mThumbnailHeight = height; 23447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 23547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t size = BYTES_PER_RGB_PIXEL * width * height; 23647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mCurrentThumbnail.resize(size) < 0) { 23747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not resize thumbnail buffer.", __FUNCTION__); 23847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 23947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 24047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 24147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* thumb = mCurrentThumbnail.editArray(); 24247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk memcpy(thumb, buffer, size); 2432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mThumbnailSet = true; 24447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return true; 24547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 24647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 2472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setOrientation(uint16_t orientation) { 2482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mOrientation = orientation; 2492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkuint16_t NativeContext::getOrientation() const { 2522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mOrientation; 2532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setDescription(const String8& desc) { 2562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mDescription = desc; 2572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mDescriptionSet = true; 2582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2602079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkString8 NativeContext::getDescription() const { 2612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mDescription; 2622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasDescription() const { 2652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mDescriptionSet; 2662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setGpsData(const GpsData& data) { 2692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mGpsData = data; 2702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mGpsSet = true; 2712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2732079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkGpsData NativeContext::getGpsData() const { 2742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mGpsData; 2752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasGpsData() const { 2782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mGpsSet; 2792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkvoid NativeContext::setCaptureTime(const String8& formattedCaptureTime) { 2822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mFormattedCaptureTime = formattedCaptureTime; 2832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk mCaptureTimeSet = true; 2842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2862079612e5851d73f4672ae3729c883a58adc4dddRuben BrunkString8 NativeContext::getCaptureTime() const { 2872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mFormattedCaptureTime; 2882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 2902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkbool NativeContext::hasCaptureTime() const { 2912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return mCaptureTimeSet; 2922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 2932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 29447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of NativeContext 29547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 29647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 29747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 29847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java OutputStream. 29947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 30047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 30147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 302f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkclass JniOutputStream : public Output, public LightRefBase<JniOutputStream> { 303f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkpublic: 304f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk JniOutputStream(JNIEnv* env, jobject outStream); 305f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 306f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk virtual ~JniOutputStream(); 307f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 308f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t open(); 30947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 310f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t write(const uint8_t* buf, size_t offset, size_t count); 31147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 312f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t close(); 313f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkprivate: 314f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk enum { 31547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 316f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk }; 317f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jobject mOutputStream; 318f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk JNIEnv* mEnv; 319f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jbyteArray mByteArray; 320f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 321f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 322f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream), 323f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv(env) { 324f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 3252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 326f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 327f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 328f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 329f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 330f967a5486a78db244624fde4c105aa5e6fa914b9Ruben BrunkJniOutputStream::~JniOutputStream() { 331f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 332f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 333f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 334f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::open() { 335f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Do nothing 336f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 337f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 338f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 339f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) { 340f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk while(count > 0) { 341f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t len = BYTE_ARRAY_LENGTH; 342f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk len = (count > len) ? len : count; 343f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset)); 344f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 345f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (mEnv->ExceptionCheck()) { 346f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return BAD_VALUE; 347f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 348f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 349f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray, 350f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 0, len); 351f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 352f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (mEnv->ExceptionCheck()) { 353f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return BAD_VALUE; 354f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 355f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 356f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk count -= len; 357f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk offset += len; 358f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 359f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 360f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 361f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 362f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatus_t JniOutputStream::close() { 363f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Do nothing 364f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return OK; 365f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 366f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 36747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniOutputStream 368f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk// ---------------------------------------------------------------------------- 369f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 37047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 37147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a Java InputStream. 37247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 37347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 37447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 37547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputStream : public Input, public LightRefBase<JniInputStream> { 37647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 37747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JniInputStream(JNIEnv* env, jobject inStream); 37847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 37947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t open(); 38047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t close(); 38247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t read(uint8_t* buf, size_t offset, size_t count); 38447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t skip(size_t count); 38647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 38747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~JniInputStream(); 38847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 38947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk enum { 39047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 39147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk }; 39247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject mInStream; 39347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 39447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jbyteArray mByteArray; 39547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 39647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 39747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 39847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::JniInputStream(JNIEnv* env, jobject inStream) : mInStream(inStream), mEnv(env) { 39947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 4002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 40147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 40247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 40347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 40447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 40547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputStream::~JniInputStream() { 40647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 40747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 40847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 40947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::read(uint8_t* buf, size_t offset, size_t count) { 41047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 41147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint realCount = BYTE_ARRAY_LENGTH; 41247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (count < BYTE_ARRAY_LENGTH) { 41347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount = count; 41447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 41547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint actual = mEnv->CallIntMethod(mInStream, gInputStreamClassInfo.mReadMethod, mByteArray, 0, 41647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount); 41747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 41847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (actual < 0) { 41947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return NOT_ENOUGH_DATA; 42047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 42147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 42247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 42347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 42447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 42547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 42647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->GetByteArrayRegion(mByteArray, 0, actual, reinterpret_cast<jbyte*>(buf + offset)); 42747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 42847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 42947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 43047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return actual; 43147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 43247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 43347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputStream::skip(size_t count) { 43447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong actual = mEnv->CallLongMethod(mInStream, gInputStreamClassInfo.mSkipMethod, 43547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk static_cast<jlong>(count)); 43647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 43747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 43847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 43947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 44047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (actual < 0) { 44147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return NOT_ENOUGH_DATA; 44247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 44347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return actual; 44447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 44547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 44647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::open() { 44747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 44847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 44947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 45047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 45147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputStream::close() { 45247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 45347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 45447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 45547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 45647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputStream 45747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 45847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 45947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 46047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * Wrapper class for a non-direct Java ByteBuffer. 46147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 46247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 46347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 46447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass JniInputByteBuffer : public Input, public LightRefBase<JniInputByteBuffer> { 46547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 46647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JniInputByteBuffer(JNIEnv* env, jobject inBuf); 46747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 46847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t open(); 46947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 47047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t close(); 47147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 47247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t read(uint8_t* buf, size_t offset, size_t count); 47347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 47447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~JniInputByteBuffer(); 47547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprivate: 47647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk enum { 47747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk BYTE_ARRAY_LENGTH = 4096 47847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk }; 47947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject mInBuf; 48047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 48147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jbyteArray mByteArray; 48247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 48347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 48447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::JniInputByteBuffer(JNIEnv* env, jobject inBuf) : mInBuf(inBuf), mEnv(env) { 48547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 4862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (mByteArray == nullptr) { 48747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 48847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 48947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 49047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 49147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkJniInputByteBuffer::~JniInputByteBuffer() { 49247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->DeleteLocalRef(mByteArray); 49347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 49447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 49547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkssize_t JniInputByteBuffer::read(uint8_t* buf, size_t offset, size_t count) { 49647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint realCount = BYTE_ARRAY_LENGTH; 49747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (count < BYTE_ARRAY_LENGTH) { 49847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk realCount = count; 49947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 50047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 5015f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, 5025f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk mByteArray, 0, realCount); 503a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk mEnv->DeleteLocalRef(chainingBuf); 50447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 50547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 506a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Exception while reading from input into byte buffer.", __FUNCTION__); 50747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 50847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 50947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 51047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->GetByteArrayRegion(mByteArray, 0, realCount, reinterpret_cast<jbyte*>(buf + offset)); 51147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mEnv->ExceptionCheck()) { 512a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Exception while reading from byte buffer.", __FUNCTION__); 51347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 51447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 51547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return realCount; 51647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 51747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 51847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::open() { 51947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 52047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 52147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 52247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 52347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t JniInputByteBuffer::close() { 52447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Do nothing 52547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 52647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 52747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 52847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of JniInputByteBuffer 52947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 53047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 53147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 53247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for Input types. 53347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 53447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 53547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 53647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 53747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass InputStripSource : public StripSource, public LightRefBase<InputStripSource> { 53847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 53947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width, uint32_t height, 54047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pixStride, uint32_t rowStride, uint64_t offset, uint32_t bytesPerSample, 54147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t samplesPerPixel); 54247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 54347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~InputStripSource(); 54447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 54547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual status_t writeToStream(Output& stream, uint32_t count); 54647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 54747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual uint32_t getIfd() const; 54847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected: 54947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mIfd; 55047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Input* mInput; 55147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mWidth; 55247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mHeight; 55347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mPixStride; 55447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mRowStride; 55547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t mOffset; 55647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 55747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mBytesPerSample; 55847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mSamplesPerPixel; 55947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 56047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 56147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::InputStripSource(JNIEnv* env, Input& input, uint32_t ifd, uint32_t width, 56247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset, 56347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd), mInput(&input), 56447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mWidth(width), mHeight(height), mPixStride(pixStride), mRowStride(rowStride), 56547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample), 56647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mSamplesPerPixel(samplesPerPixel) {} 56747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 56847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkInputStripSource::~InputStripSource() {} 56947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 57047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t InputStripSource::writeToStream(Output& stream, uint32_t count) { 5713e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel; 57247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong offset = mOffset; 57347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 57447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (fullSize != count) { 57547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count, 57647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 57747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write"); 57847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 57947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 58047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 58147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Skip offset 58247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk while (offset > 0) { 58347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t skipped = mInput->skip(offset); 58447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (skipped <= 0) { 58547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (skipped == NOT_ENOUGH_DATA || skipped == 0) { 58647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(mEnv, "java/io/IOException", 58747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Early EOF encountered in skip, not enough pixel data for image of size %u", 58847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 58947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk skipped = NOT_ENOUGH_DATA; 59047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 59147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 59247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", 59347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Error encountered while skip bytes in input stream."); 59447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 59547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 59647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 59747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return skipped; 59847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 59947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk offset -= skipped; 60047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 60147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 60247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<uint8_t> row; 60347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (row.resize(mRowStride) < 0) { 60447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/OutOfMemoryError", "Could not allocate row vector."); 60547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 60647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 60747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 60847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* rowBytes = row.editArray(); 60947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 61047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (uint32_t i = 0; i < mHeight; ++i) { 61147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t rowFillAmt = 0; 612a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk size_t rowSize = mRowStride; 61347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 61447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk while (rowFillAmt < mRowStride) { 61547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ssize_t bytesRead = mInput->read(rowBytes, rowFillAmt, rowSize); 61647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (bytesRead <= 0) { 61747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (bytesRead == NOT_ENOUGH_DATA || bytesRead == 0) { 618a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk ALOGE("%s: Early EOF on row %" PRIu32 ", received bytesRead %zd", 619a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk __FUNCTION__, i, bytesRead); 62047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(mEnv, "java/io/IOException", 621a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk "Early EOF encountered, not enough pixel data for image of size %" 622a3fdec8dac09b178d642c07a538c42faf84c2aaaRuben Brunk PRIu32, fullSize); 62347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesRead = NOT_ENOUGH_DATA; 62447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 62547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 62647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", 62747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Error encountered while reading"); 62847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 62947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 63047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return bytesRead; 63147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 63247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowFillAmt += bytesRead; 63347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowSize -= bytesRead; 63447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 63547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 63647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mPixStride == mBytesPerSample * mSamplesPerPixel) { 63747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using stream per-row write for strip.", __FUNCTION__); 63847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 63947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(rowBytes, 0, mBytesPerSample * mSamplesPerPixel * mWidth) != OK || 64047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->ExceptionCheck()) { 64147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 64247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 64347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 64447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 64547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 64647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 64747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using stream per-pixel write for strip.", __FUNCTION__); 64847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", 64947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous"); 65047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 65147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 65247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // TODO: Add support for non-contiguous pixels if needed. 65347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 65447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 65547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 65647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 65747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 65847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t InputStripSource::getIfd() const { 65947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mIfd; 66047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 66147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 66247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of InputStripSource 66347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 66447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 66547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk/** 66647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * StripSource subclass for direct buffer types. 66747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * 66847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk * This class is not intended to be used across JNI calls. 66947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk */ 67047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkclass DirectStripSource : public StripSource, public LightRefBase<DirectStripSource> { 67247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkpublic: 67347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd, uint32_t width, 67447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t height, uint32_t pixStride, uint32_t rowStride, uint64_t offset, 67547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerSample, uint32_t samplesPerPixel); 67647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual ~DirectStripSource(); 67847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 67947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual status_t writeToStream(Output& stream, uint32_t count); 68047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 68147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk virtual uint32_t getIfd() const; 68247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkprotected: 68347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mIfd; 68447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk const uint8_t* mPixelBytes; 68547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mWidth; 68647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mHeight; 68747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mPixStride; 68847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mRowStride; 68947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t mOffset; 69047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk JNIEnv* mEnv; 69147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mBytesPerSample; 69247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t mSamplesPerPixel; 69347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk}; 69447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 69547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::DirectStripSource(JNIEnv* env, const uint8_t* pixelBytes, uint32_t ifd, 69647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t width, uint32_t height, uint32_t pixStride, uint32_t rowStride, 69747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t offset, uint32_t bytesPerSample, uint32_t samplesPerPixel) : mIfd(ifd), 69847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mPixelBytes(pixelBytes), mWidth(width), mHeight(height), mPixStride(pixStride), 69947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mRowStride(rowStride), mOffset(offset), mEnv(env), mBytesPerSample(bytesPerSample), 70047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mSamplesPerPixel(samplesPerPixel) {} 70147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 70247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben BrunkDirectStripSource::~DirectStripSource() {} 70347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 70447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatus_t DirectStripSource::writeToStream(Output& stream, uint32_t count) { 7053e1902504979b9b456a14dffa6507ee2d9ea3d6aRuben Brunk uint32_t fullSize = mWidth * mHeight * mBytesPerSample * mSamplesPerPixel; 70647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 70747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (fullSize != count) { 70847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Amount to write %u doesn't match image size %u", __FUNCTION__, count, 70947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk fullSize); 71047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", "Not enough data to write"); 71147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 71247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 71347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 7142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 71547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (mPixStride == mBytesPerSample * mSamplesPerPixel 71647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk && mRowStride == mWidth * mBytesPerSample * mSamplesPerPixel) { 71747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct single-pass write for strip.", __FUNCTION__); 71847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 71947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(mPixelBytes, mOffset, fullSize) != OK || mEnv->ExceptionCheck()) { 72047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 72147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 72247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 72347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 72447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 72547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else if (mPixStride == mBytesPerSample * mSamplesPerPixel) { 72647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct per-row write for strip.", __FUNCTION__); 72747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 72847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (size_t i = 0; i < mHeight; ++i) { 72947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (stream.write(mPixelBytes, mOffset + i * mRowStride, mPixStride * mWidth) != OK || 73047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk mEnv->ExceptionCheck()) { 73147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!mEnv->ExceptionCheck()) { 73247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/io/IOException", "Failed to write pixel data"); 73347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 73447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 73547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 73647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 73747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } else { 73847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct per-pixel write for strip.", __FUNCTION__); 73947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 74047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(mEnv, "java/lang/IllegalStateException", 74147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Per-pixel strides are not supported for RAW16 -- pixels must be contiguous"); 74247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 74347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 74447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // TODO: Add support for non-contiguous pixels if needed. 74547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 74647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 74747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 74847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 74947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 75047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkuint32_t DirectStripSource::getIfd() const { 75147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return mIfd; 75247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 75347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 75447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// End of DirectStripSource 75547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 75647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 757b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk/** 758a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk * Calculate the default crop relative to the "active area" of the image sensor (this active area 759a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk * will always be the pre-correction active area rectangle), and set this. 760b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk */ 761b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunkstatic status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics, 762a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk sp<TiffWriter> writer) { 763b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 764b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry entry = 7652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 766b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 767b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 768b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 7692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation. 7702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 771a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk if (width < margin * 2 || height < margin * 2) { 772a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk ALOGE("%s: Cannot calculate default crop for image, pre-correction active area is too" 773a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk "small: h=%" PRIu32 ", w=%" PRIu32, __FUNCTION__, height, width); 774a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk jniThrowException(env, "java/lang/IllegalStateException", 775a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk "Pre-correction active area is too small."); 776a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk return BAD_VALUE; 7772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 7782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 779a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk uint32_t defaultCropOrigin[] = {margin, margin}; 780a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk uint32_t defaultCropSize[] = {width - defaultCropOrigin[0] - margin, 781a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk height - defaultCropOrigin[1] - margin}; 782a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk 783b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin, 784b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer); 785b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize, 786b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE, writer); 787b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 788b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return OK; 789b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk} 79047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 7912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic bool validateDngHeader(JNIEnv* env, sp<TiffWriter> writer, 792b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk const CameraMetadata& characteristics, jint width, jint height) { 793b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (width <= 0) { 794b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 795b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image width %d is invalid", width); 796b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk return false; 797b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk } 79847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 799b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (height <= 0) { 80047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 801b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image height %d is invalid", height); 80247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 80347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 80447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 805b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry preCorrectionEntry = 806b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 807b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_ro_entry pixelArrayEntry = 808b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE); 809b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 810b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int pWidth = static_cast<int>(pixelArrayEntry.data.i32[0]); 811b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int pHeight = static_cast<int>(pixelArrayEntry.data.i32[1]); 812b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int cWidth = static_cast<int>(preCorrectionEntry.data.i32[2]); 813b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk int cHeight = static_cast<int>(preCorrectionEntry.data.i32[3]); 814b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 815b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk bool matchesPixelArray = (pWidth == width && pHeight == height); 816b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk bool matchesPreCorrectionArray = (cWidth == width && cHeight == height); 817b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk 8182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!(matchesPixelArray || matchesPreCorrectionArray)) { 81947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ 820b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "Image dimensions (w=%d,h=%d) are invalid, must match either the pixel " 821b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk "array size (w=%d, h=%d) or the pre-correction array size (w=%d, h=%d)", 822b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk width, height, pWidth, pHeight, cWidth, cHeight); 82347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return false; 82447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 82547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 82647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return true; 82747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 82847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 8292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic status_t moveEntries(sp<TiffWriter> writer, uint32_t ifdFrom, uint32_t ifdTo, 83047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk const Vector<uint16_t>& entries) { 83147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk for (size_t i = 0; i < entries.size(); ++i) { 83247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t tagId = entries[i]; 83347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<TiffEntry> entry = writer->getEntry(tagId, ifdFrom); 8342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (entry.get() == nullptr) { 83547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: moveEntries failed, entry %u not found in IFD %u", __FUNCTION__, tagId, 83647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ifdFrom); 83747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 83847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 83947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (writer->addEntry(entry, ifdTo) != OK) { 84047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: moveEntries failed, could not add entry %u to IFD %u", __FUNCTION__, tagId, 84147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ifdFrom); 84247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return BAD_VALUE; 84347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 84447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk writer->removeEntry(tagId, ifdFrom); 84547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 84647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return OK; 84747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 84847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 849d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 850d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Write CFA pattern for given CFA enum into cfaOut. cfaOut must have length >= 4. 851d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Returns OK on success, or a negative error code if the CFA enum was invalid. 852d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 853d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic status_t convertCFA(uint8_t cfaEnum, /*out*/uint8_t* cfaOut) { 854d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa = 855d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>( 856d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum); 857d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk switch(cfa) { 858d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: { 859d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 0; 860d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 1; 861d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 1; 862d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 2; 863d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 864d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 865d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: { 866d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 1; 867d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 0; 868d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 2; 869d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 1; 870d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 871d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 872d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: { 873d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 1; 874d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 2; 875d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 0; 876d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 1; 877d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 878d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 879d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: { 880d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[0] = 2; 881d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[1] = 1; 882d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[2] = 1; 883d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaOut[3] = 0; 884d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk break; 885d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 886d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk default: { 887d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return BAD_VALUE; 888d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 889d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 890d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OK; 891d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 892d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 893d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 894d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * Convert the CFA layout enum to an OpcodeListBuilder::CfaLayout enum, defaults to 895d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * RGGB for an unknown enum. 896d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 897d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic OpcodeListBuilder::CfaLayout convertCFAEnumToOpcodeLayout(uint8_t cfaEnum) { 898d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa = 899d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>( 900d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum); 901d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk switch(cfa) { 902d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: { 903d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_RGGB; 904d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 905d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: { 906d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_GRBG; 907d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 908d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: { 909d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_GBRG; 910d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 911d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: { 912d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_BGGR; 913d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 914d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk default: { 915d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OpcodeListBuilder::CFA_RGGB; 916d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 917d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 918d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 919d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 920d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk/** 921d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * For each color plane, find the corresponding noise profile coefficients given in the 922d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * per-channel noise profile. If multiple channels in the CFA correspond to a color in the color 923d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * plane, this method takes the pair of noise profile coefficients with the higher S coefficient. 924d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * 925d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * perChannelNoiseProfile - numChannels * 2 noise profile coefficients. 926d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * cfa - numChannels color channels corresponding to each of the per-channel noise profile 927d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * coefficients. 928d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * numChannels - the number of noise profile coefficient pairs and color channels given in 929d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * the perChannelNoiseProfile and cfa arguments, respectively. 930d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * planeColors - the color planes in the noise profile output. 931d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * numPlanes - the number of planes in planeColors and pairs of coefficients in noiseProfile. 932d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * noiseProfile - 2 * numPlanes doubles containing numPlanes pairs of noise profile coefficients. 933d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * 934d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk * returns OK, or a negative error code on failure. 935d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk */ 936d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunkstatic status_t generateNoiseProfile(const double* perChannelNoiseProfile, uint8_t* cfa, 937d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t numChannels, const uint8_t* planeColors, size_t numPlanes, 938d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk /*out*/double* noiseProfile) { 939d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 940d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk for (size_t p = 0; p < numPlanes; ++p) { 941d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t S = p * 2; 942d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk size_t O = p * 2 + 1; 943d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 944d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[S] = 0; 945d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[O] = 0; 946d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk bool uninitialized = true; 947d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk for (size_t c = 0; c < numChannels; ++c) { 948d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (cfa[c] == planeColors[p] && perChannelNoiseProfile[c * 2] > noiseProfile[S]) { 949d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[S] = perChannelNoiseProfile[c * 2]; 950d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk noiseProfile[O] = perChannelNoiseProfile[c * 2 + 1]; 951d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uninitialized = false; 952d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 953d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 954d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (uninitialized) { 95546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGE("%s: No valid NoiseProfile coefficients for color plane %zu", 95646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert __FUNCTION__, p); 957d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return BAD_VALUE; 958d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 959d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 960d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk return OK; 961d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk} 962d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 96347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// ---------------------------------------------------------------------------- 964f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkextern "C" { 965f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 96647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic NativeContext* DngCreator_getNativeContext(JNIEnv* env, jobject thiz) { 967f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 96847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return reinterpret_cast<NativeContext*>(env->GetLongField(thiz, 969f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk gDngCreatorClassInfo.mNativeContext)); 970f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 971f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 97247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_setNativeContext(JNIEnv* env, jobject thiz, sp<NativeContext> context) { 973f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 97447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* current = DngCreator_getNativeContext(env, thiz); 97547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 9762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context != nullptr) { 97747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk context->incStrong((void*) DngCreator_setNativeContext); 978f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 97947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 980f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (current) { 98147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk current->decStrong((void*) DngCreator_setNativeContext); 982f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 98347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 984f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext, 98547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk reinterpret_cast<jlong>(context.get())); 98647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 98747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 988f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) { 989f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 990f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 991ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gDngCreatorClassInfo.mNativeContext = GetFieldIDOrDie(env, 992ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe clazz, ANDROID_DNGCREATOR_CTX_JNI_ID, "J"); 993ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 994ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass outputStreamClazz = FindClassOrDie(env, "java/io/OutputStream"); 995ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOutputStreamClassInfo.mWriteMethod = GetMethodIDOrDie(env, 996ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe outputStreamClazz, "write", "([BII)V"); 997ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 998ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass inputStreamClazz = FindClassOrDie(env, "java/io/InputStream"); 999ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputStreamClassInfo.mReadMethod = GetMethodIDOrDie(env, inputStreamClazz, "read", "([BII)I"); 1000ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputStreamClassInfo.mSkipMethod = GetMethodIDOrDie(env, inputStreamClazz, "skip", "(J)J"); 1001ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 1002ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass inputBufferClazz = FindClassOrDie(env, "java/nio/ByteBuffer"); 1003ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInputByteBufferClassInfo.mGetMethod = GetMethodIDOrDie(env, 1004ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe inputBufferClazz, "get", "([BII)Ljava/nio/ByteBuffer;"); 1005f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 1006f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1007f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr, 1008b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jobject resultsPtr, jstring formattedCaptureTime) { 1009f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 1010f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk CameraMetadata characteristics; 1011f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk CameraMetadata results; 1012f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) { 1013f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 1014f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk "No native metadata defined for camera characteristics."); 1015f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 1016f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1017f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) { 1018f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 1019f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk "No native metadata defined for capture results."); 1020f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 1021f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1022f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1023b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk sp<NativeContext> nativeContext = new NativeContext(characteristics, results); 10242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const char* captureTime = env->GetStringUTFChars(formattedCaptureTime, nullptr); 10262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk size_t len = strlen(captureTime) + 1; 10282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (len != NativeContext::DATETIME_COUNT) { 10292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 10302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Formatted capture time string length is not required 20 characters"); 10312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 10322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk nativeContext->setCaptureTime(String8(captureTime)); 10352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DngCreator_setNativeContext(env, thiz, nativeContext); 10372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk} 10382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t imageWidth, 10402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t imageHeight) { 10412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* nativeContext = DngCreator_getNativeContext(env, thiz); 10432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext == nullptr) { 10452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/AssertionError", 10462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "No native context, must call init before other operations."); 10472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 10482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk CameraMetadata characteristics = *(nativeContext->getCharacteristics()); 10512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk CameraMetadata results = *(nativeContext->getResult()); 10522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = new TiffWriter(); 10542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t preWidth = 0; 10562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t preHeight = 0; 10572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 10582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Check dimensions 10592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry entry = 10602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 10612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer); 10622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk preWidth = static_cast<uint32_t>(entry.data.i32[2]); 10632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk preHeight = static_cast<uint32_t>(entry.data.i32[3]); 10642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry pixelArrayEntry = 10662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE); 10672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t pixWidth = static_cast<uint32_t>(pixelArrayEntry.data.i32[0]); 10682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t pixHeight = static_cast<uint32_t>(pixelArrayEntry.data.i32[1]); 10692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!((imageWidth == preWidth && imageHeight == preHeight) || 10712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk (imageWidth == pixWidth && imageHeight == pixHeight))) { 10722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/AssertionError", 10732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Height and width of imate buffer did not match height and width of" 10742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "either the preCorrectionActiveArraySize or the pixelArraySize."); 10752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 10762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 10782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 10792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1080f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1081f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk writer->addIfd(TIFF_IFD_0); 1082f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1083f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk status_t err = OK; 1084f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1085f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk const uint32_t samplesPerPixel = 1; 1086f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk const uint32_t bitsPerSample = BITS_PER_SAMPLE; 1087f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1088f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB; 1089d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaPlaneColor[3] = {0, 1, 2}; 1090d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaEnum = -1; 1091f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1092f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // TODO: Greensplit. 1093f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // TODO: Add remaining non-essential tags 109447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 109547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk // Setup main image tags 109647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 1097f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1098f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set orientation 1099f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t orientation = 1; // Normal 11002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), 11012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ORIENTATION, writer); 1102f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1103f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1104f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1105f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set subfiletype 1106f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t subfileType = 0; // Main image 11072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, 11082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer); 1109f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1110f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1111f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1112f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set bits per sample 1113f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t bits = static_cast<uint16_t>(bitsPerSample); 11142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env, 111547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TAG_BITSPERSAMPLE, writer); 1116f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1117f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1118f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1119f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set compression 1120f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t compression = 1; // None 11212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression, 11222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_COMPRESSION, writer); 1123f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1124f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1125f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1126f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set dimensions 11272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &imageWidth, TIFF_IFD_0), 11282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGEWIDTH, writer); 11292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &imageHeight, TIFF_IFD_0), 11302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGELENGTH, writer); 1131f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1132f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1133f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1134f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set photometric interpretation 113547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t interpretation = 32803; // CFA 11362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, 11372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer); 1138f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1139f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1140f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1141f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set blacklevel tags 1142f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1143f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN); 11442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BLACKLEVEL, writer); 1145f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32); 11462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, 11472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_BLACKLEVEL, writer); 1148f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1149f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t repeatDim[2] = {2, 2}; 11502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, 11512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_BLACKLEVELREPEATDIM, writer); 1152f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1153f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1154f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1155f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set samples per pixel 1156f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t samples = static_cast<uint16_t>(samplesPerPixel); 11572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0), 115847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_SAMPLESPERPIXEL, writer); 1159f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1160f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1161f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1162f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set planar configuration 1163f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t config = 1; // Chunky 11642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, 11652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer); 1166f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1167f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1168f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1169f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA pattern dimensions 1170f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t repeatDim[2] = {2, 2}; 11712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, 11722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_CFAREPEATPATTERNDIM, writer); 1173f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1174f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1175f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1176f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA pattern 1177f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1178f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); 11792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_CFAPATTERN, writer); 1180d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1181d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const int cfaLength = 4; 1182d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaEnum = entry.data.u8[0]; 1183d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfa[cfaLength]; 1184d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = convertCFA(cfaEnum, /*out*/cfa)) != OK) { 1185d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 1186d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk "Invalid metadata for tag %d", TAG_CFAPATTERN); 1187f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1188d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 11892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPATTERN, cfaLength, cfa, TIFF_IFD_0), 11902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_CFAPATTERN, writer); 1191d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1192d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk opcodeCfaLayout = convertCFAEnumToOpcodeLayout(cfaEnum); 1193f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1194f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1195f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1196f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA plane color 11972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, 11982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_CFAPLANECOLOR, writer); 1199f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1200f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1201f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1202f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set CFA layout 1203f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t cfaLayout = 1; 12042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0), 120547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_CFALAYOUT, writer); 1206f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1207f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1208f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1209b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // image description 1210b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t imageDescription = '\0'; // empty 12112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEDESCRIPTION, 1, &imageDescription, 12122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_IMAGEDESCRIPTION, writer); 1213b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1214b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1215b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1216b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // make 1217b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char manufacturer[PROPERTY_VALUE_MAX]; 1218b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1219b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Use "" to represent unknown make as suggested in TIFF/EP spec. 1220b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.product.manufacturer", manufacturer, ""); 1221b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(manufacturer)) + 1; 1222b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MAKE, count, 12242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(manufacturer), TIFF_IFD_0), env, TAG_MAKE, writer); 1225b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1226b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1227b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1228b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // model 1229b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char model[PROPERTY_VALUE_MAX]; 1230b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1231b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Use "" to represent unknown model as suggested in TIFF/EP spec. 1232b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.product.model", model, ""); 1233b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(model)) + 1; 1234b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_MODEL, count, 12362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(model), TIFF_IFD_0), env, TAG_MODEL, writer); 1237b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1238b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1239b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1240b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // x resolution 1241b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t xres[] = { 72, 1 }; // default 72 ppi 12422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0), 124347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_XRESOLUTION, writer); 1244b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1245b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // y resolution 1246b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t yres[] = { 72, 1 }; // default 72 ppi 12472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0), 124847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_YRESOLUTION, writer); 1249b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1250b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint16_t unit = 2; // inches 12512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0), 125247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_RESOLUTIONUNIT, writer); 1253b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1254b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1255b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1256b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // software 1257b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk char software[PROPERTY_VALUE_MAX]; 1258b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk property_get("ro.build.fingerprint", software, ""); 1259b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t count = static_cast<uint32_t>(strlen(software)) + 1; 12602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SOFTWARE, count, 12612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<uint8_t*>(software), TIFF_IFD_0), env, TAG_SOFTWARE, writer); 1262b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1263b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasCaptureTime()) { 1265b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // datetime 12662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 captureTime = nativeContext->getCaptureTime(); 1267b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 12682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_DATETIME, NativeContext::DATETIME_COUNT, 12692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) { 127047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 127147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %x", TAG_DATETIME); 12722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 127347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1274b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1275b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // datetime original 12762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_DATETIMEORIGINAL, NativeContext::DATETIME_COUNT, 12772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) { 127847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 127947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid metadata for tag %x", TAG_DATETIMEORIGINAL); 12802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 128147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1282b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1283b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1284b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1285b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // TIFF/EP standard id 1286b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t standardId[] = { 1, 0, 0, 0 }; 12872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_TIFFEPSTANDARDID, 4, standardId, 128847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_TIFFEPSTANDARDID, writer); 1289b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1290b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1291b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1292b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // copyright 1293b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint8_t copyright = '\0'; // empty 12942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COPYRIGHT, 1, ©right, 129547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_COPYRIGHT, writer); 1296b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1297b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1298b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1299b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // exposure time 1300b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1301b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_SENSOR_EXPOSURE_TIME); 13022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_EXPOSURETIME, writer); 1303b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1304b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk int64_t exposureTime = *(entry.data.i64); 1305b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1306b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (exposureTime < 0) { 1307b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Should be unreachable 1308b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1309b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Negative exposure time in metadata"); 13102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1311b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1312b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1313b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Ensure exposure time doesn't overflow (for exposures > 4s) 1314b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t denominator = 1000000000; 1315b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk while (exposureTime > UINT32_MAX) { 1316b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk exposureTime >>= 1; 1317b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk denominator >>= 1; 1318b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (denominator == 0) { 1319b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // Should be unreachable 1320b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1321b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Exposure time too long"); 13222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1323b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1324b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1325b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1326b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t exposure[] = { static_cast<uint32_t>(exposureTime), denominator }; 13272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_EXPOSURETIME, 1, exposure, 132847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_EXPOSURETIME, writer); 1329b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1330b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1331b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1332b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1333b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // ISO speed ratings 1334b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1335b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_SENSOR_SENSITIVITY); 13362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ISOSPEEDRATINGS, writer); 1337b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1338b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk int32_t tempIso = *(entry.data.i32); 1339b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (tempIso < 0) { 1340b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1341b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Negative ISO value"); 13422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1343b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1344b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1345b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk if (tempIso > UINT16_MAX) { 1346b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk ALOGW("%s: ISO value overflows UINT16_MAX, clamping to max", __FUNCTION__); 1347b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk tempIso = UINT16_MAX; 1348b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1349b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1350b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint16_t iso = static_cast<uint16_t>(tempIso); 13512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ISOSPEEDRATINGS, 1, &iso, 135247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_ISOSPEEDRATINGS, writer); 1353b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1354b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1355b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1356b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // focal length 1357b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1358b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_LENS_FOCAL_LENGTH); 13592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FOCALLENGTH, writer); 1360b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1361b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t focalLength[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 }; 13622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FOCALLENGTH, 1, focalLength, 136347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_FOCALLENGTH, writer); 1364b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1365b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1366b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1367b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk // f number 1368b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk camera_metadata_entry entry = 1369b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk results.find(ANDROID_LENS_APERTURE); 13702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_FNUMBER, writer); 1371b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1372b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk uint32_t fnum[] = { static_cast<uint32_t>(*(entry.data.f) * 100), 100 }; 13732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FNUMBER, 1, fnum, 137447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_FNUMBER, writer); 1375b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk } 1376b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk 1377b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk { 1378f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set DNG version information 1379f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint8_t version[4] = {1, 4, 0, 0}; 13802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0), 138147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env, TAG_DNGVERSION, writer); 1382f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1383f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint8_t backwardVersion[4] = {1, 1, 0, 0}; 13842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, 13852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_DNGBACKWARDVERSION, writer); 1386f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1387f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1388f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1389f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set whitelevel 1390f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1391f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL); 13922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_WHITELEVEL, writer); 1393f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]); 13942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), 13952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_WHITELEVEL, writer); 1396f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1397f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1398f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1399f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set default scale 1400f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t defaultScale[4] = {1, 1, 1, 1}; 14012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, 14022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_DEFAULTSCALE, writer); 1403f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1404f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1405f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk bool singleIlluminant = false; 1406f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1407f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set calibration illuminants 1408f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1409f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1); 14102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CALIBRATIONILLUMINANT1, writer); 1411f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1412f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2); 1413f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (entry2.count == 0) { 1414f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk singleIlluminant = true; 1415f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1416f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t ref1 = entry1.data.u8[0]; 1417f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1, 141947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1, writer); 1420f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1421f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1422f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint16_t ref2 = entry2.data.u8[0]; 14232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2, 142447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2, writer); 1425f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1426f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1427f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1428f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1429f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set color transforms 1430f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1431f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1); 14322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_COLORMATRIX1, writer); 1433f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1434f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t colorTransform1[entry1.count * 2]; 1435f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1436f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1437f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1438f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform1[ctr++] = entry1.data.r[i].numerator; 1439f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform1[ctr++] = entry1.data.r[i].denominator; 1440f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1441f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX1, entry1.count, 14432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk colorTransform1, TIFF_IFD_0), env, TAG_COLORMATRIX1, writer); 1444f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1445f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1446f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2); 14472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_COLORMATRIX2, writer); 1448f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t colorTransform2[entry2.count * 2]; 1449f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1450f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1451f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1452f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform2[ctr++] = entry2.data.r[i].numerator; 1453f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk colorTransform2[ctr++] = entry2.data.r[i].denominator; 1454f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1455f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COLORMATRIX2, entry2.count, 14572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk colorTransform2, TIFF_IFD_0), env, TAG_COLORMATRIX2, writer); 1458f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1459f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1460f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1461f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1462f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set calibration transforms 1463f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1464f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1); 14652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_CAMERACALIBRATION1, writer); 1466f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1467f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t calibrationTransform1[entry1.count * 2]; 1468f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1469f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1470f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1471f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform1[ctr++] = entry1.data.r[i].numerator; 1472f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform1[ctr++] = entry1.data.r[i].denominator; 1473f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1474f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, 1476b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk calibrationTransform1, TIFF_IFD_0), env, TAG_CAMERACALIBRATION1, writer); 1477f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1478f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1479f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1480f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2); 14812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_CAMERACALIBRATION2, writer); 1482f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t calibrationTransform2[entry2.count * 2]; 1483f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1484f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1485f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1486f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform2[ctr++] = entry2.data.r[i].numerator; 1487f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk calibrationTransform2[ctr++] = entry2.data.r[i].denominator; 1488f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1489f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 14902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, 14912377cd319f8a77f147f3d70a7ddc75fa9e9fe87cAndreas Gampe calibrationTransform2, TIFF_IFD_0), env, TAG_CAMERACALIBRATION2, writer); 1492f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1493f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1494f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1495f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1496f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set forward transforms 1497f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1498f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1); 14992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry1, env, TAG_FORWARDMATRIX1, writer); 1500f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1501f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t forwardTransform1[entry1.count * 2]; 1502f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1503f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1504f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry1.count; ++i) { 1505f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform1[ctr++] = entry1.data.r[i].numerator; 1506f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform1[ctr++] = entry1.data.r[i].denominator; 1507f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1508f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, 15102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk forwardTransform1, TIFF_IFD_0), env, TAG_FORWARDMATRIX1, writer); 1511f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1512f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk if (!singleIlluminant) { 1513f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry2 = 1514f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2); 15152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry2, env, TAG_FORWARDMATRIX2, writer); 1516f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk int32_t forwardTransform2[entry2.count * 2]; 1517f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1518f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ctr = 0; 1519f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry2.count; ++i) { 1520f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform2[ctr++] = entry2.data.r[i].numerator; 1521f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk forwardTransform2[ctr++] = entry2.data.r[i].denominator; 1522f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1523f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, 15252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk forwardTransform2, TIFF_IFD_0), env, TAG_FORWARDMATRIX2, writer); 1526f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1527f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1528f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1529f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1530f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Set camera neutral 1531f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry = 1532f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT); 15332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ASSHOTNEUTRAL, writer); 1534f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk uint32_t cameraNeutral[entry.count * 2]; 1535f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1536f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk size_t ctr = 0; 1537f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk for(size_t i = 0; i < entry.count; ++i) { 1538f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraNeutral[ctr++] = 1539f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk static_cast<uint32_t>(entry.data.r[i].numerator); 1540f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraNeutral[ctr++] = 1541f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk static_cast<uint32_t>(entry.data.r[i].denominator); 1542f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1543f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral, 154547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL, writer); 1546f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1547f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1548f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1549f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1550b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk // Set dimensions 1551a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk if (calculateAndSetCrop(env, characteristics, writer) != OK) { 15522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 15532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 1554b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk camera_metadata_entry entry = 1555b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 1556a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ACTIVEAREA, writer); 1557b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); 1558b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); 1559b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 1560b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 15612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 1562a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk // If we only have a buffer containing the pre-correction rectangle, ignore the offset 1563a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk // relative to the pixel array. 1564a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk if (imageWidth == width && imageHeight == height) { 1565a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk xmin = 0; 1566a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk ymin = 0; 1567a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk } 1568a4ff47ced1ebed01722b77bc417d5a4eb51d0af9Ruben Brunk 15692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t activeArea[] = {ymin, xmin, ymin + height, xmin + width}; 15702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ACTIVEAREA, 4, activeArea, TIFF_IFD_0), 15712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ACTIVEAREA, writer); 1572f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1573f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1574f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1575f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk // Setup unique camera model tag 1576f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char model[PROPERTY_VALUE_MAX]; 1577f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.model", model, ""); 1578f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1579f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char manufacturer[PROPERTY_VALUE_MAX]; 1580f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.manufacturer", manufacturer, ""); 1581f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1582f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk char brand[PROPERTY_VALUE_MAX]; 1583f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk property_get("ro.product.brand", brand, ""); 1584f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1585f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk String8 cameraModel(model); 1586f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += "-"; 1587f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += manufacturer; 1588f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += "-"; 1589f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk cameraModel += brand; 1590f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 15912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1, 1592f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env, 159347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk TAG_UNIQUECAMERAMODEL, writer); 1594f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1595f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1596f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk { 1597b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk // Setup sensor noise model 1598b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk camera_metadata_entry entry = 1599b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk results.find(ANDROID_SENSOR_NOISE_PROFILE); 1600b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk 1601d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const status_t numPlaneColors = 3; 1602d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk const status_t numCfaChannels = 4; 1603d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1604d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk uint8_t cfaOut[numCfaChannels]; 1605d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = convertCFA(cfaEnum, /*out*/cfaOut)) != OK) { 1606d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 1607d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk "Invalid CFA from camera characteristics"); 16082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1609d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1610d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1611d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk double noiseProfile[numPlaneColors * 2]; 1612d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 1613b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk if (entry.count > 0) { 1614d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if (entry.count != numCfaChannels * 2) { 161546d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGW("%s: Invalid entry count %zu for noise profile returned " 161646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "in characteristics, no noise profile tag written...", 161746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert __FUNCTION__, entry.count); 1618d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } else { 1619d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk if ((err = generateNoiseProfile(entry.data.d, cfaOut, numCfaChannels, 1620d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk cfaPlaneColor, numPlaneColors, /*out*/ noiseProfile)) == OK) { 1621d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk 16222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NOISEPROFILE, 16232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk numPlaneColors * 2, noiseProfile, TIFF_IFD_0), env, TAG_NOISEPROFILE, 16242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk writer); 1625d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } else { 1626d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk ALOGW("%s: Error converting coefficients for noise profile, no noise profile" 1627d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk " tag written...", __FUNCTION__); 1628d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1629d70132c373eee01b4e0a35250bd4246672e7a02eRuben Brunk } 1630b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } else { 1631b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk ALOGW("%s: No noise profile found in result metadata. Image quality may be reduced.", 1632b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk __FUNCTION__); 1633b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } 1634b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk } 1635b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk 1636b1971dc8a69b8cee91208b7d3017c52b36e55721Ruben Brunk { 16375f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up opcode List 2 16385f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk OpcodeListBuilder builder; 16395f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk status_t err = OK; 16405f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 16415f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up lens shading map 1642f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk camera_metadata_entry entry1 = 1643f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE); 164447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 164547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t lsmWidth = 0; 164647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t lsmHeight = 0; 164747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 164847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (entry1.count != 0) { 164947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]); 165047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]); 165147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 1652f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 16539ce22a095685a581823316457217a318fb40c754Ruben Brunk camera_metadata_entry entry2 = results.find(ANDROID_STATISTICS_LENS_SHADING_MAP); 165447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 16552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk camera_metadata_entry entry = 16562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE); 16572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_IMAGEWIDTH, writer); 16582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]); 16592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]); 16602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 16612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 166247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (entry2.count > 0 && entry2.count == lsmWidth * lsmHeight * 4) { 1663c03443b23de0b474080168d892cd685283c3285bRuben Brunk // GainMap rectangle is relative to the active area origin. 16645f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk err = builder.addGainMapsForMetadata(lsmWidth, 16655f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk lsmHeight, 1666c03443b23de0b474080168d892cd685283c3285bRuben Brunk 0, 1667c03443b23de0b474080168d892cd685283c3285bRuben Brunk 0, 16682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk height, 16692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk width, 16705f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk opcodeCfaLayout, 16715f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk entry2.data.f); 16725f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err != OK) { 1673f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGE("%s: Could not add Lens shading map.", __FUNCTION__); 1674f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowRuntimeException(env, "failed to add lens shading map."); 16752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 16765f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 16775f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 16785f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 16799ce22a095685a581823316457217a318fb40c754Ruben Brunk 16809ce22a095685a581823316457217a318fb40c754Ruben Brunk // Set up bad pixel correction list 16819ce22a095685a581823316457217a318fb40c754Ruben Brunk camera_metadata_entry entry3 = characteristics.find(ANDROID_STATISTICS_HOT_PIXEL_MAP); 16829ce22a095685a581823316457217a318fb40c754Ruben Brunk 16839ce22a095685a581823316457217a318fb40c754Ruben Brunk if ((entry3.count % 2) != 0) { 16849ce22a095685a581823316457217a318fb40c754Ruben Brunk ALOGE("%s: Hot pixel map contains odd number of values, cannot map to pairs!", 16859ce22a095685a581823316457217a318fb40c754Ruben Brunk __FUNCTION__); 16869ce22a095685a581823316457217a318fb40c754Ruben Brunk jniThrowRuntimeException(env, "failed to add hotpixel map."); 16879ce22a095685a581823316457217a318fb40c754Ruben Brunk return nullptr; 16889ce22a095685a581823316457217a318fb40c754Ruben Brunk } 16899ce22a095685a581823316457217a318fb40c754Ruben Brunk 16909ce22a095685a581823316457217a318fb40c754Ruben Brunk // Adjust the bad pixel coordinates to be relative to the origin of the active area DNG tag 16919ce22a095685a581823316457217a318fb40c754Ruben Brunk std::vector<uint32_t> v; 16929ce22a095685a581823316457217a318fb40c754Ruben Brunk for (size_t i = 0; i < entry3.count; i+=2) { 16939ce22a095685a581823316457217a318fb40c754Ruben Brunk int32_t x = entry3.data.i32[i]; 16949ce22a095685a581823316457217a318fb40c754Ruben Brunk int32_t y = entry3.data.i32[i + 1]; 16959ce22a095685a581823316457217a318fb40c754Ruben Brunk x -= static_cast<int32_t>(xmin); 16969ce22a095685a581823316457217a318fb40c754Ruben Brunk y -= static_cast<int32_t>(ymin); 16979ce22a095685a581823316457217a318fb40c754Ruben Brunk if (x < 0 || y < 0 || static_cast<uint32_t>(x) >= width || 16989ce22a095685a581823316457217a318fb40c754Ruben Brunk static_cast<uint32_t>(y) >= width) { 16999ce22a095685a581823316457217a318fb40c754Ruben Brunk continue; 17009ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17019ce22a095685a581823316457217a318fb40c754Ruben Brunk v.push_back(x); 17029ce22a095685a581823316457217a318fb40c754Ruben Brunk v.push_back(y); 17039ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17049ce22a095685a581823316457217a318fb40c754Ruben Brunk const uint32_t* badPixels = &v[0]; 17059ce22a095685a581823316457217a318fb40c754Ruben Brunk uint32_t badPixelCount = v.size(); 17069ce22a095685a581823316457217a318fb40c754Ruben Brunk 17079ce22a095685a581823316457217a318fb40c754Ruben Brunk if (badPixelCount > 0) { 17089ce22a095685a581823316457217a318fb40c754Ruben Brunk err = builder.addBadPixelListForMetadata(badPixels, badPixelCount, opcodeCfaLayout); 17099ce22a095685a581823316457217a318fb40c754Ruben Brunk 17109ce22a095685a581823316457217a318fb40c754Ruben Brunk if (err != OK) { 17119ce22a095685a581823316457217a318fb40c754Ruben Brunk ALOGE("%s: Could not add hotpixel map.", __FUNCTION__); 17129ce22a095685a581823316457217a318fb40c754Ruben Brunk jniThrowRuntimeException(env, "failed to add hotpixel map."); 17139ce22a095685a581823316457217a318fb40c754Ruben Brunk return nullptr; 17149ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17159ce22a095685a581823316457217a318fb40c754Ruben Brunk } 17169ce22a095685a581823316457217a318fb40c754Ruben Brunk 17179ce22a095685a581823316457217a318fb40c754Ruben Brunk 1718fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk size_t listSize = builder.getSize(); 1719fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk uint8_t opcodeListBuf[listSize]; 1720fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk err = builder.buildOpList(opcodeListBuf); 1721fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk if (err == OK) { 17222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf, 1723fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk TIFF_IFD_0), env, TAG_OPCODELIST2, writer); 1724fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } else { 1725fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading" 1726fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk "map.", __FUNCTION__); 1727fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk jniThrowRuntimeException(env, "failed to construct opcode list for distortion" 1728fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk " correction and lens shading map"); 17292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1730fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } 1731fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk } 1732fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk 1733fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk { 1734fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk // Set up opcode List 3 1735fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk OpcodeListBuilder builder; 1736fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk status_t err = OK; 1737fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk 17385f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk // Set up rectilinear distortion correction 17395f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk camera_metadata_entry entry3 = 17405f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk results.find(ANDROID_LENS_RADIAL_DISTORTION); 17415f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk camera_metadata_entry entry4 = 17425f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk results.find(ANDROID_LENS_INTRINSIC_CALIBRATION); 17435f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 17445f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (entry3.count == 6 && entry4.count == 5) { 17455f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk float cx = entry4.data.f[/*c_x*/2]; 17465f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk float cy = entry4.data.f[/*c_y*/3]; 17472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk err = builder.addWarpRectilinearForMetadata(entry3.data.f, preWidth, preHeight, cx, 17485f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk cy); 17495f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err != OK) { 17505f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk ALOGE("%s: Could not add distortion correction.", __FUNCTION__); 17515f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jniThrowRuntimeException(env, "failed to add distortion correction."); 17522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1753f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 17545f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk } 17555f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk 17565f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk size_t listSize = builder.getSize(); 17575f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk uint8_t opcodeListBuf[listSize]; 17585f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk err = builder.buildOpList(opcodeListBuf); 17595f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk if (err == OK) { 17602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf, 1761fe81662cc5c0f04ecd2ef2d96b1d8890500d69a5Ruben Brunk TIFF_IFD_0), env, TAG_OPCODELIST3, writer); 1762f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } else { 17635f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading" 17645f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk "map.", __FUNCTION__); 17655f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk jniThrowRuntimeException(env, "failed to construct opcode list for distortion" 17665f2368d6def80ad18ee77cdf0e451c0e9f41e322Ruben Brunk " correction and lens shading map"); 17672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 1768f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1769f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 1770f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 17712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 17722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set up orientation tags. 17732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t orientation = nativeContext->getOrientation(); 17742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), 17752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_ORIENTATION, writer); 17762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 17772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 17782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 17792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasDescription()){ 17802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set Description 17812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk String8 description = nativeContext->getDescription(); 17822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk size_t len = description.bytes() + 1; 17832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addEntry(TAG_IMAGEDESCRIPTION, len, 17842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<const uint8_t*>(description.string()), TIFF_IFD_0) != OK) { 17852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 17862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION); 17872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 17882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 17892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 17902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasGpsData()) { 17912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set GPS tags 17922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData gpsData = nativeContext->getGpsData(); 17932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!writer->hasIfd(TIFF_IFD_GPSINFO)) { 17942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_GPSINFO, TiffWriter::GPSINFO) != OK) { 17952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Failed to add GpsInfo IFD %u to IFD %u", __FUNCTION__, TIFF_IFD_GPSINFO, 17962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0); 17972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to add GPSINFO"); 17982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 17992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18032079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint8_t version[] = {2, 3, 0, 0}; 18042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSVERSIONID, 4, version, 18052079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSVERSIONID, writer); 18062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDEREF, 18102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_REF_LENGTH, gpsData.mLatitudeRef, TIFF_IFD_GPSINFO), env, 18112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSLATITUDEREF, writer); 18122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDEREF, 18162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_REF_LENGTH, gpsData.mLongitudeRef, TIFF_IFD_GPSINFO), env, 18172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSLONGITUDEREF, writer); 18182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLATITUDE, 3, gpsData.mLatitude, 18222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSLATITUDE, writer); 18232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSLONGITUDE, 3, gpsData.mLongitude, 18272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSLONGITUDE, writer); 18282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSTIMESTAMP, 3, gpsData.mTimestamp, 18322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_GPSINFO), env, TAG_GPSTIMESTAMP, writer); 18332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_GPSDATESTAMP, 18372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData::GPS_DATE_LENGTH, gpsData.mDate, TIFF_IFD_GPSINFO), env, 18382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TAG_GPSDATESTAMP, writer); 18392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (nativeContext->hasThumbnail()) { 18442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (!writer->hasIfd(TIFF_IFD_SUB1)) { 18452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addSubIfd(TIFF_IFD_0, TIFF_IFD_SUB1) != OK) { 18462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Failed to add SubIFD %u to IFD %u", __FUNCTION__, TIFF_IFD_SUB1, 18472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0); 18482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to add SubIFD"); 18492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 18502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk Vector<uint16_t> tagsToMove; 18542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_ORIENTATION); 18552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_NEWSUBFILETYPE); 18562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_ACTIVEAREA); 18572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BITSPERSAMPLE); 18582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_COMPRESSION); 18592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_IMAGEWIDTH); 18602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_IMAGELENGTH); 18612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_PHOTOMETRICINTERPRETATION); 18622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BLACKLEVEL); 18632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_BLACKLEVELREPEATDIM); 18642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_SAMPLESPERPIXEL); 18652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_PLANARCONFIGURATION); 18662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAREPEATPATTERNDIM); 18672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAPATTERN); 18682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFAPLANECOLOR); 18692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_CFALAYOUT); 18702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_XRESOLUTION); 18712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_YRESOLUTION); 18722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_RESOLUTIONUNIT); 18732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_WHITELEVEL); 18742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTSCALE); 18752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTCROPORIGIN); 18762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_DEFAULTCROPSIZE); 18772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_OPCODELIST2); 18782079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk tagsToMove.add(TAG_OPCODELIST3); 18792079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18802079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) { 18812079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries"); 18822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 18832079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18842079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18852079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Make sure both IFDs get the same orientation tag 18862079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffEntry> orientEntry = writer->getEntry(TAG_ORIENTATION, TIFF_IFD_SUB1); 18872079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (orientEntry.get() != nullptr) { 18882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk writer->addEntry(orientEntry, TIFF_IFD_0); 18892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18902079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18912079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Setup thumbnail tags 18922079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 18932079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 18942079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set photometric interpretation 18952079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t interpretation = 2; // RGB 18962079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, 18972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk &interpretation, TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION, writer); 18982079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 18992079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19002079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19012079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set planar configuration 19022079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t config = 1; // Chunky 19032079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, 19042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_PLANARCONFIGURATION, writer); 19052079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19062079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19072079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19082079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set samples per pixel 19092079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t samples = SAMPLES_PER_RGB_PIXEL; 19102079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, 19112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_SAMPLESPERPIXEL, writer); 19122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19132079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19142079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19152079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set bits per sample 19162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t bits = BITS_PER_RGB_SAMPLE; 19172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), 19182079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_BITSPERSAMPLE, writer); 19192079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set subfiletype 19232079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t subfileType = 1; // Thumbnail image 19242079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, 19252079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_NEWSUBFILETYPE, writer); 19262079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19272079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19292079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set compression 19302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t compression = 1; // None 19312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_COMPRESSION, 1, &compression, 19322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk TIFF_IFD_0), env, TAG_COMPRESSION, writer); 19332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19352079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Set dimensions 19372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t uWidth = nativeContext->getThumbnailWidth(); 19382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t uHeight = nativeContext->getThumbnailHeight(); 19392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGEWIDTH, 1, &uWidth, TIFF_IFD_0), 19402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGEWIDTH, writer); 19412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_IMAGELENGTH, 1, &uHeight, TIFF_IFD_0), 19422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_IMAGELENGTH, writer); 19432079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19442079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19452079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk { 19462079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // x resolution 19472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t xres[] = { 72, 1 }; // default 72 ppi 19482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XRESOLUTION, 1, xres, TIFF_IFD_0), 19492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_XRESOLUTION, writer); 19502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // y resolution 19522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint32_t yres[] = { 72, 1 }; // default 72 ppi 19532079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_YRESOLUTION, 1, yres, TIFF_IFD_0), 19542079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_YRESOLUTION, writer); 19552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk uint16_t unit = 2; // inches 19572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_RESOLUTIONUNIT, 1, &unit, TIFF_IFD_0), 19582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env, TAG_RESOLUTIONUNIT, writer); 19592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19622079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addStrip(TIFF_IFD_0) != OK) { 19632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Could not setup thumbnail strip tags.", __FUNCTION__); 19642079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", 19652079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Failed to setup thumbnail strip tags."); 19662079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 19672079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19682079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 19692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->hasIfd(TIFF_IFD_SUB1)) { 19702079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer->addStrip(TIFF_IFD_SUB1) != OK) { 19712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk ALOGE("%s: Could not main image strip tags.", __FUNCTION__); 19722079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jniThrowException(env, "java/lang/IllegalStateException", 19732079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk "Failed to setup main image strip tags."); 19742079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return nullptr; 19752079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19762079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 19772079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return writer; 1978f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 1979f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 1980f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_destroy(JNIEnv* env, jobject thiz) { 1981f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 19822079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk DngCreator_setNativeContext(env, thiz, nullptr); 1983f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 1984f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 198547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz, jint orient) { 1986f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 1987f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 19882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 19892079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 199047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 199147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 199247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setOrientation called with uninitialized DngCreator"); 199347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 199447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 199547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 199647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint16_t orientation = static_cast<uint16_t>(orient); 19972079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setOrientation(orientation); 1998f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 1999f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 200047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetDescription(JNIEnv* env, jobject thiz, jstring description) { 2001f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 200247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20032079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20042079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 200547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 200647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 200747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setDescription called with uninitialized DngCreator"); 200847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 200947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 201047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20112079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk const char* desc = env->GetStringUTFChars(description, nullptr); 20122079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setDescription(String8(desc)); 201347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk env->ReleaseStringUTFChars(description, desc); 2014f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2015f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20162079612e5851d73f4672ae3729c883a58adc4dddRuben Brunkstatic void DngCreator_nativeSetGpsTags(JNIEnv* env, jobject thiz, jintArray latTag, 20172079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk jstring latRef, jintArray longTag, jstring longRef, jstring dateTag, jintArray timeTag) { 2018f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 2019f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20202079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20212079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 202247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 202347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 202447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setGpsTags called with uninitialized DngCreator"); 2025f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2026f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2027f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 20282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk GpsData data; 202947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 203047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize latLen = env->GetArrayLength(latTag); 203147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize longLen = env->GetArrayLength(longTag); 203247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jsize timeLen = env->GetArrayLength(timeTag); 20332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (latLen != GpsData::GPS_VALUE_LENGTH) { 203447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 203547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid latitude tag length"); 203647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 20372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } else if (longLen != GpsData::GPS_VALUE_LENGTH) { 203847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 203947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid longitude tag length"); 2040f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 20412079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } else if (timeLen != GpsData::GPS_VALUE_LENGTH) { 204247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", 204347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "invalid time tag length"); 204447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 204547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 204647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20472079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(latTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20482079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mLatitude)); 20492079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(longTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20502079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mLongitude)); 20512079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetIntArrayRegion(timeTag, 0, static_cast<jsize>(GpsData::GPS_VALUE_LENGTH), 20522079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<jint*>(&data.mTimestamp)); 205347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 205447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20552079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(latRef, 0, 1, reinterpret_cast<char*>(&data.mLatitudeRef)); 20562079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mLatitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0'; 20572079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(longRef, 0, 1, reinterpret_cast<char*>(&data.mLongitudeRef)); 20582079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mLongitudeRef[GpsData::GPS_REF_LENGTH - 1] = '\0'; 20592079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk env->GetStringUTFRegion(dateTag, 0, GpsData::GPS_DATE_LENGTH - 1, 20602079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk reinterpret_cast<char*>(&data.mDate)); 20612079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk data.mDate[GpsData::GPS_DATE_LENGTH - 1] = '\0'; 206247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 20632079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk context->setGpsData(data); 206447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 206547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 206647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buffer, jint width, 206747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint height) { 206847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s:", __FUNCTION__); 206947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 207047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 20712079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 2072f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 2073f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 207447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "setThumbnail called with uninitialized DngCreator"); 2075f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2076f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 207747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 207847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t fullSize = width * height * BYTES_PER_RGB_PIXEL; 207947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong capacity = env->GetDirectBufferCapacity(buffer); 20800f0b4919667f418b249c497f5ad3e83fdf4437e5Andreas Gampe if (static_cast<uint64_t>(capacity) != static_cast<uint64_t>(fullSize)) { 208147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/AssertionError", 208247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid size %d for thumbnail, expected size was %d", 208347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk capacity, fullSize); 2084f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2085f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2086f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 208747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer)); 20882079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (pixelBytes == nullptr) { 208947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__); 209047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer"); 2091f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2092f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2093f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 209447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!context->setThumbnail(pixelBytes, width, height)) { 209547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalStateException", 209647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Failed to set thumbnail."); 2097f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2098f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 209947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk} 2100f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 210147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk// TODO: Refactor out common preamble for the two nativeWrite methods. 210247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunkstatic void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width, 210347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jint height, jobject inBuffer, jint rowStride, jint pixStride, jlong offset, 210447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jboolean isDirect) { 210547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s:", __FUNCTION__); 210646d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGV("%s: nativeWriteImage called with: width=%d, height=%d, " 210746d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width, 210846d8444631b4b1253a76bfcc78a29d26014d022fDan Albert height, rowStride, pixStride, offset); 210947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t rStride = static_cast<uint32_t>(rowStride); 211047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pStride = static_cast<uint32_t>(pixStride); 211147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uWidth = static_cast<uint32_t>(width); 211247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uHeight = static_cast<uint32_t>(height); 211347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t uOffset = static_cast<uint64_t>(offset); 211447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 211547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniOutputStream> out = new JniOutputStream(env, outStream); 211647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if(env->ExceptionCheck()) { 211747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__); 2118f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2119f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2120f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 212147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 21222079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 212347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 212447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 212547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Write called with uninitialized DngCreator"); 212647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 212747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 21282079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight); 212947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 21302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer.get() == nullptr) { 21312079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 21322079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 21332079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 21342079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Validate DNG size 2135b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) { 213647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 213747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 213847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 213947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniInputByteBuffer> inBuf; 214047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<StripSource*> sources; 214147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<DirectStripSource> thumbnailSource; 214247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t targetIfd = TIFF_IFD_0; 214347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 214447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); 214547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 214647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (hasThumbnail) { 214747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); 214847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; 214947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t thumbWidth = context->getThumbnailWidth(); 215047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0, 215147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbWidth, context->getThumbnailHeight(), bytesPerPixel, 215247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesPerPixel * thumbWidth, /*offset*/0, BYTES_PER_RGB_SAMPLE, 215347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL); 215447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(thumbnailSource.get()); 215547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk targetIfd = TIFF_IFD_SUB1; 215647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 215747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 215847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (isDirect) { 215947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk size_t fullSize = rStride * uHeight; 216047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jlong capacity = env->GetDirectBufferCapacity(inBuffer); 216147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (capacity < 0 || fullSize + uOffset > static_cast<uint64_t>(capacity)) { 216247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 216347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Invalid size %d for Image, size given in metadata is %d at current stride", 216447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk capacity, fullSize); 2165f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk return; 2166f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 216747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 216847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer)); 21692079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (pixelBytes == nullptr) { 217047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not get native ByteBuffer", __FUNCTION__); 217147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid ByteBuffer"); 217247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 217347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 217447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 217547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using direct-type strip source.", __FUNCTION__); 217647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk DirectStripSource stripSource(env, pixelBytes, targetIfd, uWidth, uHeight, pStride, 217747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 217847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 217947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 218047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 218147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 218247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 218347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 218447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 218547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 2186f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 218747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 2188f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2189f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } else { 219047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk inBuf = new JniInputByteBuffer(env, inBuffer); 219147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 219247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using input-type strip source.", __FUNCTION__); 219347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource stripSource(env, *inBuf, targetIfd, uWidth, uHeight, pStride, 219447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 219547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 219647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 219747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 219847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 219947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 220047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 220147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 220247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 2203f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 220447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 2205f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2206f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk } 2207f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2208f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2209f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream, 221047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jobject inStream, jint width, jint height, jlong offset) { 2211f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk ALOGV("%s:", __FUNCTION__); 221247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 221347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t rowStride = width * BYTES_PER_SAMPLE; 221447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t pixStride = BYTES_PER_SAMPLE; 221547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uWidth = static_cast<uint32_t>(width); 221647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t uHeight = static_cast<uint32_t>(height); 221747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint64_t uOffset = static_cast<uint32_t>(offset); 221847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 221946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGV("%s: nativeWriteInputStream called with: width=%d, height=%d, " 222046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "rowStride=%d, pixStride=%d, offset=%" PRId64, __FUNCTION__, width, 222146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert height, rowStride, pixStride, offset); 222247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 222347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniOutputStream> out = new JniOutputStream(env, outStream); 222446d8444631b4b1253a76bfcc78a29d26014d022fDan Albert if (env->ExceptionCheck()) { 222547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__); 222647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 222747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 222847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 222947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk NativeContext* context = DngCreator_getNativeContext(env, thiz); 22302079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (context == nullptr) { 223147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 223247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowException(env, "java/lang/AssertionError", 223347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Write called with uninitialized DngCreator"); 223447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 223547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 22362079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk sp<TiffWriter> writer = DngCreator_setup(env, thiz, uWidth, uHeight); 22372079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk 22382079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk if (writer.get() == nullptr) { 22392079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk return; 22402079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk } 224147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 22422079612e5851d73f4672ae3729c883a58adc4dddRuben Brunk // Validate DNG size 2243b8f4c6ab1e99a44a51af26dc522819bb833825abRuben Brunk if (!validateDngHeader(env, writer, *(context->getCharacteristics()), width, height)) { 224447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 224547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 224647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 224747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<DirectStripSource> thumbnailSource; 224847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t targetIfd = TIFF_IFD_0; 224947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); 225047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk Vector<StripSource*> sources; 225147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 225247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (hasThumbnail) { 225347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Adding thumbnail strip sources.", __FUNCTION__); 225447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t bytesPerPixel = SAMPLES_PER_RGB_PIXEL * BYTES_PER_RGB_SAMPLE; 225547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk uint32_t width = context->getThumbnailWidth(); 225647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk thumbnailSource = new DirectStripSource(env, context->getThumbnail(), TIFF_IFD_0, 225747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk width, context->getThumbnailHeight(), bytesPerPixel, 225847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk bytesPerPixel * width, /*offset*/0, BYTES_PER_RGB_SAMPLE, 225947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk SAMPLES_PER_RGB_PIXEL); 226047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(thumbnailSource.get()); 226147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk targetIfd = TIFF_IFD_SUB1; 226247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 226347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 226447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sp<JniInputStream> in = new JniInputStream(env, inStream); 226547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 226647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGV("%s: Using input-type strip source.", __FUNCTION__); 226747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk InputStripSource stripSource(env, *in, targetIfd, uWidth, uHeight, pixStride, 226847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk rowStride, uOffset, BYTES_PER_SAMPLE, SAMPLES_PER_RAW_PIXEL); 226947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk sources.add(&stripSource); 227047e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk 227147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk status_t ret = OK; 227247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if ((ret = writer->write(out.get(), sources.editArray(), sources.size())) != OK) { 227347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk ALOGE("%s: write failed with error %d.", __FUNCTION__, ret); 227447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk if (!env->ExceptionCheck()) { 227547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk jniThrowExceptionFmt(env, "java/io/IOException", 227647e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk "Encountered error %d while writing file.", ret); 227747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 227847e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk return; 227947e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk } 2280f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2281f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2282f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} /*extern "C" */ 2283f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2284f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunkstatic JNINativeMethod gDngCreatorMethods[] = { 2285f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit}, 2286f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;" 2287b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V", 2288b8df8e07d6fc530c82d21ca3199411e2e60975b1Ruben Brunk (void*) DngCreator_init}, 2289f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeDestroy", "()V", (void*) DngCreator_destroy}, 2290f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk {"nativeSetOrientation", "(I)V", (void*) DngCreator_nativeSetOrientation}, 229147e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetDescription", "(Ljava/lang/String;)V", (void*) DngCreator_nativeSetDescription}, 229247e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetGpsTags", "([ILjava/lang/String;[ILjava/lang/String;Ljava/lang/String;[I)V", 229347e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk (void*) DngCreator_nativeSetGpsTags}, 229447e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeSetThumbnail","(Ljava/nio/ByteBuffer;II)V", (void*) DngCreator_nativeSetThumbnail}, 229547e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeWriteImage", "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;IIJZ)V", 2296f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk (void*) DngCreator_nativeWriteImage}, 229747e91f20952e5eb2290146ba6e33a694dd2e45e8Ruben Brunk {"nativeWriteInputStream", "(Ljava/io/OutputStream;Ljava/io/InputStream;IIJ)V", 2298f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk (void*) DngCreator_nativeWriteInputStream}, 2299f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk}; 2300f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk 2301b6079005ed0631c3972ff427f56e12523ec214a7Ruben Brunkint register_android_hardware_camera2_DngCreator(JNIEnv *env) { 2302ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe return RegisterMethodsOrDie(env, 2303ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe "android/hardware/camera2/DngCreator", gDngCreatorMethods, NELEM(gDngCreatorMethods)); 2304f967a5486a78db244624fde4c105aa5e6fa914b9Ruben Brunk} 2305