mirror of
https://gitee.com/openharmony/multimedia_image_framework
synced 2024-11-27 01:01:24 +00:00
commit
67af4b1c96
@ -545,7 +545,43 @@ uint32_t ImageSource::ModifyImageProperty(uint32_t index, const std::string &key
|
||||
}
|
||||
ret = mainDecoder_->ModifyImageProperty(index, key, value, path);
|
||||
if (ret != SUCCESS) {
|
||||
IMAGE_LOGE("[ImageSource] GetImagePropertyInt fail, ret:%{public}u", ret);
|
||||
IMAGE_LOGE("[ImageSource] ModifyImageProperty fail, ret:%{public}u", ret);
|
||||
return ret;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t ImageSource::ModifyImageProperty(uint32_t index, const std::string &key,
|
||||
const std::string &value, const int fd)
|
||||
{
|
||||
std::unique_lock<std::mutex> guard(decodingMutex_);
|
||||
uint32_t ret;
|
||||
auto iter = GetValidImageStatus(0, ret);
|
||||
if (iter == imageStatusMap_.end()) {
|
||||
IMAGE_LOGE("[ImageSource]get valid image status fail on modify image property, ret:%{public}u.", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = mainDecoder_->ModifyImageProperty(index, key, value, fd);
|
||||
if (ret != SUCCESS) {
|
||||
IMAGE_LOGE("[ImageSource] ModifyImageProperty fail, ret:%{public}u", ret);
|
||||
return ret;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t ImageSource::ModifyImageProperty(uint32_t index, const std::string &key,
|
||||
const std::string &value, uint8_t *data, uint32_t size)
|
||||
{
|
||||
std::unique_lock<std::mutex> guard(decodingMutex_);
|
||||
uint32_t ret;
|
||||
auto iter = GetValidImageStatus(0, ret);
|
||||
if (iter == imageStatusMap_.end()) {
|
||||
IMAGE_LOGE("[ImageSource]get valid image status fail on modify image property, ret:%{public}u.", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = mainDecoder_->ModifyImageProperty(index, key, value, data, size);
|
||||
if (ret != SUCCESS) {
|
||||
IMAGE_LOGE("[ImageSource] ModifyImageProperty fail, ret:%{public}u", ret);
|
||||
return ret;
|
||||
}
|
||||
return SUCCESS;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "hilog/log.h"
|
||||
#include "image_napi_utils.h"
|
||||
#include "media_errors.h"
|
||||
#include "string_ex.h"
|
||||
|
||||
using OHOS::HiviewDFX::HiLog;
|
||||
namespace {
|
||||
@ -28,6 +29,7 @@ namespace {
|
||||
constexpr uint32_t NUM_3 = 3;
|
||||
constexpr uint32_t NUM_4 = 4;
|
||||
constexpr uint32_t NUM_5 = 5;
|
||||
constexpr uint32_t NUM_8 = 8;
|
||||
}
|
||||
|
||||
namespace OHOS {
|
||||
@ -38,6 +40,9 @@ std::shared_ptr<IncrementalPixelMap> ImageSourceNapi::sIncPixelMap_ = nullptr;
|
||||
static const std::string CLASS_NAME = "ImageSource";
|
||||
static const std::string FILE_URL_PREFIX = "file://";
|
||||
std::string ImageSourceNapi::filePath_ = "";
|
||||
int ImageSourceNapi::fileDescriptor_ = -1;
|
||||
void* ImageSourceNapi::fileBuffer_ = nullptr;
|
||||
size_t ImageSourceNapi::fileBufferSize_ = 0;
|
||||
|
||||
struct ImageSourceAsyncContext {
|
||||
napi_env env;
|
||||
@ -69,6 +74,7 @@ struct ImageSourceAsyncContext {
|
||||
std::shared_ptr<ImageSource> rImageSource;
|
||||
std::shared_ptr<PixelMap> rPixelMap;
|
||||
napi_value error = nullptr;
|
||||
std::string errMsg;
|
||||
};
|
||||
|
||||
static std::string GetStringArgument(napi_env env, napi_value value)
|
||||
@ -473,6 +479,11 @@ napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info i
|
||||
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
|
||||
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
|
||||
|
||||
filePath_ = "";
|
||||
fileDescriptor_ = -1;
|
||||
fileBuffer_ = nullptr;
|
||||
fileBufferSize_ = 0;
|
||||
|
||||
std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
|
||||
uint32_t errorCode = ERR_MEDIA_INVALID_VALUE;
|
||||
SourceOptions opts;
|
||||
@ -501,10 +512,13 @@ napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info i
|
||||
} else if (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_number) {
|
||||
napi_get_value_int32(env, argValue[NUM_0], &asyncContext->fdIndex);
|
||||
HiLog::Debug(LABEL, "CreateImageSource fdIndex is [%{public}d]", asyncContext->fdIndex);
|
||||
fileDescriptor_ = asyncContext->fdIndex;
|
||||
imageSource = ImageSource::CreateImageSource(asyncContext->fdIndex, opts, errorCode);
|
||||
} else if (argCount == NUM_1) {
|
||||
status = napi_get_arraybuffer_info(env, argValue[NUM_0],
|
||||
&(asyncContext->sourceBuffer), &(asyncContext->sourceBufferSize));
|
||||
fileBuffer_ = asyncContext->sourceBuffer;
|
||||
fileBufferSize_ = asyncContext->sourceBufferSize;
|
||||
imageSource = ImageSource::CreateImageSource(static_cast<uint8_t *>(asyncContext->sourceBuffer),
|
||||
asyncContext->sourceBufferSize, opts, errorCode);
|
||||
}
|
||||
@ -791,11 +805,44 @@ static void ModifyImagePropertyComplete(napi_env env, napi_status status, ImageS
|
||||
HiLog::Error(LABEL, "context is nullptr");
|
||||
return;
|
||||
}
|
||||
napi_value result = nullptr;
|
||||
napi_get_undefined(env, &result);
|
||||
|
||||
napi_value result[NUM_2] = {0};
|
||||
napi_get_undefined(env, &result[NUM_0]);
|
||||
napi_get_undefined(env, &result[NUM_1]);
|
||||
napi_value retVal;
|
||||
napi_value callback = nullptr;
|
||||
if (context->status == ERR_MEDIA_WRITE_PARCEL_FAIL) {
|
||||
if (context->fdIndex != -1) {
|
||||
napi_create_string_utf8(env, "Create Fd without write permission!", NAPI_AUTO_LENGTH, &result[NUM_0]);
|
||||
}
|
||||
} else if (context->status == ERR_MEDIA_OUT_OF_RANGE) {
|
||||
napi_create_string_utf8(env, "The given buffer size is too small to add new exif data!",
|
||||
NAPI_AUTO_LENGTH, &result[NUM_0]);
|
||||
} else if (context->status == ERR_IMAGE_DECODE_EXIF_UNSUPPORT) {
|
||||
napi_create_string_utf8(env, "The exif data format is not standard, so modify it failed!",
|
||||
NAPI_AUTO_LENGTH, &result[NUM_0]);
|
||||
} else if (context->status == ERR_MEDIA_VALUE_INVALID) {
|
||||
napi_create_string_utf8(env, (context->errMsg).c_str(), NAPI_AUTO_LENGTH, &result[NUM_0]);
|
||||
}
|
||||
|
||||
if (context->deferred) {
|
||||
if (context->status == SUCCESS) {
|
||||
napi_resolve_deferred(env, context->deferred, result[NUM_1]);
|
||||
} else {
|
||||
napi_reject_deferred(env, context->deferred, result[NUM_0]);
|
||||
}
|
||||
} else {
|
||||
HiLog::Debug(LABEL, "call callback function");
|
||||
napi_get_reference_value(env, context->callbackRef, &callback);
|
||||
napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
|
||||
napi_delete_reference(env, context->callbackRef);
|
||||
}
|
||||
|
||||
napi_delete_async_work(env, context->work);
|
||||
|
||||
delete context;
|
||||
context = nullptr;
|
||||
HiLog::Debug(LABEL, "ModifyPropertyComplete OUT");
|
||||
ImageSourceCallbackRoutine(env, context, result);
|
||||
}
|
||||
|
||||
static void GetImagePropertyComplete(napi_env env, napi_status status, ImageSourceAsyncContext *context)
|
||||
@ -865,6 +912,67 @@ static std::unique_ptr<ImageSourceAsyncContext> UnwrapContext(napi_env env, napi
|
||||
return context;
|
||||
}
|
||||
|
||||
static bool CheckExifDataValue(const std::string &key, const std::string &value, std::string &errorInfo)
|
||||
{
|
||||
if (IsSameTextStr(key, "BitsPerSample")) {
|
||||
std::vector<std::string> bitsVec;
|
||||
SplitStr(value, ",", bitsVec);
|
||||
if (bitsVec.size() > NUM_2) {
|
||||
errorInfo = "BitsPerSample has invalid exif value: ";
|
||||
errorInfo.append(value);
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < bitsVec.size(); i++) {
|
||||
if (!IsNumericStr(bitsVec[i])) {
|
||||
errorInfo = "BitsPerSample has invalid exif value: ";
|
||||
errorInfo.append(bitsVec[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (IsSameTextStr(key, "Orientation")) {
|
||||
if (!IsNumericStr(value) || atoi(value.c_str()) < 1 || atoi(value.c_str()) > NUM_8) {
|
||||
errorInfo = "Orientation has invalid exif value: ";
|
||||
errorInfo.append(value);
|
||||
return false;
|
||||
}
|
||||
} else if (IsSameTextStr(key, "ImageLength") || IsSameTextStr(key, "ImageWidth")) {
|
||||
if (!IsNumericStr(value)) {
|
||||
errorInfo = "ImageLength or ImageWidth has invalid exif value: ";
|
||||
errorInfo.append(value);
|
||||
return false;
|
||||
}
|
||||
} else if (IsSameTextStr(key, "GPSLatitude") || IsSameTextStr(key, "GPSLongitude")) {
|
||||
std::vector<std::string> gpsVec;
|
||||
SplitStr(value, ",", gpsVec);
|
||||
if (gpsVec.size() != NUM_2) {
|
||||
errorInfo = "GPSLatitude or GPSLongitude has invalid exif value: ";
|
||||
errorInfo.append(value);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < gpsVec.size(); i++) {
|
||||
if (!IsNumericStr(gpsVec[i])) {
|
||||
errorInfo = "GPSLatitude or GPSLongitude has invalid exif value: ";
|
||||
errorInfo.append(gpsVec[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (IsSameTextStr(key, "GPSLatitudeRef")) {
|
||||
if (!IsSameTextStr(value, "N") && !IsSameTextStr(value, "S")) {
|
||||
errorInfo = "GPSLatitudeRef has invalid exif value: ";
|
||||
errorInfo.append(value);
|
||||
return false;
|
||||
}
|
||||
} else if (IsSameTextStr(key, "GPSLongitudeRef")) {
|
||||
if (!IsSameTextStr(value, "W") && !IsSameTextStr(value, "E")) {
|
||||
errorInfo = "GPSLongitudeRef has invalid exif value: ";
|
||||
errorInfo.append(value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ImageSourceAsyncContext> UnwrapContextForModify(napi_env env,
|
||||
napi_callback_info info)
|
||||
{
|
||||
@ -914,6 +1022,9 @@ static std::unique_ptr<ImageSourceAsyncContext> UnwrapContextForModify(napi_env
|
||||
}
|
||||
}
|
||||
context->pathName = ImageSourceNapi::filePath_;
|
||||
context->fdIndex = ImageSourceNapi::fileDescriptor_;
|
||||
context->sourceBuffer = ImageSourceNapi::fileBuffer_;
|
||||
context->sourceBufferSize = ImageSourceNapi::fileBufferSize_;
|
||||
return context;
|
||||
}
|
||||
|
||||
@ -940,8 +1051,25 @@ napi_value ImageSourceNapi::ModifyImageProperty(napi_env env, napi_callback_info
|
||||
[](napi_env env, void *data)
|
||||
{
|
||||
auto context = static_cast<ImageSourceAsyncContext*>(data);
|
||||
context->status = context->rImageSource->ModifyImageProperty(context->index,
|
||||
context->keyStr, context->valueStr, context->pathName);
|
||||
|
||||
if (!CheckExifDataValue(context->keyStr, context->valueStr, context->errMsg)) {
|
||||
HiLog::Error(LABEL, "There is invalid exif data parameter");
|
||||
context->status = ERR_MEDIA_VALUE_INVALID;
|
||||
return;
|
||||
}
|
||||
if (!IsSameTextStr(context->pathName, "")) {
|
||||
context->status = context->rImageSource->ModifyImageProperty(context->index,
|
||||
context->keyStr, context->valueStr, context->pathName);
|
||||
} else if (context->fdIndex != -1) {
|
||||
context->status = context->rImageSource->ModifyImageProperty(context->index,
|
||||
context->keyStr, context->valueStr, context->fdIndex);
|
||||
} else if (context->sourceBuffer != nullptr) {
|
||||
context->status = context->rImageSource->ModifyImageProperty(context->index,
|
||||
context->keyStr, context->valueStr, static_cast<uint8_t *>(context->sourceBuffer),
|
||||
context->sourceBufferSize);
|
||||
} else {
|
||||
HiLog::Error(LABEL, "There is no image source!");
|
||||
}
|
||||
},
|
||||
reinterpret_cast<napi_async_complete_callback>(ModifyImagePropertyComplete),
|
||||
asyncContext,
|
||||
|
@ -164,6 +164,10 @@ public:
|
||||
NATIVEEXPORT uint32_t GetImagePropertyString(uint32_t index, const std::string &key, std::string &value);
|
||||
NATIVEEXPORT uint32_t ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value,
|
||||
const std::string &path);
|
||||
NATIVEEXPORT uint32_t ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value,
|
||||
const int fd);
|
||||
NATIVEEXPORT uint32_t ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value,
|
||||
uint8_t *data, uint32_t size);
|
||||
NATIVEEXPORT const NinePatchInfo &GetNinePatchInfo() const;
|
||||
NATIVEEXPORT void SetMemoryUsagePreference(const MemoryUsagePreference preference);
|
||||
NATIVEEXPORT MemoryUsagePreference GetMemoryUsagePreference();
|
||||
|
@ -39,6 +39,9 @@ public:
|
||||
}
|
||||
|
||||
static std::string filePath_;
|
||||
static int fileDescriptor_;
|
||||
static void* fileBuffer_;
|
||||
static size_t fileBufferSize_;
|
||||
|
||||
private:
|
||||
static napi_value Constructor(napi_env env, napi_callback_info info);
|
||||
|
@ -36,7 +36,9 @@ public:
|
||||
*/
|
||||
int ParseExifData(const unsigned char *buf, unsigned len);
|
||||
int ParseExifData(const std::string &data);
|
||||
bool ModifyExifData(const ExifTag &tag, const std::string &value, const std::string &path);
|
||||
uint32_t ModifyExifData(const ExifTag &tag, const std::string &value, const std::string &path);
|
||||
uint32_t ModifyExifData(const ExifTag &tag, const std::string &value, const int fd);
|
||||
uint32_t ModifyExifData(const ExifTag &tag, const std::string &value, unsigned char *data, uint32_t size);
|
||||
|
||||
public:
|
||||
std::string bitsPerSample_; // Number of bits in each pixel of an image.
|
||||
@ -51,11 +53,18 @@ public:
|
||||
|
||||
private:
|
||||
void SetExifTagValues(const ExifTag &tag, const std::string &value);
|
||||
ExifIfd GetImageFileDirectory(const ExifTag &tag);
|
||||
ExifEntry* InitExifTag(ExifData *exif, ExifIfd ifd, ExifTag tag);
|
||||
ExifEntry* CreateExifTag(ExifData *exif, ExifIfd ifd, ExifTag tag, size_t len, ExifFormat format);
|
||||
long GetFileSize(FILE *fp);
|
||||
void ReleaseSource(unsigned char *buf, FILE *file);
|
||||
void ReleaseSource(unsigned char **ptrBuf, FILE **ptrFile);
|
||||
bool CreateExifData(unsigned char *buf, unsigned long length, ExifData **data, bool &isNewExifData);
|
||||
unsigned int GetOrginExifDataLength(const bool &isNewExifData, unsigned char *buf);
|
||||
ExifByteOrder GetExifByteOrder(const bool &isNewExifData, unsigned char *buf);
|
||||
bool CreateExifEntry(const ExifTag &tag, ExifData *data, const std::string &value,
|
||||
ExifByteOrder order, ExifEntry **ptrEntry);
|
||||
bool WriteExifDataToFile(ExifData *data, unsigned int orginExifDataLength, unsigned long fileLength,
|
||||
unsigned char *buf, FILE *fp);
|
||||
void UpdateCacheExifData(FILE *fp);
|
||||
|
||||
private:
|
||||
ExifIfd imageFileDirectory_;
|
||||
|
@ -55,7 +55,10 @@ public:
|
||||
uint32_t GetImagePropertyString(uint32_t index, const std::string &key, std::string &value) override;
|
||||
uint32_t ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value,
|
||||
const std::string &path) override;
|
||||
|
||||
uint32_t ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value,
|
||||
const int fd) override;
|
||||
uint32_t ModifyImageProperty(uint32_t index, const std::string &key, const std::string &value,
|
||||
uint8_t *data, uint32_t size) override;
|
||||
private:
|
||||
DISALLOW_COPY_AND_MOVE(JpegDecoder);
|
||||
int ExifPrintMethod();
|
||||
@ -69,7 +72,7 @@ private:
|
||||
void CreateDecoder();
|
||||
bool IsMarker(uint8_t rawPrefix, uint8_t rawMarkderCode, uint8_t markerCode);
|
||||
bool FindMarker(InputDataStream &stream, uint8_t marker);
|
||||
ExifTag getExifTagFromKey(const std::string &key, const std::string &value);
|
||||
ExifTag getExifTagFromKey(const std::string &key);
|
||||
|
||||
static MultimediaPlugin::PluginServer &pluginServer_;
|
||||
jpeg_decompress_struct decodeInfo_;
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "exif_info.h"
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
#include "media_errors.h"
|
||||
#include "string_ex.h"
|
||||
#include "securec.h"
|
||||
|
||||
@ -38,6 +40,7 @@ namespace {
|
||||
static const int MOVE_OFFSET_8 = 8;
|
||||
static const int LENGTH_ARRAY_SIZE = 2;
|
||||
static const int CONSTANT_2 = 2;
|
||||
static const unsigned long MAX_FILE_SIZE = 1000 * 1000 * 1000;
|
||||
|
||||
/* raw EXIF header data */
|
||||
static const unsigned char exifHeader[] = {
|
||||
@ -117,195 +120,188 @@ void EXIFInfo::SetExifTagValues(const ExifTag &tag, const std::string &value)
|
||||
}
|
||||
}
|
||||
|
||||
bool EXIFInfo::ModifyExifData(const ExifTag &tag, const std::string &value, const std::string &path)
|
||||
uint32_t EXIFInfo::ModifyExifData(const ExifTag &tag, const std::string &value, const std::string &path)
|
||||
{
|
||||
FILE *file = fopen(path.c_str(), "rb");
|
||||
if (file == nullptr) {
|
||||
HiLog::Error(LABEL, "Error creating file %{public}s", path.c_str());
|
||||
return false;
|
||||
return Media::ERR_MEDIA_IO_ABNORMAL;
|
||||
}
|
||||
|
||||
// read jpeg file to buff
|
||||
unsigned long fileLength = GetFileSize(file);
|
||||
if (fileLength == 0) {
|
||||
if (fileLength == 0 || fileLength > MAX_FILE_SIZE) {
|
||||
HiLog::Error(LABEL, "Get file size failed.");
|
||||
fclose(file);
|
||||
return false;
|
||||
return Media::ERR_MEDIA_BUFFER_TOO_SMALL;
|
||||
}
|
||||
unsigned char *fileBuf = (unsigned char *)malloc(fileLength);
|
||||
|
||||
unsigned char *fileBuf = static_cast<unsigned char *>(malloc(fileLength));
|
||||
if (fileBuf == nullptr) {
|
||||
HiLog::Error(LABEL, "Allocate buf for %{public}s failed.", path.c_str());
|
||||
fclose(file);
|
||||
return false;
|
||||
return Media::ERR_IMAGE_MALLOC_ABNORMAL;
|
||||
}
|
||||
|
||||
if (fread(fileBuf, fileLength, 1, file) != 1) {
|
||||
HiLog::Error(LABEL, "Read %{public}s failed.", path.c_str());
|
||||
ReleaseSource(fileBuf, file);
|
||||
return false;
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
return Media::ERR_MEDIA_READ_PARCEL_FAIL;
|
||||
}
|
||||
|
||||
if (!(fileBuf[0] == 0xFF && fileBuf[1] == 0xD8)) {
|
||||
HiLog::Error(LABEL, "%{public}s is not jpeg file.", path.c_str());
|
||||
ReleaseSource(fileBuf, file);
|
||||
return false;
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
return Media::ERR_IMAGE_MISMATCHED_FORMAT;
|
||||
}
|
||||
|
||||
unsigned char lenthArray[LENGTH_ARRAY_SIZE] = {
|
||||
fileBuf[BUFFER_POSITION_5], fileBuf[BUFFER_POSITION_4]
|
||||
};
|
||||
unsigned int orginExifDataLength = *(unsigned int*)lenthArray;
|
||||
|
||||
ExifData *ptrExifData = nullptr;
|
||||
if ((fileBuf[BUFFER_POSITION_6] == 'E' && fileBuf[BUFFER_POSITION_7] == 'x' &&
|
||||
fileBuf[BUFFER_POSITION_8] == 'i' && fileBuf[BUFFER_POSITION_9] == 'f')) {
|
||||
ptrExifData = exif_data_new_from_file(path.c_str());
|
||||
if (!ptrExifData) {
|
||||
HiLog::Error(LABEL, "Create exif data from file failed.");
|
||||
ReleaseSource(fileBuf, file);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ptrExifData = exif_data_new();
|
||||
if (!ptrExifData) {
|
||||
HiLog::Error(LABEL, "Create exif data failed.");
|
||||
ReleaseSource(fileBuf, file);
|
||||
return false;
|
||||
}
|
||||
/* Set the image options */
|
||||
exif_data_set_option(ptrExifData, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
|
||||
exif_data_set_data_type(ptrExifData, EXIF_DATA_TYPE_COMPRESSED);
|
||||
exif_data_set_byte_order(ptrExifData, EXIF_BYTE_ORDER_INTEL);
|
||||
|
||||
/* Create the mandatory EXIF fields with default data */
|
||||
exif_data_fix(ptrExifData);
|
||||
bool isNewExifData = false;
|
||||
if (!CreateExifData(fileBuf, fileLength, &ptrExifData, isNewExifData)) {
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
(void)fclose(file);
|
||||
file = nullptr;
|
||||
|
||||
ExifByteOrder order = EXIF_BYTE_ORDER_MOTOROLA;
|
||||
if (fileBuf[BUFFER_POSITION_12] == 'M' && fileBuf[BUFFER_POSITION_13] == 'M') {
|
||||
order = EXIF_BYTE_ORDER_MOTOROLA;
|
||||
} else {
|
||||
order = EXIF_BYTE_ORDER_INTEL;
|
||||
unsigned int orginExifDataLength = GetOrginExifDataLength(isNewExifData, fileBuf);
|
||||
if (!isNewExifData && orginExifDataLength == 0) {
|
||||
HiLog::Error(LABEL, "There is no orginExifDataLength node in %{public}s.", path.c_str());
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
FILE *newFile = fopen(path.c_str(), "wb");
|
||||
ExifByteOrder order = GetExifByteOrder(isNewExifData, fileBuf);
|
||||
FILE *newFile = fopen(path.c_str(), "wb+");
|
||||
if (newFile == nullptr) {
|
||||
HiLog::Error(LABEL, "Error create new file %{public}s", path.c_str());
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
ReleaseSource(&fileBuf, &newFile);
|
||||
return Media::ERR_MEDIA_IO_ABNORMAL;
|
||||
}
|
||||
ExifEntry *entry = nullptr;
|
||||
if (!CreateExifEntry(tag, ptrExifData, value, order, &entry)) {
|
||||
ReleaseSource(&fileBuf, &newFile);
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
if (!WriteExifDataToFile(ptrExifData, orginExifDataLength, fileLength, fileBuf, newFile)) {
|
||||
ReleaseSource(&fileBuf, &newFile);
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_MEDIA_WRITE_PARCEL_FAIL;
|
||||
}
|
||||
ReleaseSource(&fileBuf, &newFile);
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t EXIFInfo::ModifyExifData(const ExifTag &tag, const std::string &value, const int fd)
|
||||
{
|
||||
const int localFd = dup(fd);
|
||||
FILE *file = fdopen(localFd, "wb+");
|
||||
if (file == nullptr) {
|
||||
HiLog::Error(LABEL, "Error creating file %{public}d", localFd);
|
||||
return Media::ERR_MEDIA_IO_ABNORMAL;
|
||||
}
|
||||
|
||||
// read jpeg file to buff
|
||||
unsigned long fileLength = GetFileSize(file);
|
||||
if (fileLength == 0 || fileLength > MAX_FILE_SIZE) {
|
||||
HiLog::Error(LABEL, "Get file size failed.");
|
||||
fclose(file);
|
||||
return Media::ERR_MEDIA_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
unsigned char *fileBuf = static_cast<unsigned char *>(malloc(fileLength));
|
||||
if (fileBuf == nullptr) {
|
||||
HiLog::Error(LABEL, "Allocate buf for %{public}d failed.", localFd);
|
||||
fclose(file);
|
||||
return Media::ERR_IMAGE_MALLOC_ABNORMAL;
|
||||
}
|
||||
|
||||
// Set current position to begin of file.
|
||||
(void)fseek(file, 0L, 0);
|
||||
if (fread(fileBuf, fileLength, 1, file) != 1) {
|
||||
HiLog::Error(LABEL, "Read %{public}d failed.", localFd);
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
return Media::ERR_MEDIA_READ_PARCEL_FAIL;
|
||||
}
|
||||
|
||||
if (!(fileBuf[0] == 0xFF && fileBuf[1] == 0xD8)) {
|
||||
HiLog::Error(LABEL, "%{public}d is not jpeg file.", localFd);
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
return Media::ERR_IMAGE_MISMATCHED_FORMAT;
|
||||
}
|
||||
|
||||
ExifData *ptrExifData = nullptr;
|
||||
bool isNewExifData = false;
|
||||
if (!CreateExifData(fileBuf, fileLength, &ptrExifData, isNewExifData)) {
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
unsigned int orginExifDataLength = GetOrginExifDataLength(isNewExifData, fileBuf);
|
||||
if (!isNewExifData && orginExifDataLength == 0) {
|
||||
HiLog::Error(LABEL, "There is no orginExifDataLength node in %{public}d.", localFd);
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
ExifByteOrder order = GetExifByteOrder(isNewExifData, fileBuf);
|
||||
// Set current position to begin of new file.
|
||||
(void)fseek(file, 0L, 0);
|
||||
ExifEntry *entry = nullptr;
|
||||
switch (tag) {
|
||||
case EXIF_TAG_BITS_PER_SAMPLE: {
|
||||
entry = InitExifTag(ptrExifData, EXIF_IFD_1, EXIF_TAG_BITS_PER_SAMPLE);
|
||||
std::vector<std::string> bitsVec;
|
||||
SplitStr(value, ",", bitsVec);
|
||||
if (bitsVec.size() > CONSTANT_2) {
|
||||
HiLog::Error(LABEL, "BITS_PER_SAMPLE Invalid value %{public}s", value.c_str());
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
}
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (bitsVec.size() != 0) {
|
||||
for (size_t i = 0; i < bitsVec.size(); i++) {
|
||||
exif_set_short(entry->data + i * CONSTANT_2, order, (ExifShort)atoi(bitsVec[i].c_str()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_ORIENTATION: {
|
||||
entry = InitExifTag(ptrExifData, EXIF_IFD_0, EXIF_TAG_ORIENTATION);
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
exif_set_short(entry->data, order, (ExifShort)atoi(value.c_str()));
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_IMAGE_LENGTH: {
|
||||
entry = InitExifTag(ptrExifData, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH);
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
exif_set_short(entry->data, order, (ExifShort)atoi(value.c_str()));
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_IMAGE_WIDTH: {
|
||||
entry = InitExifTag(ptrExifData, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH);
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
exif_set_short(entry->data, order, (ExifShort)atoi(value.c_str()));
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_GPS_LATITUDE: {
|
||||
std::vector<std::string> latVec;
|
||||
SplitStr(value, ",", latVec);
|
||||
if (latVec.size() != CONSTANT_2) {
|
||||
HiLog::Error(LABEL, "GPS_LATITUDE Invalid value %{public}s", value.c_str());
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
}
|
||||
if (!CreateExifEntry(tag, ptrExifData, value, order, &entry)) {
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
ExifRational latRational;
|
||||
latRational.numerator = atoi(latVec[0].c_str());
|
||||
latRational.denominator = atoi(latVec[1].c_str());
|
||||
entry = CreateExifTag(ptrExifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE,
|
||||
sizeof(latRational), EXIF_FORMAT_RATIONAL);
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
exif_set_rational(entry->data, order, latRational);
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_GPS_LONGITUDE: {
|
||||
std::vector<std::string> longVec;
|
||||
SplitStr(value, ",", longVec);
|
||||
if (longVec.size() != CONSTANT_2) {
|
||||
HiLog::Error(LABEL, "GPS_LONGITUDE Invalid value %{public}s", value.c_str());
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
}
|
||||
if (!WriteExifDataToFile(ptrExifData, orginExifDataLength, fileLength, fileBuf, file)) {
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_MEDIA_WRITE_PARCEL_FAIL;
|
||||
}
|
||||
ReleaseSource(&fileBuf, &file);
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::SUCCESS;
|
||||
}
|
||||
|
||||
ExifRational longRational;
|
||||
longRational.numerator = atoi(longVec[0].c_str());
|
||||
longRational.denominator = atoi(longVec[1].c_str());
|
||||
entry = CreateExifTag(ptrExifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE,
|
||||
sizeof(longRational), EXIF_FORMAT_RATIONAL);
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
exif_set_rational(entry->data, order, longRational);
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_GPS_LATITUDE_REF: {
|
||||
entry = CreateExifTag(ptrExifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF,
|
||||
value.length(), EXIF_FORMAT_ASCII);
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (memcpy_s(entry->data, value.length(), value.c_str(), value.length()) != 0) {
|
||||
HiLog::Error(LABEL, "LATITUDE ref memcpy error");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_GPS_LONGITUDE_REF: {
|
||||
entry = CreateExifTag(ptrExifData, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF,
|
||||
value.length(), EXIF_FORMAT_ASCII);
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (memcpy_s(entry->data, value.length(), value.c_str(), value.length()) != 0) {
|
||||
HiLog::Error(LABEL, "LONGITUDE ref memcpy error");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
uint32_t EXIFInfo::ModifyExifData(const ExifTag &tag, const std::string &value,
|
||||
unsigned char *data, uint32_t size)
|
||||
{
|
||||
if (data == nullptr) {
|
||||
HiLog::Error(LABEL, "buffer is nullptr.");
|
||||
return Media::ERR_IMAGE_SOURCE_DATA;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
HiLog::Error(LABEL, "buffer size is 0.");
|
||||
return Media::ERR_MEDIA_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (!(data[0] == 0xFF && data[1] == 0xD8)) {
|
||||
HiLog::Error(LABEL, "This is not jpeg file.");
|
||||
return Media::ERR_IMAGE_MISMATCHED_FORMAT;
|
||||
}
|
||||
|
||||
ExifData *ptrExifData = nullptr;
|
||||
bool isNewExifData = false;
|
||||
if (!CreateExifData(data, size, &ptrExifData, isNewExifData)) {
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
unsigned int orginExifDataLength = GetOrginExifDataLength(isNewExifData, data);
|
||||
if (!isNewExifData && orginExifDataLength == 0) {
|
||||
HiLog::Error(LABEL, "There is no orginExifDataLength node in buffer.");
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
ExifByteOrder order = GetExifByteOrder(isNewExifData, data);
|
||||
ExifEntry *entry = nullptr;
|
||||
if (!CreateExifEntry(tag, ptrExifData, value, order, &entry)) {
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
unsigned char* exifDataBuf = nullptr;
|
||||
@ -313,68 +309,95 @@ bool EXIFInfo::ModifyExifData(const ExifTag &tag, const std::string &value, cons
|
||||
exif_data_save_data(ptrExifData, &exifDataBuf, &exifDataBufLength);
|
||||
if (exifDataBuf == nullptr) {
|
||||
HiLog::Error(LABEL, "Get Exif Data Buf failed!");
|
||||
return false;
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
/* Write EXIF header */
|
||||
if (fwrite(exifHeader, sizeof(exifHeader), 1, newFile) != 1) {
|
||||
HiLog::Error(LABEL, "Error writing EXIF header to file!");
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
if (size == 0 || size > MAX_FILE_SIZE) {
|
||||
HiLog::Error(LABEL, "Buffer size is out of range.");
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
unsigned char *tempBuf = static_cast<unsigned char *>(malloc(size));
|
||||
if (tempBuf == nullptr) {
|
||||
HiLog::Error(LABEL, "Allocate temp buffer ailed.");
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_IMAGE_MALLOC_ABNORMAL;
|
||||
}
|
||||
|
||||
/* Write EXIF block length in big-endian order */
|
||||
if (fputc((exifDataBufLength + LENGTH_OFFSET_2) >> MOVE_OFFSET_8, newFile) < 0) {
|
||||
HiLog::Error(LABEL, "Error writing EXIF block length to file!");
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
}
|
||||
if (fputc((exifDataBufLength + LENGTH_OFFSET_2) & 0xff, newFile) < 0) {
|
||||
HiLog::Error(LABEL, "Error writing EXIF block length to file!");
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
// Write EXIF header to buffer
|
||||
uint32_t index = 0;
|
||||
if (sizeof(exifHeader) >= size) {
|
||||
HiLog::Error(LABEL, "There is not enough space for EXIF header!");
|
||||
free(tempBuf);
|
||||
tempBuf = nullptr;
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_MEDIA_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
/* Write EXIF data block */
|
||||
if (fwrite(exifDataBuf, exifDataBufLength, 1, newFile) != 1) {
|
||||
HiLog::Error(LABEL, "Error writing EXIF data block to file!");
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
}
|
||||
/* Write JPEG image data, skipping the non-EXIF header */
|
||||
unsigned int dataOffset = orginExifDataLength + sizeof(exifHeader);
|
||||
if (fwrite(fileBuf + dataOffset, fileLength - dataOffset, 1, newFile) != 1) {
|
||||
HiLog::Error(LABEL, "Error writing JPEG image data to file!");
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return false;
|
||||
for (size_t i = 0; i < sizeof(exifHeader); i++) {
|
||||
tempBuf[index] = exifHeader[i];
|
||||
index += 1;
|
||||
}
|
||||
|
||||
ReleaseSource(fileBuf, newFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
ExifIfd EXIFInfo::GetImageFileDirectory(const ExifTag &tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case EXIF_TAG_BITS_PER_SAMPLE:
|
||||
case EXIF_TAG_ORIENTATION:
|
||||
case EXIF_TAG_IMAGE_LENGTH:
|
||||
case EXIF_TAG_IMAGE_WIDTH: {
|
||||
return EXIF_IFD_0;
|
||||
}
|
||||
case EXIF_TAG_DATE_TIME_ORIGINAL: {
|
||||
return EXIF_IFD_EXIF;
|
||||
}
|
||||
case EXIF_TAG_GPS_LATITUDE:
|
||||
case EXIF_TAG_GPS_LONGITUDE:
|
||||
case EXIF_TAG_GPS_LATITUDE_REF:
|
||||
case EXIF_TAG_GPS_LONGITUDE_REF: {
|
||||
return EXIF_IFD_GPS;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
// Write EXIF block length in big-endian order
|
||||
unsigned char highBit = static_cast<unsigned char>((exifDataBufLength + LENGTH_OFFSET_2) >> MOVE_OFFSET_8);
|
||||
if (index >= size) {
|
||||
HiLog::Error(LABEL, "There is not enough space for writing EXIF block length!");
|
||||
free(tempBuf);
|
||||
tempBuf = nullptr;
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_MEDIA_OUT_OF_RANGE;
|
||||
}
|
||||
return EXIF_IFD_COUNT;
|
||||
tempBuf[index] = highBit;
|
||||
index += 1;
|
||||
|
||||
unsigned char lowBit = static_cast<unsigned char>((exifDataBufLength + LENGTH_OFFSET_2) & 0xff);
|
||||
if (index >= size) {
|
||||
HiLog::Error(LABEL, "There is not enough space for writing EXIF block length!");
|
||||
free(tempBuf);
|
||||
tempBuf = nullptr;
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_MEDIA_OUT_OF_RANGE;
|
||||
}
|
||||
tempBuf[index] = lowBit;
|
||||
index += 1;
|
||||
|
||||
// Write EXIF data block
|
||||
if ((index + exifDataBufLength) >= size) {
|
||||
HiLog::Error(LABEL, "There is not enough space for writing EXIF data block!");
|
||||
free(tempBuf);
|
||||
tempBuf = nullptr;
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_MEDIA_OUT_OF_RANGE;
|
||||
}
|
||||
for (unsigned int i = 0; i < exifDataBufLength; i++) {
|
||||
tempBuf[index] = exifDataBuf[i];
|
||||
index += 1;
|
||||
}
|
||||
|
||||
// Write JPEG image data, skipping the non-EXIF header
|
||||
if ((index + size - orginExifDataLength - sizeof(exifHeader)) > size) {
|
||||
HiLog::Error(LABEL, "There is not enough space for writing JPEG image data!");
|
||||
free(tempBuf);
|
||||
tempBuf = nullptr;
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::ERR_MEDIA_OUT_OF_RANGE;
|
||||
}
|
||||
for (unsigned int i = 0; i < (size - orginExifDataLength - sizeof(exifHeader)); i++) {
|
||||
tempBuf[index] = data[orginExifDataLength + sizeof(exifHeader) + i];
|
||||
index += 1;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
data[i] = tempBuf[i];
|
||||
}
|
||||
|
||||
ParseExifData(data, static_cast<unsigned int>(index));
|
||||
free(tempBuf);
|
||||
tempBuf = nullptr;
|
||||
exif_data_unref(ptrExifData);
|
||||
return Media::SUCCESS;
|
||||
}
|
||||
|
||||
ExifEntry* EXIFInfo::InitExifTag(ExifData *exif, ExifIfd ifd, ExifTag tag)
|
||||
@ -411,7 +434,7 @@ ExifEntry* EXIFInfo::CreateExifTag(ExifData *exif, ExifIfd ifd, ExifTag tag,
|
||||
{
|
||||
void *buf;
|
||||
ExifEntry *entry;
|
||||
|
||||
|
||||
if ((entry = exif_content_get_entry(exif->ifd[ifd], tag)) != nullptr) {
|
||||
return entry;
|
||||
}
|
||||
@ -461,30 +484,247 @@ long EXIFInfo::GetFileSize(FILE *fp)
|
||||
|
||||
/* Save the current position. */
|
||||
position = ftell(fp);
|
||||
|
||||
|
||||
/* Jump to the end of the file. */
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
|
||||
(void)fseek(fp, 0L, SEEK_END);
|
||||
|
||||
/* Get the end position. */
|
||||
size = ftell(fp);
|
||||
|
||||
|
||||
/* Jump back to the original position. */
|
||||
fseek(fp, position, SEEK_SET);
|
||||
(void)fseek(fp, position, SEEK_SET);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void EXIFInfo::ReleaseSource(unsigned char *buf, FILE *file)
|
||||
bool EXIFInfo::CreateExifData(unsigned char *buf, unsigned long length, ExifData **ptrData, bool &isNewExifData)
|
||||
{
|
||||
if (buf) {
|
||||
free(buf);
|
||||
buf = nullptr;
|
||||
if ((buf[BUFFER_POSITION_6] == 'E' && buf[BUFFER_POSITION_7] == 'x' &&
|
||||
buf[BUFFER_POSITION_8] == 'i' && buf[BUFFER_POSITION_9] == 'f')) {
|
||||
*ptrData = exif_data_new_from_data(buf, static_cast<unsigned int>(length));
|
||||
if (!(*ptrData)) {
|
||||
HiLog::Error(LABEL, "Create exif data from file failed.");
|
||||
return false;
|
||||
}
|
||||
isNewExifData = false;
|
||||
HiLog::Error(LABEL, "Create exif data from buffer.");
|
||||
} else {
|
||||
*ptrData = exif_data_new();
|
||||
if (!(*ptrData)) {
|
||||
HiLog::Error(LABEL, "Create exif data failed.");
|
||||
return false;
|
||||
}
|
||||
/* Set the image options */
|
||||
exif_data_set_option(*ptrData, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
|
||||
exif_data_set_data_type(*ptrData, EXIF_DATA_TYPE_COMPRESSED);
|
||||
exif_data_set_byte_order(*ptrData, EXIF_BYTE_ORDER_INTEL);
|
||||
|
||||
/* Create the mandatory EXIF fields with default data */
|
||||
exif_data_fix(*ptrData);
|
||||
isNewExifData = true;
|
||||
HiLog::Error(LABEL, "Create new exif data.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int EXIFInfo::GetOrginExifDataLength(const bool &isNewExifData, unsigned char *buf)
|
||||
{
|
||||
unsigned int orginExifDataLength = 0;
|
||||
if (!isNewExifData) {
|
||||
unsigned char lenthArray[LENGTH_ARRAY_SIZE] = {
|
||||
buf[BUFFER_POSITION_5], buf[BUFFER_POSITION_4]
|
||||
};
|
||||
orginExifDataLength = *(unsigned int*)lenthArray;
|
||||
}
|
||||
return orginExifDataLength;
|
||||
}
|
||||
|
||||
ExifByteOrder EXIFInfo::GetExifByteOrder(const bool &isNewExifData, unsigned char *buf)
|
||||
{
|
||||
if (isNewExifData) {
|
||||
return EXIF_BYTE_ORDER_INTEL;
|
||||
} else {
|
||||
if (buf[BUFFER_POSITION_12] == 'M' && buf[BUFFER_POSITION_13] == 'M') {
|
||||
return EXIF_BYTE_ORDER_MOTOROLA;
|
||||
} else {
|
||||
return EXIF_BYTE_ORDER_INTEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EXIFInfo::CreateExifEntry(const ExifTag &tag, ExifData *data, const std::string &value,
|
||||
ExifByteOrder order, ExifEntry **ptrEntry)
|
||||
{
|
||||
switch (tag) {
|
||||
case EXIF_TAG_BITS_PER_SAMPLE: {
|
||||
*ptrEntry = InitExifTag(data, EXIF_IFD_1, EXIF_TAG_BITS_PER_SAMPLE);
|
||||
std::vector<std::string> bitsVec;
|
||||
SplitStr(value, ",", bitsVec);
|
||||
if (bitsVec.size() > CONSTANT_2) {
|
||||
HiLog::Error(LABEL, "BITS_PER_SAMPLE Invalid value %{public}s", value.c_str());
|
||||
return false;
|
||||
}
|
||||
if (bitsVec.size() != 0) {
|
||||
for (size_t i = 0; i < bitsVec.size(); i++) {
|
||||
exif_set_short((*ptrEntry)->data + i * CONSTANT_2, order, (ExifShort)atoi(bitsVec[i].c_str()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_ORIENTATION: {
|
||||
*ptrEntry = InitExifTag(data, EXIF_IFD_0, EXIF_TAG_ORIENTATION);
|
||||
exif_set_short((*ptrEntry)->data, order, (ExifShort)atoi(value.c_str()));
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_IMAGE_LENGTH: {
|
||||
*ptrEntry = InitExifTag(data, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH);
|
||||
exif_set_long((*ptrEntry)->data, order, (ExifLong)atoi(value.c_str()));
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_IMAGE_WIDTH: {
|
||||
*ptrEntry = InitExifTag(data, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH);
|
||||
exif_set_long((*ptrEntry)->data, order, (ExifLong)atoi(value.c_str()));
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_GPS_LATITUDE: {
|
||||
std::vector<std::string> latVec;
|
||||
SplitStr(value, ",", latVec);
|
||||
if (latVec.size() != CONSTANT_2) {
|
||||
HiLog::Error(LABEL, "GPS_LATITUDE Invalid value %{public}s", value.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ExifRational latRational;
|
||||
latRational.numerator = atoi(latVec[0].c_str());
|
||||
latRational.denominator = atoi(latVec[1].c_str());
|
||||
*ptrEntry = CreateExifTag(data, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE,
|
||||
sizeof(latRational), EXIF_FORMAT_RATIONAL);
|
||||
exif_set_rational((*ptrEntry)->data, order, latRational);
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_GPS_LONGITUDE: {
|
||||
std::vector<std::string> longVec;
|
||||
SplitStr(value, ",", longVec);
|
||||
if (longVec.size() != CONSTANT_2) {
|
||||
HiLog::Error(LABEL, "GPS_LONGITUDE Invalid value %{public}s", value.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ExifRational longRational;
|
||||
longRational.numerator = atoi(longVec[0].c_str());
|
||||
longRational.denominator = atoi(longVec[1].c_str());
|
||||
*ptrEntry = CreateExifTag(data, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE,
|
||||
sizeof(longRational), EXIF_FORMAT_RATIONAL);
|
||||
exif_set_rational((*ptrEntry)->data, order, longRational);
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_GPS_LATITUDE_REF: {
|
||||
*ptrEntry = CreateExifTag(data, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF,
|
||||
value.length(), EXIF_FORMAT_ASCII);
|
||||
if (memcpy_s((*ptrEntry)->data, value.length(), value.c_str(), value.length()) != 0) {
|
||||
HiLog::Error(LABEL, "LATITUDE ref memcpy error");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXIF_TAG_GPS_LONGITUDE_REF: {
|
||||
*ptrEntry = CreateExifTag(data, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF,
|
||||
value.length(), EXIF_FORMAT_ASCII);
|
||||
if (memcpy_s((*ptrEntry)->data, value.length(), value.c_str(), value.length()) != 0) {
|
||||
HiLog::Error(LABEL, "LONGITUDE ref memcpy error");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EXIFInfo::WriteExifDataToFile(ExifData *data, unsigned int orginExifDataLength, unsigned long fileLength,
|
||||
unsigned char *buf, FILE *fp)
|
||||
{
|
||||
unsigned char* exifDataBuf = nullptr;
|
||||
unsigned int exifDataBufLength = 0;
|
||||
exif_data_save_data(data, &exifDataBuf, &exifDataBufLength);
|
||||
if (exifDataBuf == nullptr) {
|
||||
HiLog::Error(LABEL, "Get Exif Data Buf failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file != nullptr) {
|
||||
fclose(file);
|
||||
file = nullptr;
|
||||
// Write EXIF header
|
||||
if (fwrite(exifHeader, sizeof(exifHeader), 1, fp) != 1) {
|
||||
HiLog::Error(LABEL, "Error writing EXIF header to file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write EXIF block length in big-endian order
|
||||
if (fputc((exifDataBufLength + LENGTH_OFFSET_2) >> MOVE_OFFSET_8, fp) < 0) {
|
||||
HiLog::Error(LABEL, "Error writing EXIF block length to file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fputc((exifDataBufLength + LENGTH_OFFSET_2) & 0xff, fp) < 0) {
|
||||
HiLog::Error(LABEL, "Error writing EXIF block length to file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write EXIF data block
|
||||
if (fwrite(exifDataBuf, exifDataBufLength, 1, fp) != 1) {
|
||||
HiLog::Error(LABEL, "Error writing EXIF data block to file!");
|
||||
return false;
|
||||
}
|
||||
// Write JPEG image data, skipping the non-EXIF header
|
||||
unsigned int dataOffset = orginExifDataLength + sizeof(exifHeader);
|
||||
if (fwrite(buf + dataOffset, fileLength - dataOffset, 1, fp) != 1) {
|
||||
HiLog::Error(LABEL, "Error writing JPEG image data to file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateCacheExifData(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EXIFInfo::ReleaseSource(unsigned char **ptrBuf, FILE **ptrFile)
|
||||
{
|
||||
if (*ptrBuf) {
|
||||
free(*ptrBuf);
|
||||
*ptrBuf = nullptr;
|
||||
ptrBuf = nullptr;
|
||||
}
|
||||
|
||||
if (*ptrFile != nullptr) {
|
||||
fclose(*ptrFile);
|
||||
*ptrFile = nullptr;
|
||||
ptrFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void EXIFInfo::UpdateCacheExifData(FILE *fp)
|
||||
{
|
||||
unsigned long fileLength = GetFileSize(fp);
|
||||
if (fileLength == 0 || fileLength > MAX_FILE_SIZE) {
|
||||
HiLog::Error(LABEL, "Get file size failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char *fileBuf = static_cast<unsigned char *>(malloc(fileLength));
|
||||
if (fileBuf == nullptr) {
|
||||
HiLog::Error(LABEL, "Allocate buf failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set current position to begin of file.
|
||||
(void)fseek(fp, 0L, 0);
|
||||
if (fread(fileBuf, fileLength, 1, fp) != 1) {
|
||||
HiLog::Error(LABEL, "Read new file failed.");
|
||||
free(fileBuf);
|
||||
fileBuf = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
ParseExifData(fileBuf, static_cast<unsigned int>(fileLength));
|
||||
free(fileBuf);
|
||||
fileBuf = nullptr;
|
||||
}
|
||||
} // namespace ImagePlugin
|
||||
} // namespace OHOS
|
||||
|
@ -600,34 +600,25 @@ uint32_t JpegDecoder::GetImagePropertyString(uint32_t index, const std::string &
|
||||
return Media::SUCCESS;
|
||||
}
|
||||
|
||||
ExifTag JpegDecoder::getExifTagFromKey(const std::string &key, const std::string &value)
|
||||
ExifTag JpegDecoder::getExifTagFromKey(const std::string &key)
|
||||
{
|
||||
if (IsSameTextStr(key, BITS_PER_SAMPLE)) {
|
||||
exifInfo_.bitsPerSample_ = value;
|
||||
return EXIF_TAG_BITS_PER_SAMPLE;
|
||||
} else if (IsSameTextStr(key, ORIENTATION)) {
|
||||
exifInfo_.orientation_ = value;
|
||||
return EXIF_TAG_ORIENTATION;
|
||||
} else if (IsSameTextStr(key, IMAGE_LENGTH)) {
|
||||
exifInfo_.imageLength_ = value;
|
||||
return EXIF_TAG_IMAGE_LENGTH;
|
||||
} else if (IsSameTextStr(key, IMAGE_WIDTH)) {
|
||||
exifInfo_.imageWidth_ = value;
|
||||
return EXIF_TAG_IMAGE_WIDTH;
|
||||
} else if (IsSameTextStr(key, GPS_LATITUDE)) {
|
||||
exifInfo_.gpsLatitude_ = value;
|
||||
return EXIF_TAG_GPS_LATITUDE;
|
||||
} else if (IsSameTextStr(key, GPS_LONGITUDE)) {
|
||||
exifInfo_.gpsLongitude_ = value;
|
||||
return EXIF_TAG_GPS_LONGITUDE;
|
||||
} else if (IsSameTextStr(key, GPS_LATITUDE_REF)) {
|
||||
exifInfo_.gpsLatitudeRef_ = value;
|
||||
return EXIF_TAG_GPS_LATITUDE_REF;
|
||||
} else if (IsSameTextStr(key, GPS_LONGITUDE_REF)) {
|
||||
exifInfo_.gpsLongitudeRef_ = value;
|
||||
return EXIF_TAG_GPS_LONGITUDE_REF;
|
||||
} else if (IsSameTextStr(key, DATE_TIME_ORIGINAL)) {
|
||||
exifInfo_.dateTimeOriginal_ = value;
|
||||
return EXIF_TAG_DATE_TIME_ORIGINAL;
|
||||
} else {
|
||||
return EXIF_TAG_PRINT_IMAGE_MATCHING;
|
||||
@ -637,15 +628,50 @@ ExifTag JpegDecoder::getExifTagFromKey(const std::string &key, const std::string
|
||||
uint32_t JpegDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
|
||||
const std::string &value, const std::string &path)
|
||||
{
|
||||
HiLog::Error(LABEL, "[ModifyImageProperty] enter jped plugin, key:%{public}s, value:%{public}s",
|
||||
key.c_str(), value.c_str());
|
||||
ExifTag tag = getExifTagFromKey(key, value);
|
||||
HiLog::Error(LABEL, "[ModifyImageProperty] with path:%{public}s, key:%{public}s, value:%{public}s",
|
||||
path.c_str(), key.c_str(), value.c_str());
|
||||
ExifTag tag = getExifTagFromKey(key);
|
||||
if (tag == EXIF_TAG_PRINT_IMAGE_MATCHING) {
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
if (!exifInfo_.ModifyExifData(tag, value, path)) {
|
||||
return ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
uint32_t ret = exifInfo_.ModifyExifData(tag, value, path);
|
||||
if (ret != Media::SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
return Media::SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t JpegDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
|
||||
const std::string &value, const int fd)
|
||||
{
|
||||
HiLog::Error(LABEL, "[ModifyImageProperty] with fd:%{public}d, key:%{public}s, value:%{public}s",
|
||||
fd, key.c_str(), value.c_str());
|
||||
ExifTag tag = getExifTagFromKey(key);
|
||||
if (tag == EXIF_TAG_PRINT_IMAGE_MATCHING) {
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
uint32_t ret = exifInfo_.ModifyExifData(tag, value, fd);
|
||||
if (ret != Media::SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
return Media::SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t JpegDecoder::ModifyImageProperty(uint32_t index, const std::string &key,
|
||||
const std::string &value, uint8_t *data, uint32_t size)
|
||||
{
|
||||
HiLog::Error(LABEL, "[ModifyImageProperty] with buffer:%{public}p, key:%{public}s, value:%{public}s",
|
||||
data, key.c_str(), value.c_str());
|
||||
ExifTag tag = getExifTagFromKey(key);
|
||||
if (tag == EXIF_TAG_PRINT_IMAGE_MATCHING) {
|
||||
return Media::ERR_IMAGE_DECODE_EXIF_UNSUPPORT;
|
||||
}
|
||||
|
||||
uint32_t ret = exifInfo_.ModifyExifData(tag, value, data, size);
|
||||
if (ret != Media::SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
return Media::SUCCESS;
|
||||
}
|
||||
|
@ -154,6 +154,18 @@ public:
|
||||
return Media::ERR_MEDIA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
virtual uint32_t ModifyImageProperty(uint32_t index, const std::string &key,
|
||||
const std::string &value, const int fd)
|
||||
{
|
||||
return Media::ERR_MEDIA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
virtual uint32_t ModifyImageProperty(uint32_t index, const std::string &key,
|
||||
const std::string &value, uint8_t *data, uint32_t size)
|
||||
{
|
||||
return Media::ERR_MEDIA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
// define multiple subservices for this interface
|
||||
static constexpr uint16_t SERVICE_DEFAULT = 0;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user