diff --git a/ui/image/image_prepare.cpp b/ui/image/image_prepare.cpp index 164db6b..69bf818 100644 --- a/ui/image/image_prepare.cpp +++ b/ui/image/image_prepare.cpp @@ -1293,4 +1293,88 @@ bool IsProgressiveJpeg(const QByteArray &bytes) { return (info.progressive_mode > 0); } +QByteArray MakeProgressiveJpeg(const QByteArray &bytes) { + struct jpeg_decompress_struct srcinfo; + struct jpeg_compress_struct dstinfo; + struct my_error_mgr jerr; + + srcinfo.err = jpeg_std_error(&jerr); + dstinfo.err = jpeg_std_error(&jerr); + jerr.error_exit = my_error_exit; + if (setjmp(jerr.setjmp_buffer)) { + return {}; + } + + jpeg_create_decompress(&srcinfo); + const auto srcguard = gsl::finally([&] { + jpeg_abort_decompress(&srcinfo); + jpeg_destroy_decompress(&srcinfo); + }); + + jpeg_create_compress(&dstinfo); + const auto dstguard = gsl::finally([&] { + jpeg_abort_compress(&dstinfo); + jpeg_destroy_compress(&dstinfo); + }); + + jpeg_mem_src( + &srcinfo, + reinterpret_cast(bytes.data()), + bytes.size()); + + jpeg_save_markers(&srcinfo, JPEG_COM, 0xFFFF); + for (int m = 0; m < 16; m++) { + jpeg_save_markers(&srcinfo, JPEG_APP0 + m, 0xFFFF); + } + + jpeg_read_header(&srcinfo, true); + const auto coefArrays = jpeg_read_coefficients(&srcinfo); + jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + jpeg_simple_progression(&dstinfo); + + unsigned char* outbuffer = nullptr; + long unsigned int outsize = 0; + jpeg_mem_dest(&dstinfo, &outbuffer, &outsize); + const auto outbufferGuard = gsl::finally([&] { + free(outbuffer); + }); + + jpeg_write_coefficients(&dstinfo, coefArrays); + + for (jpeg_saved_marker_ptr marker = srcinfo.marker_list + ; marker != nullptr + ; marker = marker->next) { + if (dstinfo.write_JFIF_header + && marker->marker == JPEG_APP0 + && marker->data_length >= 5 + && marker->data[0] == 0x4A + && marker->data[1] == 0x46 + && marker->data[2] == 0x49 + && marker->data[3] == 0x46 + && marker->data[4] == 0) + continue; // reject duplicate JFIF + if (dstinfo.write_Adobe_marker + && marker->marker == JPEG_APP0 + 14 + && marker->data_length >= 5 + && marker->data[0] == 0x41 + && marker->data[1] == 0x64 + && marker->data[2] == 0x6F + && marker->data[3] == 0x62 + && marker->data[4] == 0x65) + continue; // reject duplicate Adobe + jpeg_write_marker( + &dstinfo, + marker->marker, + marker->data, + marker->data_length); + } + + jpeg_finish_compress(&dstinfo); + jpeg_finish_decompress(&srcinfo); + + return QByteArray::fromRawData( + reinterpret_cast(outbuffer), + outsize); +} + } // namespace Images diff --git a/ui/image/image_prepare.h b/ui/image/image_prepare.h index 3ede8dc..da0b7cb 100644 --- a/ui/image/image_prepare.h +++ b/ui/image/image_prepare.h @@ -204,5 +204,6 @@ struct PrepareArgs { } [[nodiscard]] bool IsProgressiveJpeg(const QByteArray &bytes); +[[nodiscard]] QByteArray MakeProgressiveJpeg(const QByteArray &bytes); } // namespace Images