Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions lib/src/jpegdecoderhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,39 @@ static void jpeg_extract_marker_payload(const j_decompress_ptr cinfo, const uint
}
}

// Locate the selected payload in the original JPEG stream. The saved-marker list is incomplete
// by design and is not a reliable source of byte offsets when other segments precede EXIF.
static long find_marker_payload_offset(const uint8_t* image, size_t length, uint32_t marker_code,
const uint8_t* payload, size_t payload_length) {
if (image == nullptr || payload == nullptr || length < 2 || image[0] != 0xff ||
image[1] != 0xd8) {
return -1;
}

size_t pos = 2;
while (pos + 1 < length) {
if (image[pos] != 0xff) return -1;
while (pos < length && image[pos] == 0xff) ++pos;
if (pos >= length) return -1;

const uint8_t marker = image[pos++];
if (marker == 0xd9 || marker == 0xda) return -1;
if (marker == 0xd8 || marker == 0x01 || (marker >= 0xd0 && marker <= 0xd7)) continue;
if (pos + 2 > length) return -1;

const size_t segment_length = (static_cast<size_t>(image[pos]) << 8) | image[pos + 1];
if (segment_length < 2 || segment_length > length - pos) return -1;
const size_t segment_payload_length = segment_length - 2;
const size_t segment_payload_offset = pos + 2;
if (marker == marker_code && segment_payload_length == payload_length &&
memcmp(image + segment_payload_offset, payload, payload_length) == 0) {
return static_cast<long>(segment_payload_offset);
}
pos += segment_length;
}
return -1;
}

static uhdr_img_fmt_t getOutputSamplingFormat(const j_decompress_ptr cinfo) {
if (cinfo->num_components == 1)
return UHDR_IMG_FMT_8bppYCbCr400;
Expand Down Expand Up @@ -238,6 +271,19 @@ uhdr_error_info_t JpegDecoderHelper::decode(const void* image, size_t length, de
jpeg_extract_marker_payload(&cinfo, kAPP1Marker, kExifIdCode,
sizeof kExifIdCode / sizeof kExifIdCode[0], mEXIFBuffer,
mExifPayLoadOffset);
if (mExifPayLoadOffset >= 0) {
mExifPayLoadOffset = find_marker_payload_offset(
static_cast<const uint8_t*>(image), length, kAPP1Marker, mEXIFBuffer.data(),
mEXIFBuffer.size());
if (mExifPayLoadOffset < 0) {
status.error_code = UHDR_CODEC_ERROR;
status.has_detail = 1;
snprintf(status.detail, sizeof status.detail,
"failed to locate extracted EXIF payload in JPEG source");
jpeg_destroy_decompress(&cinfo);
return status;
}
}
jpeg_extract_marker_payload(&cinfo, kAPP2Marker, kICCSig, sizeof kICCSig / sizeof kICCSig[0],
mICCBuffer, payloadOffset);
jpeg_extract_marker_payload(&cinfo, kAPP2Marker, kIsoMetadataNameSpace,
Expand Down
28 changes: 24 additions & 4 deletions lib/src/jpegr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,14 @@ UltraHdr::UltraHdr(void* uhdrGLESCtxt, int mapDimensionScaleFactor, int mapCompr
* (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(uhdr_compressed_image_t* pDest, uhdr_compressed_image_t* pSource,
static bool copyJpegWithoutExif(uhdr_compressed_image_t* pDest, uhdr_compressed_image_t* pSource,
size_t exif_pos, size_t exif_size) {
const size_t exif_offset = 4; // exif_pos has 4 bytes offset to the FF sign
if (pDest == nullptr || pSource == nullptr || pSource->data == nullptr || exif_pos < exif_offset ||
exif_pos > pSource->data_sz || exif_size > pSource->data_sz - exif_pos ||
exif_offset > pSource->data_sz - exif_size) {
return false;
}
pDest->data_sz = pSource->data_sz - exif_size - exif_offset;
pDest->data = new uint8_t[pDest->data_sz];
pDest->capacity = pDest->data_sz;
Expand All @@ -173,6 +178,7 @@ static void copyJpegWithoutExif(uhdr_compressed_image_t* pDest, uhdr_compressed_
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->data_sz - exif_pos - exif_size);
return true;
}

/* Encode API-0 */
Expand Down Expand Up @@ -1197,8 +1203,15 @@ uhdr_error_info_t JpegR::appendGainMap(uhdr_compressed_image_t* sdr_intent_compr
"contains exif, unsure which one to use");
return status;
}
copyJpegWithoutExif(&new_jpg_image, sdr_intent_compressed, decoder.getEXIFPos(),
decoder.getEXIFSize());
if (!copyJpegWithoutExif(&new_jpg_image, sdr_intent_compressed, decoder.getEXIFPos(),
decoder.getEXIFSize())) {
uhdr_error_info_t status;
status.error_code = UHDR_CODEC_INVALID_PARAM;
status.has_detail = 1;
snprintf(status.detail, sizeof status.detail,
"invalid EXIF position or size in compressed base image");
return status;
}
dest_data.reset(reinterpret_cast<uint8_t*>(new_jpg_image.data));
exif_from_jpg.data = decoder.getEXIFPtr();
exif_from_jpg.data_sz = decoder.getEXIFSize();
Expand Down Expand Up @@ -1316,11 +1329,18 @@ uhdr_error_info_t JpegR::appendGainMap(uhdr_compressed_image_t* sdr_intent_compr
if (base_data[base_pos] != 0xFF) break;
if (base_pos + 1 >= base_size) break; // guard against truncated data
uint8_t marker = base_data[base_pos+1];
if (marker == 0xFF) {
// JPEG permits repeated 0xFF fill bytes before a marker code. Keep the final
// 0xFF as the marker prefix so the normal segment parsing below can consume it.
while (base_pos + 2 < base_size && base_data[base_pos+1] == 0xFF) ++base_pos;
if (base_pos + 1 >= base_size || base_data[base_pos+1] == 0xFF) break;
marker = base_data[base_pos+1];
}
if (marker == 0xDA) { // SOS - stop here, MPF goes before this
sos_offset = base_pos;
break;
}
if (marker == 0x00 || marker == 0xFF) { base_pos += 2; continue; }
if (marker == 0x00) { base_pos += 2; continue; }
if (marker >= 0xD0 && marker <= 0xD7) { base_pos += 2; continue; }
if (marker == 0xD9) break; // EOI - shouldn't happen here but guard
// OOB check: need at least 2 bytes for the segment length field
Expand Down
Loading
Loading