Loading libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h +16 −1 Original line number Diff line number Diff line Loading @@ -75,15 +75,27 @@ public: * calling decompressImage() or getCompressedImageParameters(). */ size_t getXMPSize(); /* * Extracts EXIF package and updates the EXIF position / length without decoding the image. */ bool extractEXIF(const void* image, int length); /* * Returns the EXIF data from the image. * This method must be called after extractEXIF() or decompressImage(). */ void* getEXIFPtr(); /* * Returns the decompressed EXIF buffer size. This method must be called only after * calling decompressImage() or getCompressedImageParameters(). * calling decompressImage(), extractEXIF() or getCompressedImageParameters(). */ size_t getEXIFSize(); /* * Returns the position offset of EXIF package * (4 bypes offset to FF sign, the byte after FF E1 XX XX <this byte>), * or -1 if no EXIF exists. * This method must be called after extractEXIF() or decompressImage(). */ int getEXIFPos() { return mExifPos; } /* * Returns the ICC data from the image. */ Loading Loading @@ -122,6 +134,9 @@ private: // Resolution of the decompressed image. size_t mWidth; size_t mHeight; // Position of EXIF package, default value is -1 which means no EXIF package appears. size_t mExifPos; }; } /* namespace android::ultrahdr */ Loading libs/ultrahdr/include/ultrahdr/jpegr.h +9 −7 Original line number Diff line number Diff line Loading @@ -366,22 +366,24 @@ private: * the compressed gain map and optionally the exif package as inputs, and generate the XMP * metadata, and finally append everything in the order of: * SOI, APP2(EXIF) (if EXIF is from outside), APP2(XMP), primary image, gain map * Note that EXIF package is only available for encoding API-0 and API-1. For encoding API-2 and * API-3 this parameter is null, but the primary image in JPEG/R may still have EXIF as long as * the input JPEG has EXIF. * * Note that in the final JPEG/R output, EXIF package will appear if ONLY ONE of the following * conditions is fulfilled: * (1) EXIF package is available from outside input. I.e. pExif != nullptr. * (2) Input JPEG has EXIF. * If both conditions are fulfilled, this method will return ERROR_JPEGR_INVALID_INPUT_TYPE * * @param primary_jpg_image_ptr destination of primary image * @param gainmap_jpg_image_ptr destination of compressed gain map image * @param (nullable) exif EXIF package * @param (nullable) icc ICC package * @param (nullable) pExif EXIF package * @param (nullable) pIcc ICC package * @param icc_size length in bytes of ICC package * @param metadata JPEG/R metadata to encode in XMP of the jpeg * @param dest compressed JPEGR image * @return NO_ERROR if calculation succeeds, error code if error occurs. */ status_t appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr exif, void* icc, jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr pExif, void* pIcc, size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest); /* Loading libs/ultrahdr/jpegdecoderhelper.cpp +76 −14 Original line number Diff line number Diff line Loading @@ -32,12 +32,17 @@ const uint32_t kAPP0Marker = JPEG_APP0; // JFIF const uint32_t kAPP1Marker = JPEG_APP0 + 1; // EXIF, XMP const uint32_t kAPP2Marker = JPEG_APP0 + 2; // ICC const std::string kXmpNameSpace = "http://ns.adobe.com/xap/1.0/"; const std::string kExifIdCode = "Exif"; constexpr uint32_t kICCMarkerHeaderSize = 14; constexpr uint8_t kICCSig[] = { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0', }; constexpr uint8_t kXmpNameSpace[] = { 'h', 't', 't', 'p', ':', '/', '/', 'n', 's', '.', 'a', 'd', 'o', 'b', 'e', '.', 'c', 'o', 'm', '/', 'x', 'a', 'p', '/', '1', '.', '0', '/', '\0', }; constexpr uint8_t kExifIdCode[] = { 'E', 'x', 'i', 'f', '\0', '\0', }; struct jpegr_source_mgr : jpeg_source_mgr { jpegr_source_mgr(const uint8_t* ptr, int len); Loading Loading @@ -146,6 +151,58 @@ size_t JpegDecoderHelper::getDecompressedImageHeight() { return mHeight; } // Here we only handle the first EXIF package, and in theary EXIF (or JFIF) must be the first // in the image file. // We assume that all packages are starting with two bytes marker (eg FF E1 for EXIF package), // two bytes of package length which is stored in marker->original_length, and the real data // which is stored in marker->data. bool JpegDecoderHelper::extractEXIF(const void* image, int length) { jpeg_decompress_struct cinfo; jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length); jpegrerror_mgr myerr; cinfo.err = jpeg_std_error(&myerr.pub); myerr.pub.error_exit = jpegrerror_exit; if (setjmp(myerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); return false; } jpeg_create_decompress(&cinfo); jpeg_save_markers(&cinfo, kAPP0Marker, 0xFFFF); jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF); cinfo.src = &mgr; jpeg_read_header(&cinfo, TRUE); size_t pos = 2; // position after SOI for (jpeg_marker_struct* marker = cinfo.marker_list; marker; marker = marker->next) { pos += 4; pos += marker->original_length; if (marker->marker != kAPP1Marker) { continue; } const unsigned int len = marker->data_length; if (len > sizeof(kExifIdCode) && !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) { mEXIFBuffer.resize(len, 0); memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len); mExifPos = pos - marker->original_length; break; } } jpeg_destroy_decompress(&cinfo); return true; } bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) { bool status = true; jpeg_decompress_struct cinfo; Loading Loading @@ -178,25 +235,31 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) bool exifAppears = false; bool xmpAppears = false; bool iccAppears = false; size_t pos = 2; // position after SOI for (jpeg_marker_struct* marker = cinfo.marker_list; marker && !(exifAppears && xmpAppears && iccAppears); marker = marker->next) { marker && !(exifAppears && xmpAppears && iccAppears); marker = marker->next) { pos += 4; pos += marker->original_length; if (marker->marker != kAPP1Marker && marker->marker != kAPP2Marker) { continue; } const unsigned int len = marker->data_length; if (!xmpAppears && len > kXmpNameSpace.size() && !strncmp(reinterpret_cast<const char*>(marker->data), kXmpNameSpace.c_str(), kXmpNameSpace.size())) { if (!xmpAppears && len > sizeof(kXmpNameSpace) && !memcmp(marker->data, kXmpNameSpace, sizeof(kXmpNameSpace))) { mXMPBuffer.resize(len+1, 0); memcpy(static_cast<void*>(mXMPBuffer.data()), marker->data, len); xmpAppears = true; } else if (!exifAppears && len > kExifIdCode.size() && !strncmp(reinterpret_cast<const char*>(marker->data), kExifIdCode.c_str(), kExifIdCode.size())) { } else if (!exifAppears && len > sizeof(kExifIdCode) && !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) { mEXIFBuffer.resize(len, 0); memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len); exifAppears = true; } else if (!iccAppears && len > sizeof(kICCSig) && mExifPos = pos - marker->original_length; } else if (!iccAppears && len > sizeof(kICCSig) && !memcmp(marker->data, kICCSig, sizeof(kICCSig))) { mICCBuffer.resize(len, 0); memcpy(static_cast<void*>(mICCBuffer.data()), marker->data, len); Loading Loading @@ -325,9 +388,8 @@ bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int leng } const unsigned int len = marker->data_length; if (len >= kExifIdCode.size() && !strncmp(reinterpret_cast<const char*>(marker->data), kExifIdCode.c_str(), kExifIdCode.size())) { if (len >= sizeof(kExifIdCode) && !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) { exifData->resize(len, 0); memcpy(static_cast<void*>(exifData->data()), marker->data, len); exifAppears = true; Loading libs/ultrahdr/jpegr.cpp +68 −12 Original line number Diff line number Diff line Loading @@ -72,6 +72,32 @@ int GetCPUCoreCount() { return cpuCoreCount; } /* * Helper function copies the JPEG image from without EXIF. * * @param pDest destination of the data to be written. * @param pSource source of data being written. * @param exif_pos position of the EXIF package, which is aligned with jpegdecoder.getEXIFPos(). * (4 bytes offset to FF sign, the byte after FF E1 XX XX <this byte>). * @param exif_size exif size without the initial 4 bytes, aligned with jpegdecoder.getEXIFSize(). */ static void copyJpegWithoutExif(jr_compressed_ptr pDest, jr_compressed_ptr pSource, size_t exif_pos, size_t exif_size) { memcpy(pDest, pSource, sizeof(jpegr_compressed_struct)); const size_t exif_offset = 4; //exif_pos has 4 bytes offset to the FF sign pDest->length = pSource->length - exif_size - exif_offset; pDest->data = new uint8_t[pDest->length]; std::unique_ptr<uint8_t[]> dest_data; dest_data.reset(reinterpret_cast<uint8_t*>(pDest->data)); memcpy(pDest->data, pSource->data, exif_pos - exif_offset); memcpy((uint8_t*)pDest->data + exif_pos - exif_offset, (uint8_t*)pSource->data + exif_pos + exif_size, pSource->length - exif_pos - exif_size); } status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_transfer_function hdr_tf, Loading Loading @@ -1152,7 +1178,8 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, // JPEG/R structure: // SOI (ff d8) // // (Optional, only if EXIF package is from outside) // (Optional, if EXIF package is from outside (Encode API-0 API-1), or if EXIF package presents // in the JPEG input (Encode API-2, API-3, API-4)) // APP1 (ff e1) // 2 bytes of length (2 + length of exif package) // EXIF package (this includes the first two bytes representing the package length) Loading @@ -1166,7 +1193,7 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, // 2 bytes of length // MPF // // (Required) primary image (without the first two bytes (SOI), may have other packages) // (Required) primary image (without the first two bytes (SOI) and EXIF, may have other packages) // // SOI (ff d8) // Loading @@ -1183,8 +1210,8 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, // Adobe XMP spec part 3 for XMP marker // ICC v4.3 spec for ICC status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr exif, void* icc, size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr pExif, void* pIcc, size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest) { if (primary_jpg_image_ptr == nullptr || gainmap_jpg_image_ptr == nullptr || metadata == nullptr || dest == nullptr) { Loading Loading @@ -1229,6 +1256,35 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, // same as primary const int xmp_primary_length = 2 + nameSpaceLength + xmp_primary.size(); // Check if EXIF package presents in the JPEG input. // If so, extract and remove the EXIF package. JpegDecoderHelper decoder; if (!decoder.extractEXIF(primary_jpg_image_ptr->data, primary_jpg_image_ptr->length)) { return ERROR_JPEGR_DECODE_ERROR; } jpegr_exif_struct exif_from_jpg; exif_from_jpg.data = nullptr; exif_from_jpg.length = 0; jpegr_compressed_struct new_jpg_image; new_jpg_image.data = nullptr; new_jpg_image.length = 0; if (decoder.getEXIFPos() != 0) { if (pExif != nullptr) { ALOGE("received EXIF from outside while the primary image already contains EXIF"); return ERROR_JPEGR_INVALID_INPUT_TYPE; } copyJpegWithoutExif(&new_jpg_image, primary_jpg_image_ptr, decoder.getEXIFPos(), decoder.getEXIFSize()); exif_from_jpg.data = decoder.getEXIFPtr(); exif_from_jpg.length = decoder.getEXIFSize(); pExif = &exif_from_jpg; } jr_compressed_ptr final_primary_jpg_image_ptr = new_jpg_image.length == 0 ? primary_jpg_image_ptr : &new_jpg_image; int pos = 0; // Begin primary image // Write SOI Loading @@ -1236,15 +1292,15 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos)); // Write EXIF if (exif != nullptr) { const int length = 2 + exif->length; if (pExif != nullptr) { const int length = 2 + pExif->length; const uint8_t lengthH = ((length >> 8) & 0xff); const uint8_t lengthL = (length & 0xff); JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos)); JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); JPEGR_CHECK(Write(dest, exif->data, exif->length, pos)); JPEGR_CHECK(Write(dest, pExif->data, pExif->length, pos)); } // Prepare and write XMP Loading @@ -1261,7 +1317,7 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, } // Write ICC if (icc != nullptr && icc_size > 0) { if (pIcc != nullptr && icc_size > 0) { const int length = icc_size + 2; const uint8_t lengthH = ((length >> 8) & 0xff); const uint8_t lengthL = (length & 0xff); Loading @@ -1269,7 +1325,7 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos)); JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); JPEGR_CHECK(Write(dest, icc, icc_size, pos)); JPEGR_CHECK(Write(dest, pIcc, icc_size, pos)); } // Prepare and write MPF Loading @@ -1277,7 +1333,7 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, const int length = 2 + calculateMpfSize(); const uint8_t lengthH = ((length >> 8) & 0xff); const uint8_t lengthL = (length & 0xff); int primary_image_size = pos + length + primary_jpg_image_ptr->length; int primary_image_size = pos + length + final_primary_jpg_image_ptr->length; // between APP2 + package size + signature // ff e2 00 58 4d 50 46 00 // 2 + 2 + 4 = 8 (bytes) Loading @@ -1293,8 +1349,8 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, } // Write primary image JPEGR_CHECK(Write(dest, (uint8_t*)primary_jpg_image_ptr->data + 2, primary_jpg_image_ptr->length - 2, pos)); JPEGR_CHECK(Write(dest, (uint8_t*)final_primary_jpg_image_ptr->data + 2, final_primary_jpg_image_ptr->length - 2, pos)); // Finish primary image // Begin secondary image (gain map) Loading Loading
libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h +16 −1 Original line number Diff line number Diff line Loading @@ -75,15 +75,27 @@ public: * calling decompressImage() or getCompressedImageParameters(). */ size_t getXMPSize(); /* * Extracts EXIF package and updates the EXIF position / length without decoding the image. */ bool extractEXIF(const void* image, int length); /* * Returns the EXIF data from the image. * This method must be called after extractEXIF() or decompressImage(). */ void* getEXIFPtr(); /* * Returns the decompressed EXIF buffer size. This method must be called only after * calling decompressImage() or getCompressedImageParameters(). * calling decompressImage(), extractEXIF() or getCompressedImageParameters(). */ size_t getEXIFSize(); /* * Returns the position offset of EXIF package * (4 bypes offset to FF sign, the byte after FF E1 XX XX <this byte>), * or -1 if no EXIF exists. * This method must be called after extractEXIF() or decompressImage(). */ int getEXIFPos() { return mExifPos; } /* * Returns the ICC data from the image. */ Loading Loading @@ -122,6 +134,9 @@ private: // Resolution of the decompressed image. size_t mWidth; size_t mHeight; // Position of EXIF package, default value is -1 which means no EXIF package appears. size_t mExifPos; }; } /* namespace android::ultrahdr */ Loading
libs/ultrahdr/include/ultrahdr/jpegr.h +9 −7 Original line number Diff line number Diff line Loading @@ -366,22 +366,24 @@ private: * the compressed gain map and optionally the exif package as inputs, and generate the XMP * metadata, and finally append everything in the order of: * SOI, APP2(EXIF) (if EXIF is from outside), APP2(XMP), primary image, gain map * Note that EXIF package is only available for encoding API-0 and API-1. For encoding API-2 and * API-3 this parameter is null, but the primary image in JPEG/R may still have EXIF as long as * the input JPEG has EXIF. * * Note that in the final JPEG/R output, EXIF package will appear if ONLY ONE of the following * conditions is fulfilled: * (1) EXIF package is available from outside input. I.e. pExif != nullptr. * (2) Input JPEG has EXIF. * If both conditions are fulfilled, this method will return ERROR_JPEGR_INVALID_INPUT_TYPE * * @param primary_jpg_image_ptr destination of primary image * @param gainmap_jpg_image_ptr destination of compressed gain map image * @param (nullable) exif EXIF package * @param (nullable) icc ICC package * @param (nullable) pExif EXIF package * @param (nullable) pIcc ICC package * @param icc_size length in bytes of ICC package * @param metadata JPEG/R metadata to encode in XMP of the jpeg * @param dest compressed JPEGR image * @return NO_ERROR if calculation succeeds, error code if error occurs. */ status_t appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr exif, void* icc, jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr pExif, void* pIcc, size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest); /* Loading
libs/ultrahdr/jpegdecoderhelper.cpp +76 −14 Original line number Diff line number Diff line Loading @@ -32,12 +32,17 @@ const uint32_t kAPP0Marker = JPEG_APP0; // JFIF const uint32_t kAPP1Marker = JPEG_APP0 + 1; // EXIF, XMP const uint32_t kAPP2Marker = JPEG_APP0 + 2; // ICC const std::string kXmpNameSpace = "http://ns.adobe.com/xap/1.0/"; const std::string kExifIdCode = "Exif"; constexpr uint32_t kICCMarkerHeaderSize = 14; constexpr uint8_t kICCSig[] = { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0', }; constexpr uint8_t kXmpNameSpace[] = { 'h', 't', 't', 'p', ':', '/', '/', 'n', 's', '.', 'a', 'd', 'o', 'b', 'e', '.', 'c', 'o', 'm', '/', 'x', 'a', 'p', '/', '1', '.', '0', '/', '\0', }; constexpr uint8_t kExifIdCode[] = { 'E', 'x', 'i', 'f', '\0', '\0', }; struct jpegr_source_mgr : jpeg_source_mgr { jpegr_source_mgr(const uint8_t* ptr, int len); Loading Loading @@ -146,6 +151,58 @@ size_t JpegDecoderHelper::getDecompressedImageHeight() { return mHeight; } // Here we only handle the first EXIF package, and in theary EXIF (or JFIF) must be the first // in the image file. // We assume that all packages are starting with two bytes marker (eg FF E1 for EXIF package), // two bytes of package length which is stored in marker->original_length, and the real data // which is stored in marker->data. bool JpegDecoderHelper::extractEXIF(const void* image, int length) { jpeg_decompress_struct cinfo; jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length); jpegrerror_mgr myerr; cinfo.err = jpeg_std_error(&myerr.pub); myerr.pub.error_exit = jpegrerror_exit; if (setjmp(myerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); return false; } jpeg_create_decompress(&cinfo); jpeg_save_markers(&cinfo, kAPP0Marker, 0xFFFF); jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF); cinfo.src = &mgr; jpeg_read_header(&cinfo, TRUE); size_t pos = 2; // position after SOI for (jpeg_marker_struct* marker = cinfo.marker_list; marker; marker = marker->next) { pos += 4; pos += marker->original_length; if (marker->marker != kAPP1Marker) { continue; } const unsigned int len = marker->data_length; if (len > sizeof(kExifIdCode) && !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) { mEXIFBuffer.resize(len, 0); memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len); mExifPos = pos - marker->original_length; break; } } jpeg_destroy_decompress(&cinfo); return true; } bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) { bool status = true; jpeg_decompress_struct cinfo; Loading Loading @@ -178,25 +235,31 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) bool exifAppears = false; bool xmpAppears = false; bool iccAppears = false; size_t pos = 2; // position after SOI for (jpeg_marker_struct* marker = cinfo.marker_list; marker && !(exifAppears && xmpAppears && iccAppears); marker = marker->next) { marker && !(exifAppears && xmpAppears && iccAppears); marker = marker->next) { pos += 4; pos += marker->original_length; if (marker->marker != kAPP1Marker && marker->marker != kAPP2Marker) { continue; } const unsigned int len = marker->data_length; if (!xmpAppears && len > kXmpNameSpace.size() && !strncmp(reinterpret_cast<const char*>(marker->data), kXmpNameSpace.c_str(), kXmpNameSpace.size())) { if (!xmpAppears && len > sizeof(kXmpNameSpace) && !memcmp(marker->data, kXmpNameSpace, sizeof(kXmpNameSpace))) { mXMPBuffer.resize(len+1, 0); memcpy(static_cast<void*>(mXMPBuffer.data()), marker->data, len); xmpAppears = true; } else if (!exifAppears && len > kExifIdCode.size() && !strncmp(reinterpret_cast<const char*>(marker->data), kExifIdCode.c_str(), kExifIdCode.size())) { } else if (!exifAppears && len > sizeof(kExifIdCode) && !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) { mEXIFBuffer.resize(len, 0); memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len); exifAppears = true; } else if (!iccAppears && len > sizeof(kICCSig) && mExifPos = pos - marker->original_length; } else if (!iccAppears && len > sizeof(kICCSig) && !memcmp(marker->data, kICCSig, sizeof(kICCSig))) { mICCBuffer.resize(len, 0); memcpy(static_cast<void*>(mICCBuffer.data()), marker->data, len); Loading Loading @@ -325,9 +388,8 @@ bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int leng } const unsigned int len = marker->data_length; if (len >= kExifIdCode.size() && !strncmp(reinterpret_cast<const char*>(marker->data), kExifIdCode.c_str(), kExifIdCode.size())) { if (len >= sizeof(kExifIdCode) && !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) { exifData->resize(len, 0); memcpy(static_cast<void*>(exifData->data()), marker->data, len); exifAppears = true; Loading
libs/ultrahdr/jpegr.cpp +68 −12 Original line number Diff line number Diff line Loading @@ -72,6 +72,32 @@ int GetCPUCoreCount() { return cpuCoreCount; } /* * Helper function copies the JPEG image from without EXIF. * * @param pDest destination of the data to be written. * @param pSource source of data being written. * @param exif_pos position of the EXIF package, which is aligned with jpegdecoder.getEXIFPos(). * (4 bytes offset to FF sign, the byte after FF E1 XX XX <this byte>). * @param exif_size exif size without the initial 4 bytes, aligned with jpegdecoder.getEXIFSize(). */ static void copyJpegWithoutExif(jr_compressed_ptr pDest, jr_compressed_ptr pSource, size_t exif_pos, size_t exif_size) { memcpy(pDest, pSource, sizeof(jpegr_compressed_struct)); const size_t exif_offset = 4; //exif_pos has 4 bytes offset to the FF sign pDest->length = pSource->length - exif_size - exif_offset; pDest->data = new uint8_t[pDest->length]; std::unique_ptr<uint8_t[]> dest_data; dest_data.reset(reinterpret_cast<uint8_t*>(pDest->data)); memcpy(pDest->data, pSource->data, exif_pos - exif_offset); memcpy((uint8_t*)pDest->data + exif_pos - exif_offset, (uint8_t*)pSource->data + exif_pos + exif_size, pSource->length - exif_pos - exif_size); } status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_transfer_function hdr_tf, Loading Loading @@ -1152,7 +1178,8 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, // JPEG/R structure: // SOI (ff d8) // // (Optional, only if EXIF package is from outside) // (Optional, if EXIF package is from outside (Encode API-0 API-1), or if EXIF package presents // in the JPEG input (Encode API-2, API-3, API-4)) // APP1 (ff e1) // 2 bytes of length (2 + length of exif package) // EXIF package (this includes the first two bytes representing the package length) Loading @@ -1166,7 +1193,7 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, // 2 bytes of length // MPF // // (Required) primary image (without the first two bytes (SOI), may have other packages) // (Required) primary image (without the first two bytes (SOI) and EXIF, may have other packages) // // SOI (ff d8) // Loading @@ -1183,8 +1210,8 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, // Adobe XMP spec part 3 for XMP marker // ICC v4.3 spec for ICC status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr exif, void* icc, size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr pExif, void* pIcc, size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest) { if (primary_jpg_image_ptr == nullptr || gainmap_jpg_image_ptr == nullptr || metadata == nullptr || dest == nullptr) { Loading Loading @@ -1229,6 +1256,35 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, // same as primary const int xmp_primary_length = 2 + nameSpaceLength + xmp_primary.size(); // Check if EXIF package presents in the JPEG input. // If so, extract and remove the EXIF package. JpegDecoderHelper decoder; if (!decoder.extractEXIF(primary_jpg_image_ptr->data, primary_jpg_image_ptr->length)) { return ERROR_JPEGR_DECODE_ERROR; } jpegr_exif_struct exif_from_jpg; exif_from_jpg.data = nullptr; exif_from_jpg.length = 0; jpegr_compressed_struct new_jpg_image; new_jpg_image.data = nullptr; new_jpg_image.length = 0; if (decoder.getEXIFPos() != 0) { if (pExif != nullptr) { ALOGE("received EXIF from outside while the primary image already contains EXIF"); return ERROR_JPEGR_INVALID_INPUT_TYPE; } copyJpegWithoutExif(&new_jpg_image, primary_jpg_image_ptr, decoder.getEXIFPos(), decoder.getEXIFSize()); exif_from_jpg.data = decoder.getEXIFPtr(); exif_from_jpg.length = decoder.getEXIFSize(); pExif = &exif_from_jpg; } jr_compressed_ptr final_primary_jpg_image_ptr = new_jpg_image.length == 0 ? primary_jpg_image_ptr : &new_jpg_image; int pos = 0; // Begin primary image // Write SOI Loading @@ -1236,15 +1292,15 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos)); // Write EXIF if (exif != nullptr) { const int length = 2 + exif->length; if (pExif != nullptr) { const int length = 2 + pExif->length; const uint8_t lengthH = ((length >> 8) & 0xff); const uint8_t lengthL = (length & 0xff); JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos)); JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); JPEGR_CHECK(Write(dest, exif->data, exif->length, pos)); JPEGR_CHECK(Write(dest, pExif->data, pExif->length, pos)); } // Prepare and write XMP Loading @@ -1261,7 +1317,7 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, } // Write ICC if (icc != nullptr && icc_size > 0) { if (pIcc != nullptr && icc_size > 0) { const int length = icc_size + 2; const uint8_t lengthH = ((length >> 8) & 0xff); const uint8_t lengthL = (length & 0xff); Loading @@ -1269,7 +1325,7 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos)); JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); JPEGR_CHECK(Write(dest, icc, icc_size, pos)); JPEGR_CHECK(Write(dest, pIcc, icc_size, pos)); } // Prepare and write MPF Loading @@ -1277,7 +1333,7 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, const int length = 2 + calculateMpfSize(); const uint8_t lengthH = ((length >> 8) & 0xff); const uint8_t lengthL = (length & 0xff); int primary_image_size = pos + length + primary_jpg_image_ptr->length; int primary_image_size = pos + length + final_primary_jpg_image_ptr->length; // between APP2 + package size + signature // ff e2 00 58 4d 50 46 00 // 2 + 2 + 4 = 8 (bytes) Loading @@ -1293,8 +1349,8 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, } // Write primary image JPEGR_CHECK(Write(dest, (uint8_t*)primary_jpg_image_ptr->data + 2, primary_jpg_image_ptr->length - 2, pos)); JPEGR_CHECK(Write(dest, (uint8_t*)final_primary_jpg_image_ptr->data + 2, final_primary_jpg_image_ptr->length - 2, pos)); // Finish primary image // Begin secondary image (gain map) Loading