diff options
| author | 2023-01-19 13:44:23 -0800 | |
|---|---|---|
| committer | 2023-01-20 19:20:09 +0000 | |
| commit | 0daf5f8e9073c54438d1045d6da70d9bbd7110a0 (patch) | |
| tree | 8b985d150a1b0e0bce637a01647cd9447a168ad7 | |
| parent | 91dfc57ae2b1d18725e6a59111634abe5220d26d (diff) | |
Update EXIF
Some tags contain offsets, and need to be modified after an insertion of
a "JR" tag
Test: manual
Bug: b/264715926
Change-Id: I273c43ca86ee2d089abeae84f65aa37dace1e4c4
| -rw-r--r-- | libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h | 49 | ||||
| -rw-r--r-- | libs/jpegrecoverymap/recoverymaputils.cpp | 118 |
2 files changed, 162 insertions, 5 deletions
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h index f8ae30aade..8b2672fefa 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h @@ -107,7 +107,6 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta std::string generateXmp(int secondary_image_length, jpegr_metadata& metadata); /* - * Helper function * Add J R entry to existing exif, or create a new one with J R entry if it's null. * EXIF syntax / change: * ori: @@ -120,7 +119,7 @@ std::string generateXmp(int secondary_image_length, jpegr_metadata& metadata); * 06 00 - 6 entries * 00 01 - Width Tag * 03 00 - 'Short' type - * 01 00 00 00 - one entry + * 01 00 00 00 - 1 component * 00 05 00 00 - image with 0x500 *-------------------------------------------------------------------------- * new: @@ -133,14 +132,56 @@ std::string generateXmp(int secondary_image_length, jpegr_metadata& metadata); * 07 00 - +1 entry * 4A 52 Custom ('J''R') Tag * 07 00 - Unknown type - * 01 00 00 00 - one element + * 01 00 00 00 - 1 component * 00 00 00 00 - empty data * 00 01 - Width Tag * 03 00 - 'Short' type - * 01 00 00 00 - one entry + * 01 00 00 00 - 1 component * 00 05 00 00 - image with 0x500 */ status_t updateExif(jr_exif_ptr exif, jr_exif_ptr dest); + +/* + * Modify offsets in EXIF in place. + * + * Each tag has the following structure: + * + * 00 01 - Tag + * 03 00 - data format + * 01 00 00 00 - number of components + * 00 05 00 00 - value + * + * The value means offset if + * (1) num_of_components * bytes_per_component > 4 bytes, or + * (2) tag == 0x8769 (ExifOffset). + * In both cases, the method will add EXIF_J_R_ENTRY_LENGTH (12) to the offsets. + */ +void updateExifOffsets(jr_exif_ptr exif, int pos, bool use_big_endian); +void updateExifOffsets(jr_exif_ptr exif, int pos, int num_entry, bool use_big_endian); + +/* + * Read data from the target position and target length in bytes; + */ +int readValue(uint8_t* data, int pos, int length, bool use_big_endian); + +/* + * Returns the length of data format in bytes + * + * ---------------------------------------------------------------------------------------------- + * | value | 1 | 2 | 3 | 4 | + * | format | unsigned byte | ascii strings | unsigned short | unsigned long | + * | bytes/component | 1 | 1 | 2 | 4 | + * ---------------------------------------------------------------------------------------------- + * | value | 5 | 6 | 7 | 8 | + * | format |unsigned rational| signed byte | undefined | signed short | + * | bytes/component | 8 | 1 | 1 | 2 | + * ---------------------------------------------------------------------------------------------- + * | value | 9 | 10 | 11 | 12 | + * | format | signed long | signed rational | single float | double float | + * | bytes/component | 4 | 8 | 4 | 8 | + * ---------------------------------------------------------------------------------------------- + */ +int findFormatLengthInBytes(int data_format); } #endif //ANDROID_JPEGRECOVERYMAP_RECOVERYMAPUTILS_H diff --git a/libs/jpegrecoverymap/recoverymaputils.cpp b/libs/jpegrecoverymap/recoverymaputils.cpp index 78edd27b09..d5ad9a51c4 100644 --- a/libs/jpegrecoverymap/recoverymaputils.cpp +++ b/libs/jpegrecoverymap/recoverymaputils.cpp @@ -22,6 +22,8 @@ #include <image_io/xml/xml_handler.h> #include <image_io/xml/xml_rule.h> +#include <utils/Log.h> + using namespace photos_editing_formats::image_io; using namespace std; @@ -406,7 +408,121 @@ status_t updateExif(jr_exif_ptr exif, jr_exif_ptr dest) { Write(dest, (uint8_t*)exif->data + 16, exif->length - 16, pos); + updateExifOffsets(dest, + 28, // start from the second tag, skip the "JR" tag + num_entry - 1, + use_big_endian); + return NO_ERROR; } -} // namespace android::recoverymap +/* + * Helper function + * Modify offsets in EXIF in place. + */ +void updateExifOffsets(jr_exif_ptr exif, int pos, bool use_big_endian) { + int num_entry = readValue(reinterpret_cast<uint8_t*>(exif->data), pos, 2, use_big_endian); + updateExifOffsets(exif, pos + 2, num_entry, use_big_endian); +} + +void updateExifOffsets(jr_exif_ptr exif, int pos, int num_entry, bool use_big_endian) { + for (int i = 0; i < num_entry; pos += EXIF_J_R_ENTRY_LENGTH, i++) { + int tag = readValue(reinterpret_cast<uint8_t*>(exif->data), pos, 2, use_big_endian); + bool need_to_update_offset = false; + if (tag == 0x8769) { + need_to_update_offset = true; + int sub_ifd_offset = + readValue(reinterpret_cast<uint8_t*>(exif->data), pos + 8, 4, use_big_endian) + + 6 // "Exif\0\0"; + + EXIF_J_R_ENTRY_LENGTH; + updateExifOffsets(exif, sub_ifd_offset, use_big_endian); + } else { + int data_format = + readValue(reinterpret_cast<uint8_t*>(exif->data), pos + 2, 2, use_big_endian); + int num_of_components = + readValue(reinterpret_cast<uint8_t*>(exif->data), pos + 4, 4, use_big_endian); + int data_length = findFormatLengthInBytes(data_format) * num_of_components; + if (data_length > 4) { + need_to_update_offset = true; + } + } + + if (!need_to_update_offset) { + continue; + } + + int offset = readValue(reinterpret_cast<uint8_t*>(exif->data), pos + 8, 4, use_big_endian); + + offset += EXIF_J_R_ENTRY_LENGTH; + + if (use_big_endian) { + reinterpret_cast<uint8_t*>(exif->data)[pos + 11] = offset & 0xff; + reinterpret_cast<uint8_t*>(exif->data)[pos + 10] = (offset >> 8) & 0xff; + reinterpret_cast<uint8_t*>(exif->data)[pos + 9] = (offset >> 16) & 0xff; + reinterpret_cast<uint8_t*>(exif->data)[pos + 8] = (offset >> 24) & 0xff; + } else { + reinterpret_cast<uint8_t*>(exif->data)[pos + 8] = offset & 0xff; + reinterpret_cast<uint8_t*>(exif->data)[pos + 9] = (offset >> 8) & 0xff; + reinterpret_cast<uint8_t*>(exif->data)[pos + 10] = (offset >> 16) & 0xff; + reinterpret_cast<uint8_t*>(exif->data)[pos + 11] = (offset >> 24) & 0xff; + } + } +} + +/* + * Read data from the target position and target length in bytes; + */ +int readValue(uint8_t* data, int pos, int length, bool use_big_endian) { + if (length == 2) { + if (use_big_endian) { + return (data[pos] << 8) | data[pos + 1]; + } else { + return (data[pos + 1] << 8) | data[pos]; + } + } else if (length == 4) { + if (use_big_endian) { + return (data[pos] << 24) | (data[pos + 1] << 16) | (data[pos + 2] << 8) | data[pos + 3]; + } else { + return (data[pos + 3] << 24) | (data[pos + 2] << 16) | (data[pos + 1] << 8) | data[pos]; + } + } else { + // Not support for now. + ALOGE("Error in readValue(): pos=%d, length=%d", pos, length); + return -1; + } +} + +/* + * Helper function + * Returns the length of data format in bytes + */ +int findFormatLengthInBytes(int data_format) { + switch (data_format) { + case 1: // unsigned byte + case 2: // ascii strings + case 6: // signed byte + case 7: // undefined + return 1; + + case 3: // unsigned short + case 8: // signed short + return 2; + + case 4: // unsigned long + case 9: // signed long + case 11: // single float + return 4; + + case 5: // unsigned rational + case 10: // signed rational + case 12: // double float + return 8; + + default: + // should not hit here + ALOGE("Error in findFormatLengthInBytes(): data_format=%d", data_format); + return -1; + } +} + +} // namespace android::recoverymap
\ No newline at end of file |