From a144481e6cedea3af2546d3e1a36c5cd4d2e67a9 Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Sat, 8 Feb 2025 00:13:12 -0500 Subject: [PATCH] LibGfx/PNG: Read the cICP chunk --- Libraries/LibGfx/ImageFormats/PNGLoader.cpp | 30 ++++++++++++++---- Libraries/LibGfx/ImageFormats/PNGLoader.h | 1 + .../png/apng/apng-lime-rectangle-ref.html | 8 +++++ .../wpt-import/png/apng/support/lime.png | Bin 0 -> 179 bytes .../wpt-import/png/cICP-wins-ref.html | 17 ++++++++++ .../wpt-import/png/support/srgb_green.png | Bin 0 -> 192 bytes .../png/apng/fDAT-inherits-cICP.html | 22 +++++++++++++ .../input/wpt-import/png/apng/support/062.png | Bin 0 -> 445 bytes .../Ref/input/wpt-import/png/cICP-wins.html | 22 +++++++++++++ .../wpt-import/png/support/cICP-and-iCCP.png | Bin 0 -> 2745 bytes 10 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 Tests/LibWeb/Ref/expected/wpt-import/png/apng/apng-lime-rectangle-ref.html create mode 100644 Tests/LibWeb/Ref/expected/wpt-import/png/apng/support/lime.png create mode 100644 Tests/LibWeb/Ref/expected/wpt-import/png/cICP-wins-ref.html create mode 100644 Tests/LibWeb/Ref/expected/wpt-import/png/support/srgb_green.png create mode 100644 Tests/LibWeb/Ref/input/wpt-import/png/apng/fDAT-inherits-cICP.html create mode 100644 Tests/LibWeb/Ref/input/wpt-import/png/apng/support/062.png create mode 100644 Tests/LibWeb/Ref/input/wpt-import/png/cICP-wins.html create mode 100644 Tests/LibWeb/Ref/input/wpt-import/png/support/cICP-and-iCCP.png diff --git a/Libraries/LibGfx/ImageFormats/PNGLoader.cpp b/Libraries/LibGfx/ImageFormats/PNGLoader.cpp index ef796a793b4..6f844027099 100644 --- a/Libraries/LibGfx/ImageFormats/PNGLoader.cpp +++ b/Libraries/LibGfx/ImageFormats/PNGLoader.cpp @@ -30,6 +30,7 @@ struct PNGLoadingContext { u32 frame_count { 0 }; u32 loop_count { 0 }; Vector frame_descriptors; + Optional cicp; Optional icc_profile; OwnPtr exif_metadata; @@ -111,6 +112,11 @@ ErrorOr PNGImageDecoderPlugin::frame(size_t index, Optiona return m_context->frame_descriptors[index]; } +ErrorOr> PNGImageDecoderPlugin::cicp() +{ + return m_context->cicp; +} + ErrorOr> PNGImageDecoderPlugin::icc_data() { if (m_context->icc_profile.has_value()) @@ -187,12 +193,24 @@ ErrorOr PNGImageDecoderPlugin::initialize() png_set_filler(m_context->png_ptr, 0xFF, PNG_FILLER_AFTER); png_set_bgr(m_context->png_ptr); - char* profile_name = nullptr; - int compression_type = 0; - u8* profile_data = nullptr; - u32 profile_len = 0; - if (png_get_iCCP(m_context->png_ptr, m_context->info_ptr, &profile_name, &compression_type, &profile_data, &profile_len)) - m_context->icc_profile = TRY(ByteBuffer::copy(profile_data, profile_len)); + png_byte color_primaries { 0 }; + png_byte transfer_function { 0 }; + png_byte matrix_coefficients { 0 }; + png_byte video_full_range_flag { 0 }; + if (png_get_cICP(m_context->png_ptr, m_context->info_ptr, &color_primaries, &transfer_function, &matrix_coefficients, &video_full_range_flag)) { + Media::ColorPrimaries cp { color_primaries }; + Media::TransferCharacteristics tc { transfer_function }; + Media::MatrixCoefficients mc { matrix_coefficients }; + Media::VideoFullRangeFlag rf { video_full_range_flag }; + m_context->cicp = Media::CodingIndependentCodePoints { cp, tc, mc, rf }; + } else { + char* profile_name = nullptr; + int compression_type = 0; + u8* profile_data = nullptr; + u32 profile_len = 0; + if (png_get_iCCP(m_context->png_ptr, m_context->info_ptr, &profile_name, &compression_type, &profile_data, &profile_len)) + m_context->icc_profile = TRY(ByteBuffer::copy(profile_data, profile_len)); + } u8* exif_data = nullptr; u32 exif_length = 0; diff --git a/Libraries/LibGfx/ImageFormats/PNGLoader.h b/Libraries/LibGfx/ImageFormats/PNGLoader.h index 7f20b6535dc..37782d8a97d 100644 --- a/Libraries/LibGfx/ImageFormats/PNGLoader.h +++ b/Libraries/LibGfx/ImageFormats/PNGLoader.h @@ -27,6 +27,7 @@ public: virtual size_t first_animated_frame_index() override; virtual ErrorOr frame(size_t index, Optional ideal_size = {}) override; virtual Optional metadata() override; + virtual ErrorOr> cicp() override; virtual ErrorOr> icc_data() override; private: diff --git a/Tests/LibWeb/Ref/expected/wpt-import/png/apng/apng-lime-rectangle-ref.html b/Tests/LibWeb/Ref/expected/wpt-import/png/apng/apng-lime-rectangle-ref.html new file mode 100644 index 00000000000..6cc29d40d42 --- /dev/null +++ b/Tests/LibWeb/Ref/expected/wpt-import/png/apng/apng-lime-rectangle-ref.html @@ -0,0 +1,8 @@ + + +PNG Third Edition: animated PNG + + +

Test passes if you see a lime green rectangle, and no red.

+
+ diff --git a/Tests/LibWeb/Ref/expected/wpt-import/png/apng/support/lime.png b/Tests/LibWeb/Ref/expected/wpt-import/png/apng/support/lime.png new file mode 100644 index 0000000000000000000000000000000000000000..9bd36328110f13f87a1fe85bfb8dc99495edfcef GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0y~yU}#`qU~u4IVqjp1-SR?%fq{V~-O<;Pfnj4m_n$;o z1_p*KPZ!6Kid%0l8Zt64a2!~0(|*gb4~<+t(*14?42&ECR3ol1?%;4>G-KVhk%57M N!PC{xWt~$(698` + + +PNG Third Edition: Coding Independent Code Points + + + +

Test passes if you see a green rectangle, and no red.

+
+ + \ No newline at end of file diff --git a/Tests/LibWeb/Ref/expected/wpt-import/png/support/srgb_green.png b/Tests/LibWeb/Ref/expected/wpt-import/png/support/srgb_green.png new file mode 100644 index 0000000000000000000000000000000000000000..a978f32536c3be6121e947f0312deaaeb7860bfc GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0y~yU}#`qU~u4IV_;yobgjOgfq|jj)5S5QV$R!33waqB zI9N8y&pn&SDa0cBRb6kTN&j5-1O}c4Mgs=60}K)j%w%#7R1(nNz{@<#;?beAFO|15 QFfcH9y85}Sb4q9e0J9e=t^fc4 literal 0 HcmV?d00001 diff --git a/Tests/LibWeb/Ref/input/wpt-import/png/apng/fDAT-inherits-cICP.html b/Tests/LibWeb/Ref/input/wpt-import/png/apng/fDAT-inherits-cICP.html new file mode 100644 index 00000000000..6f6466f56de --- /dev/null +++ b/Tests/LibWeb/Ref/input/wpt-import/png/apng/fDAT-inherits-cICP.html @@ -0,0 +1,22 @@ + + + +PNG Third Edition: animated PNG, fdAT inherits colorspace from cICP + + + + + + + + + +

Test passes if you see a lime green rectangle, and no red.

+ +
+ diff --git a/Tests/LibWeb/Ref/input/wpt-import/png/apng/support/062.png b/Tests/LibWeb/Ref/input/wpt-import/png/apng/support/062.png new file mode 100644 index 0000000000000000000000000000000000000000..e50902adb9fe038676cd5f45eb6ecc9468dbb2b0 GIT binary patch literal 445 zcmeAS@N?(olHy`uVBq!ia0y~yU}#`qU~u4IV_;yobgjOgfq{V~+0!|IhnImdkNNR? z1_lO>#N-ek1_lO31_lO(ExIokFfcGo_H=O!shIQj(n3ZC1A&$ex9eZNmk@P1qI@IQ z{dygH0s~J2qX7fk0R{;MX0kbtcm&cLESQf-Dx6~|Wa}_?n8S!i$X4{m;Y}sodEXcq z7^Ko5P6oLc>^~3#j8hm=7#JA@o}FP}V3?hj;ur$*7|0`rf(!}*2R4Xz$lfVtHh($ literal 0 HcmV?d00001 diff --git a/Tests/LibWeb/Ref/input/wpt-import/png/cICP-wins.html b/Tests/LibWeb/Ref/input/wpt-import/png/cICP-wins.html new file mode 100644 index 00000000000..b8f9ba4c2fa --- /dev/null +++ b/Tests/LibWeb/Ref/input/wpt-import/png/cICP-wins.html @@ -0,0 +1,22 @@ + + + +PNG Third Edition: Coding Independent Code Points + + + + + + + + +

Test passes if you see a green rectangle, and no red.

+
+ + \ No newline at end of file diff --git a/Tests/LibWeb/Ref/input/wpt-import/png/support/cICP-and-iCCP.png b/Tests/LibWeb/Ref/input/wpt-import/png/support/cICP-and-iCCP.png new file mode 100644 index 0000000000000000000000000000000000000000..71d88defc12b18b29d2c2dd4303e4bfb15d1a4c0 GIT binary patch literal 2745 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 D<0u?{ literal 0 HcmV?d00001