You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
TermApp/app/src/main/cpp/DngCreator.h

333 lines
9.3 KiB
C

9 months ago
//#define LOG_NDEBUG 0
#define LOG_TAG "DngCreator_JNI"
#include <inttypes.h>
#include <string.h>
#include <algorithm>
#include <array>
#include <memory>
#include <vector>
#include <cmath>
#include <algorithm>
#include <camera/NdkCameraMetadata.h>
#include <img_utils/DngUtils.h>
#include <img_utils/TagDefinitions.h>
#include <img_utils/TiffIfd.h>
#include <img_utils/TiffWriter.h>
#include <img_utils/Output.h>
#include <img_utils/Input.h>
#include <img_utils/StripSource.h>
#include <sys/system_properties.h>
// #include "core_jni_helpers.h"
// #include "android_runtime/AndroidRuntime.h"
// #include "android_runtime/android_hardware_camera2_CameraMetadata.h"
#include <jni.h>
// #include <nativehelper/JNIHelp.h>
using namespace android;
using namespace img_utils;
// using android::base::GetProperty;
/**
* Max width or height dimension for thumbnails.
*/
// max pixel dimension for TIFF/EP
#define MAX_THUMBNAIL_DIMENSION 256
// bytes per sample
#define DEFAULT_PIXEL_STRIDE 2
// byts per pixel
#define BYTES_PER_RGB_PIX 3
#define GPS_LAT_REF_NORTH "N"
#define GPS_LAT_REF_SOUTH "S"
#define GPS_LONG_REF_EAST "E"
#define GPS_LONG_REF_WEST "W"
#define GPS_DATE_FORMAT_STR "yyyy:MM:dd"
#define TIFF_DATETIME_FORMAT "yyyy:MM:dd kk:mm:ss"
class ByteVectorOutput : public Output {
public:
ByteVectorOutput(std::vector<uint8_t>& buf);
virtual ~ByteVectorOutput();
virtual status_t open();
virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
virtual status_t close();
protected:
std::vector<uint8_t>& m_buf;
};
class ByteVectorInput : public Input {
public:
ByteVectorInput(const std::vector<uint8_t>& buf);
virtual ~ByteVectorInput();
/**
* Open this Input.
*
* Returns OK on success, or a negative error code.
*/
status_t open();
/**
* Read bytes into the given buffer. At most, the number of bytes given in the
* count argument will be read. Bytes will be written into the given buffer starting
* at the index given in the offset argument.
*
* Returns the number of bytes read, or NOT_ENOUGH_DATA if at the end of the file. If an
* error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA.
*/
ssize_t read(uint8_t* buf, size_t offset, size_t count);
/**
* Skips bytes in the input.
*
* Returns the number of bytes skipped, or NOT_ENOUGH_DATA if at the end of the file. If an
* error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA.
*/
ssize_t skip(size_t count);
/**
* Close the Input. It is not valid to call open on a previously closed Input.
*
* Returns OK on success, or a negative error code.
*/
status_t close();
protected:
const std::vector<uint8_t>& m_buf;
size_t m_offset;
};
class ByteBufferInput : public Input {
public:
ByteBufferInput(const uint8_t* buf, size_t len);
virtual ~ByteBufferInput();
/**
* Open this Input.
*
* Returns OK on success, or a negative error code.
*/
status_t open();
/**
* Read bytes into the given buffer. At most, the number of bytes given in the
* count argument will be read. Bytes will be written into the given buffer starting
* at the index given in the offset argument.
*
* Returns the number of bytes read, or NOT_ENOUGH_DATA if at the end of the file. If an
* error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA.
*/
ssize_t read(uint8_t* buf, size_t offset, size_t count);
/**
* Skips bytes in the input.
*
* Returns the number of bytes skipped, or NOT_ENOUGH_DATA if at the end of the file. If an
* error has occurred, this will return a negative error code other than NOT_ENOUGH_DATA.
*/
ssize_t skip(size_t count);
/**
* Close the Input. It is not valid to call open on a previously closed Input.
*
* Returns OK on success, or a negative error code.
*/
status_t close();
protected:
const uint8_t* m_buf;
size_t m_len;
size_t m_offset;
};
struct SIZE
{
int width;
int height;
};
#define BAIL_IF_INVALID_RET_BOOL(expr, jnienv, tagId, writer) \
if ((expr) != OK) { \
return false; \
}
#define BAIL_IF_INVALID_RET_NULL_SP(expr, jnienv, tagId, writer) \
if ((expr) != OK) { \
return nullptr; \
}
#define BAIL_IF_INVALID_R(expr, jnienv, tagId, writer) \
if ((expr) != OK) { \
return -1; \
}
#define BAIL_IF_EMPTY_RET_NULL_SP(entry, jnienv, tagId, writer) \
if ((entry).count == 0) { \
return nullptr; \
}
#define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \
if (expr) { \
return nullptr; \
}
#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext"
enum {
BITS_PER_SAMPLE = 16,
BYTES_PER_SAMPLE = 2,
BYTES_PER_RGB_PIXEL = 3,
BITS_PER_RGB_SAMPLE = 8,
BYTES_PER_RGB_SAMPLE = 1,
SAMPLES_PER_RGB_PIXEL = 3,
SAMPLES_PER_RAW_PIXEL = 1,
TIFF_IFD_0 = 0,
TIFF_IFD_SUB1 = 1,
TIFF_IFD_GPSINFO = 2,
};
/**
* POD container class for GPS tag data.
*/
class GpsData {
public:
enum {
GPS_VALUE_LENGTH = 6,
GPS_REF_LENGTH = 2,
GPS_DATE_LENGTH = 11,
};
uint32_t mLatitude[GPS_VALUE_LENGTH];
uint32_t mLongitude[GPS_VALUE_LENGTH];
uint32_t mTimestamp[GPS_VALUE_LENGTH];
uint8_t mLatitudeRef[GPS_REF_LENGTH];
uint8_t mLongitudeRef[GPS_REF_LENGTH];
uint8_t mDate[GPS_DATE_LENGTH];
};
// ----------------------------------------------------------------------------
/**
* Container class for the persistent native context.
*/
class NativeContext : public LightRefBase<NativeContext> {
public:
enum {
DATETIME_COUNT = 20,
};
NativeContext(ACameraMetadata* characteristics, ACameraMetadata* result);
virtual ~NativeContext();
TiffWriter* getWriter();
ACameraMetadata* getCharacteristics() const;
ACameraMetadata* getResult() const;
uint32_t getThumbnailWidth() const;
uint32_t getThumbnailHeight() const;
const uint8_t* getThumbnail() const;
bool hasThumbnail() const;
bool setThumbnail(const std::vector<uint8_t>& buffer, uint32_t width, uint32_t height);
void setOrientation(uint16_t orientation);
uint16_t getOrientation() const;
void setDescription(const std::string& desc);
std::string getDescription() const;
bool hasDescription() const;
void setGpsData(const GpsData& data);
GpsData getGpsData() const;
bool hasGpsData() const;
void setCaptureTime(const std::string& formattedCaptureTime);
std::string getCaptureTime() const;
bool hasCaptureTime() const;
protected:
std::vector<uint8_t> mCurrentThumbnail;
TiffWriter mWriter;
ACameraMetadata* mCharacteristics;
ACameraMetadata* mResult;
uint32_t mThumbnailWidth;
uint32_t mThumbnailHeight;
uint16_t mOrientation;
bool mThumbnailSet;
bool mGpsSet;
bool mDescriptionSet;
bool mCaptureTimeSet;
std::string mDescription;
GpsData mGpsData;
std::string mFormattedCaptureTime;
};
class DngCreator : public NativeContext
{
public:
DngCreator(ACameraMetadata* characteristics, ACameraMetadata* result);
#if 0
void setLocation(Location location);
#endif
void writeInputStream(std::vector<uint8_t>& dngOutput, SIZE size, const std::vector<uint8_t>& pixels, long offset);
void writeByteBuffer(std::vector<uint8_t>& dngOutput, SIZE size, const std::vector<uint8_t>& pixels, long offset);
#if 0
void writeImage(OutputStream& dngOutput, AImage& pixels);
#endif
void close();
// private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
// private static final DateFormat sDateTimeStampFormat = new SimpleDateFormat(TIFF_DATETIME_FORMAT);
#if 0
static {
sDateTimeStampFormat.setTimeZone(TimeZone.getDefault());
sExifGPSDateStamp.setTimeZone(TimeZone.getTimeZone("UTC"));
}
#endif
/**
* Offset, rowStride, and pixelStride are given in bytes. Height and width are given in pixels.
*/
void writeByteBuffer(int width, int height, const std::vector<uint8_t>& pixels, std::vector<uint8_t>& dngOutput, int pixelStride, int rowStride, long offset);
/**
* Generate a direct RGB {@link ByteBuffer} from a {@link Bitmap}.
*/
/**
* Convert coordinate to EXIF GPS tag format.
*/
void toExifLatLong(double value, int data[6]);
void init(ACameraMetadata* characteristics, ACameraMetadata* result, const std::string& captureTime);
sp<TiffWriter> setup(uint32_t imageWidth, uint32_t imageHeight);
void destroy();
void setGpsTags(const std::vector<int>& latTag, const std::string& latRef, const std::vector<int>& longTag, const std::string& longRef, const std::string& dateTag, const std::vector<int>& timeTag);
void writeImage(std::vector<uint8_t>& out, uint32_t width, uint32_t height, const std::vector<uint8_t>& rawBuffer, int rowStride, int pixStride, uint64_t offset, bool isDirect);
void writeInputStream(std::vector<uint8_t>& out, const std::vector<uint8_t>& rawStream, uint32_t width, uint32_t height, long offset);
void writeInputBuffer(std::vector<uint8_t>& out, const uint8_t* rawBuffer, size_t bufferLen, uint32_t width, uint32_t height, long offset);
};