JPEGR Decoder. Inital implementation
* Implements JPEGR Decoding
* Doesn't implement XMP data parsing
* Implements retrieval of image data
Bug: b/252835416
Test: build
Change-Id: I62c7c323842b8d87866c43e85c1d7238e5b9b0d5
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
index ad41839..b685294 100644
--- a/libs/jpegrecoverymap/recoverymap.cpp
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -18,15 +18,23 @@
#include <jpegrecoverymap/jpegencoder.h>
#include <jpegrecoverymap/jpegdecoder.h>
#include <jpegrecoverymap/recoverymapmath.h>
+#include <jpegrecoverymap/recoverymaputils.h>
#include <image_io/jpeg/jpeg_marker.h>
#include <image_io/xml/xml_writer.h>
+#include <image_io/jpeg/jpeg_info.h>
+#include <image_io/jpeg/jpeg_scanner.h>
+#include <image_io/jpeg/jpeg_info_builder.h>
+#include <image_io/base/data_segment_data_source.h>
+#include <utils/Log.h>
#include <memory>
#include <sstream>
#include <string>
+#include <cmath>
using namespace std;
+using namespace photos_editing_formats::image_io;
namespace android::recoverymap {
@@ -234,17 +242,41 @@
return NO_ERROR;
}
+status_t RecoveryMap::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image,
+ jr_info_ptr jpegr_info) {
+ if (compressed_jpegr_image == nullptr || jpegr_info == nullptr) {
+ return ERROR_JPEGR_INVALID_NULL_PTR;
+ }
+
+ jpegr_compressed_struct primary_image, recovery_map;
+ JPEGR_CHECK(extractPrimaryImageAndRecoveryMap(compressed_jpegr_image,
+ &primary_image, &recovery_map));
+
+ JpegDecoder jpeg_decoder;
+ if (!jpeg_decoder.getCompressedImageParameters(primary_image.data, primary_image.length,
+ &jpegr_info->width, &jpegr_info->height,
+ jpegr_info->iccData, jpegr_info->exifData)) {
+ return ERROR_JPEGR_DECODE_ERROR;
+ }
+
+ return NO_ERROR;
+}
+
+
status_t RecoveryMap::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
jr_uncompressed_ptr dest,
- jr_exif_ptr /* exif */,
- bool /* request_sdr */) {
+ jr_exif_ptr exif,
+ bool request_sdr) {
if (compressed_jpegr_image == nullptr || dest == nullptr) {
return ERROR_JPEGR_INVALID_NULL_PTR;
}
+ // TODO: fill EXIF data
+ (void) exif;
+
jpegr_compressed_struct compressed_map;
jpegr_metadata metadata;
- JPEGR_CHECK(extractRecoveryMap(compressed_jpegr_image, &compressed_map, &metadata));
+ JPEGR_CHECK(extractRecoveryMap(compressed_jpegr_image, &compressed_map));
jpegr_uncompressed_struct map;
JPEGR_CHECK(decompressRecoveryMap(&compressed_map, &map));
@@ -259,7 +291,19 @@
uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth();
uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight();
- JPEGR_CHECK(applyRecoveryMap(&uncompressed_yuv_420_image, &map, &metadata, dest));
+ if (!getMetadataFromXMP(static_cast<uint8_t*>(jpeg_decoder.getXMPPtr()),
+ jpeg_decoder.getXMPSize(), &metadata)) {
+ return ERROR_JPEGR_DECODE_ERROR;
+ }
+
+ if (request_sdr) {
+ memcpy(dest->data, uncompressed_yuv_420_image.data,
+ uncompressed_yuv_420_image.width*uncompressed_yuv_420_image.height *3 / 2);
+ dest->width = uncompressed_yuv_420_image.width;
+ dest->height = uncompressed_yuv_420_image.height;
+ } else {
+ JPEGR_CHECK(applyRecoveryMap(&uncompressed_yuv_420_image, &map, &metadata, dest));
+ }
return NO_ERROR;
}
@@ -467,19 +511,66 @@
reinterpret_cast<uint32_t*>(dest->data)[pixel_idx] = rgba1010102;
}
}
+ return NO_ERROR;
+}
+
+status_t RecoveryMap::extractPrimaryImageAndRecoveryMap(jr_compressed_ptr compressed_jpegr_image,
+ jr_compressed_ptr primary_image,
+ jr_compressed_ptr recovery_map) {
+ if (compressed_jpegr_image == nullptr) {
+ return ERROR_JPEGR_INVALID_NULL_PTR;
+ }
+
+ MessageHandler msg_handler;
+ std::shared_ptr<DataSegment> seg =
+ DataSegment::Create(DataRange(0, compressed_jpegr_image->length),
+ static_cast<const uint8_t*>(compressed_jpegr_image->data),
+ DataSegment::BufferDispositionPolicy::kDontDelete);
+ DataSegmentDataSource data_source(seg);
+ JpegInfoBuilder jpeg_info_builder;
+ jpeg_info_builder.SetImageLimit(2);
+ JpegScanner jpeg_scanner(&msg_handler);
+ jpeg_scanner.Run(&data_source, &jpeg_info_builder);
+ data_source.Reset();
+
+ if (jpeg_scanner.HasError()) {
+ return ERROR_JPEGR_INVALID_INPUT_TYPE;
+ }
+
+ const auto& jpeg_info = jpeg_info_builder.GetInfo();
+ const auto& image_ranges = jpeg_info.GetImageRanges();
+ if (image_ranges.empty()) {
+ return ERROR_JPEGR_INVALID_INPUT_TYPE;
+ }
+
+ if (image_ranges.size() != 2) {
+ // Must be 2 JPEG Images
+ return ERROR_JPEGR_INVALID_INPUT_TYPE;
+ }
+
+ if (primary_image != nullptr) {
+ primary_image->data = static_cast<uint8_t*>(compressed_jpegr_image->data) +
+ image_ranges[0].GetBegin();
+ primary_image->length = image_ranges[0].GetLength();
+ }
+
+ if (recovery_map != nullptr) {
+ recovery_map->data = static_cast<uint8_t*>(compressed_jpegr_image->data) +
+ image_ranges[1].GetBegin();
+ recovery_map->length = image_ranges[1].GetLength();
+ }
return NO_ERROR;
}
+
status_t RecoveryMap::extractRecoveryMap(jr_compressed_ptr compressed_jpegr_image,
- jr_compressed_ptr dest,
- jr_metadata_ptr metadata) {
- if (compressed_jpegr_image == nullptr || dest == nullptr || metadata == nullptr) {
+ jr_compressed_ptr dest) {
+ if (compressed_jpegr_image == nullptr || dest == nullptr) {
return ERROR_JPEGR_INVALID_NULL_PTR;
}
- // TBD
- return NO_ERROR;
+ return extractPrimaryImageAndRecoveryMap(compressed_jpegr_image, nullptr, dest);
}
status_t RecoveryMap::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image,