From 81e216f1cede22d30573233c36039716cc438b33 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 9 Mar 2022 17:37:02 +0400 Subject: [PATCH] Allow checking if JPEG bytes are a progressive jpeg. --- CMakeLists.txt | 1 + ui/image/image_prepare.cpp | 50 +++++++++++++++++++++++++++++++++----- ui/image/image_prepare.h | 2 ++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 99ec041..4c6651f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,4 +278,5 @@ PUBLIC desktop-app::lib_base PRIVATE desktop-app::external_zlib + desktop-app::external_jpeg ) diff --git a/ui/image/image_prepare.cpp b/ui/image/image_prepare.cpp index 83900f5..ef13147 100644 --- a/ui/image/image_prepare.cpp +++ b/ui/image/image_prepare.cpp @@ -22,6 +22,21 @@ #include #include +#include + +struct my_error_mgr : public jpeg_error_mgr { + jmp_buf setjmp_buffer; +}; + +extern "C" { + +static void my_error_exit(j_common_ptr cinfo) { + my_error_mgr* myerr = (my_error_mgr*)cinfo->err; + longjmp(myerr->setjmp_buffer, 1); +} + +} // extern "C" + namespace Images { namespace { @@ -420,12 +435,12 @@ std::array PrepareCorners( return {}; } auto result = ReadResult(); + result.format = reader.format().toLower(); + result.animated = reader.supportsAnimation() + && (reader.imageCount() > 1); if (!reader.read(&result.image) || result.image.isNull()) { return {}; } - result.animated = reader.supportsAnimation() - && (reader.imageCount() > 1); - result.format = reader.format().toLower(); return result; } @@ -459,9 +474,7 @@ ReadResult Read(ReadArgs &&args) { Qt::KeepAspectRatio, Qt::SmoothTransformation); } - if (args.forceOpaque - && result.format != qstr("jpg") - && result.format != qstr("jpeg")) { + if (args.forceOpaque && result.format != qstr("jpeg")) { result.image = Opaque(std::move(result.image)); } return result; @@ -1221,4 +1234,29 @@ QImage Prepare(QImage image, int w, int h, const PrepareArgs &args) { return image; } +bool IsProgressiveJpeg(const QByteArray &bytes) { + struct jpeg_decompress_struct info; + struct my_error_mgr jerr; + + info.err = jpeg_std_error(&jerr); + jerr.error_exit = my_error_exit; + if (setjmp(jerr.setjmp_buffer)) { + return false; + } + + jpeg_create_decompress(&info); + jpeg_mem_src( + &info, + reinterpret_cast(bytes.data()), + bytes.size()); + if (jpeg_read_header(&info, TRUE) != 1) { + return false; + } + + const auto result = (info.progressive_mode > 0); + jpeg_destroy_decompress(&info); + + return result; +} + } // namespace Images diff --git a/ui/image/image_prepare.h b/ui/image/image_prepare.h index 3535c79..2efb6a7 100644 --- a/ui/image/image_prepare.h +++ b/ui/image/image_prepare.h @@ -153,4 +153,6 @@ struct PrepareArgs { return Prepare(std::move(image), size.width(), size.height(), args); } +[[nodiscard]] bool IsProgressiveJpeg(const QByteArray &bytes); + } // namespace Images