1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 15:53:03 +04:00

Merge branch 4.x

This commit is contained in:
Alexander Smorkalov
2025-07-30 16:04:47 +03:00
10 changed files with 236 additions and 45 deletions
+57 -23
View File
@@ -247,8 +247,43 @@ bool JpegDecoder::readHeader()
if (state->cinfo.src != 0)
{
jpeg_save_markers(&state->cinfo, APP1, 0xffff);
jpeg_save_markers(&state->cinfo, APP2, 0xffff);
jpeg_read_header( &state->cinfo, TRUE );
const std::streamsize EXIF_HEADER_SIZE = 6; // "Exif\0\0"
const std::streamsize XMP_HEADER_SIZE = 29; // "http://ns.adobe.com/xap/1.0/"
const std::streamsize ICC_HEADER_SIZE = 14; // "ICC_PROFILE\0" + seq/total
for (jpeg_saved_marker_ptr cmarker = state->cinfo.marker_list; cmarker != nullptr; cmarker = cmarker->next)
{
// Handle APP1 marker: could be Exif or XMP
if (cmarker->marker == APP1 && cmarker->data_length > EXIF_HEADER_SIZE)
{
unsigned char* data = cmarker->data;
// Check for Exif data
if (std::memcmp(data, "Exif\0\0", EXIF_HEADER_SIZE) == 0)
{
m_exif.parseExif(data + EXIF_HEADER_SIZE, cmarker->data_length - EXIF_HEADER_SIZE);
}
// Check for XMP metadata
else if (m_read_options && cmarker->data_length >= XMP_HEADER_SIZE &&
std::memcmp(data, "http://ns.adobe.com/xap/1.0/", XMP_HEADER_SIZE) == 0)
{
std::vector<uchar>& xmp = m_metadata[IMAGE_METADATA_XMP];
xmp.insert(xmp.end(), data, data + cmarker->data_length);
}
}
// Handle APP2 marker: typically contains ICC profile data
if (m_read_options && cmarker->marker == APP2 && cmarker->data_length > ICC_HEADER_SIZE)
{
const unsigned char* data = cmarker->data;
std::vector<uchar>& iccp = m_metadata[IMAGE_METADATA_ICCP];
iccp.insert(iccp.end(), data + ICC_HEADER_SIZE, data + cmarker->data_length);
}
}
state->cinfo.scale_num=1;
state->cinfo.scale_denom = m_scale_denom;
m_scale_denom=1; // trick! to know which decoder used scale_denom see imread_
@@ -469,29 +504,6 @@ bool JpegDecoder::readData( Mat& img )
}
}
// Check for Exif marker APP1
jpeg_saved_marker_ptr exif_marker = NULL;
jpeg_saved_marker_ptr cmarker = cinfo->marker_list;
while( cmarker && exif_marker == NULL )
{
if (cmarker->marker == APP1)
exif_marker = cmarker;
cmarker = cmarker->next;
}
// Parse Exif data
if( exif_marker )
{
const std::streamsize offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header
if (exif_marker->data_length > offsetToTiffHeader)
{
m_exif.parseExif(exif_marker->data + offsetToTiffHeader, exif_marker->data_length - offsetToTiffHeader);
}
}
jpeg_start_decompress( cinfo );
if( doDirectRead)
@@ -602,6 +614,8 @@ JpegEncoder::JpegEncoder()
m_buf_supported = true;
m_support_metadata.assign((size_t)IMAGE_METADATA_MAX + 1, false);
m_support_metadata[(size_t)IMAGE_METADATA_EXIF] = true;
m_support_metadata[(size_t)IMAGE_METADATA_XMP] = true;
m_support_metadata[(size_t)IMAGE_METADATA_ICCP] = true;
}
@@ -831,6 +845,26 @@ bool JpegEncoder::write( const Mat& img, const std::vector<int>& params )
memcpy(data + app1_exif_prefix_size, metadata_exif.data(), exif_size);
jpeg_write_marker(&cinfo, JPEG_APP0 + 1, data, (unsigned)data_size);
}
const std::vector<uchar>& metadata_xmp = m_metadata[IMAGE_METADATA_XMP];
size_t xmp_size = metadata_xmp.size();
if (xmp_size > 0u) {
jpeg_write_marker(&cinfo, JPEG_APP0 + 1, metadata_xmp.data(), (unsigned)xmp_size);
}
const std::vector<uchar>& metadata_iccp = m_metadata[IMAGE_METADATA_ICCP];
size_t iccp_size = metadata_iccp.size();
if (iccp_size > 0u) {
const char app1_iccp_prefix[] = {'I','C','C','_','P','R','O','F','I','L','E','\0','\1','\1'};
size_t app1_iccp_prefix_size = sizeof(app1_iccp_prefix);
size_t data_size = iccp_size + app1_iccp_prefix_size;
std::vector<uchar> metadata_app1(data_size);
uchar* data = metadata_app1.data();
memcpy(data, app1_iccp_prefix, app1_iccp_prefix_size);
memcpy(data + app1_iccp_prefix_size, metadata_iccp.data(), iccp_size);
jpeg_write_marker(&cinfo, JPEG_APP0 + 2, data, (unsigned)data_size);
}
}
if( doDirectWrite )
+13 -1
View File
@@ -648,7 +648,11 @@ bool PngDecoder::readData( Mat& img )
png_charp icc_name;
int compression_type;
#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10500)
png_bytep icc_profile;
#else
png_charp icc_profile;
#endif
png_uint_32 icc_length;
if (png_get_iCCP(m_png_ptr, m_info_ptr, &icc_name, &compression_type, &icc_profile, &icc_length)) {
@@ -1028,7 +1032,11 @@ bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
if (!m_metadata.empty()) {
std::vector<uchar>& exif = m_metadata[IMAGE_METADATA_EXIF];
if (!exif.empty()) {
#ifdef PNG_eXIf_SUPPORTED
png_set_eXIf_1(png_ptr, info_ptr, static_cast<png_uint_32>(exif.size()), exif.data());
#else
CV_LOG_WARNING(NULL, "Libpng is too old and does not support EXIF.");
#endif
}
std::vector<uchar>& xmp = m_metadata[IMAGE_METADATA_XMP];
@@ -1045,7 +1053,7 @@ bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
std::vector<uchar> iccp = m_metadata[IMAGE_METADATA_ICCP];
if (!iccp.empty()) {
// PNG standard requires a profile name (null-terminated, max 79 characters, printable Latin-1)
const char* iccp_profile_name = "ICC Profile";
char iccp_profile_name[] = "ICC Profile";
// Compression type must be 0 (deflate) as per libpng docs
int compression_type = PNG_COMPRESSION_TYPE_BASE;
@@ -1056,7 +1064,11 @@ bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
png_set_iCCP(png_ptr, info_ptr,
iccp_profile_name,
compression_type,
#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10500)
reinterpret_cast<png_const_bytep>(iccp.data()),
#else
reinterpret_cast<png_charp>(iccp.data()),
#endif
static_cast<png_uint_32>(iccp.size()));
}
}