| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |  * Copyright (c) 2023-2024, Lucas Chollet <lucas.chollet@serenityos.org> | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  | #include <AK/Debug.h>
 | 
					
						
							|  |  |  | #include <AK/Error.h>
 | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | #include <LibGfx/ImageFormats/JPEGXLLoader.h>
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  | #include <jxl/decode.h>
 | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Gfx { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  | class JPEGXLLoadingContext { | 
					
						
							| 
									
										
										
										
											2024-07-22 17:55:11 -04:00
										 |  |  |     AK_MAKE_NONCOPYABLE(JPEGXLLoadingContext); | 
					
						
							|  |  |  |     AK_MAKE_NONMOVABLE(JPEGXLLoadingContext); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     JPEGXLLoadingContext(JxlDecoder* decoder) | 
					
						
							|  |  |  |         : m_decoder(decoder) | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     ~JPEGXLLoadingContext() | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         JxlDecoderDestroy(m_decoder); | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     ErrorOr<void> decode_image_header() | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         return run_state_machine_until(State::HeaderDecoded); | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     ErrorOr<void> decode_image() | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         return run_state_machine_until(State::FrameDecoded); | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     enum class State : u8 { | 
					
						
							|  |  |  |         NotDecoded = 0, | 
					
						
							|  |  |  |         Error, | 
					
						
							|  |  |  |         HeaderDecoded, | 
					
						
							|  |  |  |         FrameDecoded, | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     State state() const | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         return m_state; | 
					
						
							| 
									
										
										
										
											2023-07-31 16:56:12 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     IntSize size() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return m_size; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |     Vector<ImageFrameDescriptor> const& frame_descriptors() const | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |         return m_frame_descriptors; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool is_animated() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return m_animated; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     u32 loop_count() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return m_loop_count; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     u32 frame_count() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return m_frame_count; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  | private: | 
					
						
							|  |  |  |     ErrorOr<void> run_state_machine_until(State requested_state) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |         Optional<u32> frame_duration; | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         for (;;) { | 
					
						
							|  |  |  |             auto const status = JxlDecoderProcessInput(m_decoder); | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |             if (status == JXL_DEC_ERROR) | 
					
						
							|  |  |  |                 return Error::from_string_literal("JPEGXLImageDecoderPlugin: Decoder is corrupted."); | 
					
						
							|  |  |  |             if (status == JXL_DEC_NEED_MORE_INPUT) | 
					
						
							|  |  |  |                 return Error::from_string_literal("JPEGXLImageDecoderPlugin: Decoder need more input."); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |             if (status == JXL_DEC_BASIC_INFO) { | 
					
						
							|  |  |  |                 TRY(decode_image_header_impl()); | 
					
						
							|  |  |  |                 if (requested_state <= State::HeaderDecoded) | 
					
						
							|  |  |  |                     return {}; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-07-30 23:08:54 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |             if (status == JXL_DEC_FRAME) { | 
					
						
							|  |  |  |                 JxlFrameHeader header; | 
					
						
							|  |  |  |                 if (auto res = JxlDecoderGetFrameHeader(m_decoder, &header); | 
					
						
							|  |  |  |                     res != JXL_DEC_SUCCESS) | 
					
						
							|  |  |  |                     return Error::from_string_literal("JPEGXLImageDecoderPlugin: Unable to retrieve frame header."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 frame_duration = header.duration; | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |             if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |                 if (!frame_duration.has_value()) | 
					
						
							|  |  |  |                     return Error::from_string_literal("JPEGXLImageDecoderPlugin: No frame header was read."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 TRY(set_output_buffer(*frame_duration)); | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |             if (status == JXL_DEC_FULL_IMAGE) { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |                 m_frame_count++; | 
					
						
							|  |  |  |                 continue; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |             if (status == JXL_DEC_SUCCESS) { | 
					
						
							|  |  |  |                 if (m_state != State::Error) | 
					
						
							|  |  |  |                     m_state = State::FrameDecoded; | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |                 return {}; | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-08-10 23:51:11 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |             warnln("JPEGXLImageDecoderPlugin: Unknown event."); | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |             return Error::from_string_literal("JPEGXLImageDecoderPlugin: Unknown event."); | 
					
						
							| 
									
										
										
										
											2023-08-10 23:51:11 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     ErrorOr<void> decode_image_header_impl() | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         JxlBasicInfo info; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         if (auto res = JxlDecoderGetBasicInfo(m_decoder, &info); res != JXL_DEC_SUCCESS) | 
					
						
							|  |  |  |             return Error::from_string_literal("JPEGXLImageDecoderPlugin: Unable to decode basic information."); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         m_size = { info.xsize, info.ysize }; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |         m_animated = static_cast<bool>(info.have_animation); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (m_animated) | 
					
						
							|  |  |  |             m_loop_count = info.animation.num_loops; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |         m_state = State::HeaderDecoded; | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |     ErrorOr<void> set_output_buffer(u32 duration) | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |         auto result = [this, duration]() -> ErrorOr<void> { | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |             if (JxlDecoderProcessInput(m_decoder) != JXL_DEC_NEED_IMAGE_OUT_BUFFER) | 
					
						
							|  |  |  |                 return Error::from_string_literal("JPEGXLImageDecoderPlugin: Decoder is in an unexpected state."); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |             auto bitmap = TRY(Bitmap::create(Gfx::BitmapFormat::RGBA8888, m_size)); | 
					
						
							|  |  |  |             TRY(m_frame_descriptors.try_empend(bitmap, static_cast<int>(duration))); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |             JxlPixelFormat format = { 4, JXL_TYPE_UINT8, JXL_NATIVE_ENDIAN, 0 }; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |             size_t needed_size = 0; | 
					
						
							|  |  |  |             JxlDecoderImageOutBufferSize(m_decoder, &format, &needed_size); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |             if (needed_size != bitmap->size_in_bytes()) | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |                 return Error::from_string_literal("JPEGXLImageDecoderPlugin: Expected bitmap size is wrong."); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |             if (auto res = JxlDecoderSetImageOutBuffer(m_decoder, &format, bitmap->begin(), bitmap->size_in_bytes()); | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |                 res != JXL_DEC_SUCCESS) | 
					
						
							|  |  |  |                 return Error::from_string_literal("JPEGXLImageDecoderPlugin: Unable to decode frame."); | 
					
						
							| 
									
										
										
										
											2023-08-11 13:16:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |             return {}; | 
					
						
							|  |  |  |         }(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |         if (result.is_error()) { | 
					
						
							|  |  |  |             m_state = State::Error; | 
					
						
							|  |  |  |             warnln("{}", result.error()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     State m_state { State::NotDecoded }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     JxlDecoder* m_decoder; | 
					
						
							| 
									
										
										
										
											2023-08-11 13:16:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     IntSize m_size; | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |     Vector<ImageFrameDescriptor> m_frame_descriptors; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool m_animated { false }; | 
					
						
							|  |  |  |     u32 m_loop_count { 0 }; | 
					
						
							|  |  |  |     u32 m_frame_count { 0 }; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  | JPEGXLImageDecoderPlugin::JPEGXLImageDecoderPlugin(OwnPtr<JPEGXLLoadingContext> context) | 
					
						
							|  |  |  |     : m_context(move(context)) | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | JPEGXLImageDecoderPlugin::~JPEGXLImageDecoderPlugin() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | IntSize JPEGXLImageDecoderPlugin::size() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_context->size(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool JPEGXLImageDecoderPlugin::sniff(ReadonlyBytes data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     auto signature = JxlSignatureCheck(data.data(), data.size()); | 
					
						
							|  |  |  |     return signature == JXL_SIG_CODESTREAM || signature == JXL_SIG_CONTAINER; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JPEGXLImageDecoderPlugin::create(ReadonlyBytes data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |     auto* decoder = JxlDecoderCreate(nullptr); | 
					
						
							|  |  |  |     if (!decoder) | 
					
						
							|  |  |  |         return Error::from_errno(ENOMEM); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |     auto const events = JXL_DEC_BASIC_INFO | JXL_DEC_FRAME | JXL_DEC_FULL_IMAGE; | 
					
						
							|  |  |  |     if (auto res = JxlDecoderSubscribeEvents(decoder, events); res == JXL_DEC_ERROR) | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         return Error::from_string_literal("JPEGXLImageDecoderPlugin: Unable to subscribe to events."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (auto res = JxlDecoderSetInput(decoder, data.data(), data.size()); res == JXL_DEC_ERROR) | 
					
						
							|  |  |  |         return Error::from_string_literal("JPEGXLImageDecoderPlugin: Unable to set decoder input."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Tell the decoder that it won't receive more data for the image.
 | 
					
						
							|  |  |  |     JxlDecoderCloseInput(decoder); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto context = TRY(adopt_nonnull_own_or_enomem(new (nothrow) JPEGXLLoadingContext(decoder))); | 
					
						
							|  |  |  |     auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) JPEGXLImageDecoderPlugin(move(context)))); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  |     TRY(plugin->m_context->decode_image_header()); | 
					
						
							|  |  |  |     return plugin; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool JPEGXLImageDecoderPlugin::is_animated() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |     return m_context->is_animated(); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t JPEGXLImageDecoderPlugin::loop_count() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |     return m_context->loop_count(); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t JPEGXLImageDecoderPlugin::frame_count() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |     // FIXME: There doesn't seem to be a way to have that information
 | 
					
						
							|  |  |  |     //        before decoding all the frames.
 | 
					
						
							|  |  |  |     if (m_context->frame_count() == 0) | 
					
						
							|  |  |  |         (void)frame(0); | 
					
						
							|  |  |  |     return m_context->frame_count(); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t JPEGXLImageDecoderPlugin::first_animated_frame_index() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ErrorOr<ImageFrameDescriptor> JPEGXLImageDecoderPlugin::frame(size_t index, Optional<IntSize>) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_context->state() == JPEGXLLoadingContext::State::Error) | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         return Error::from_string_literal("JPEGXLImageDecoderPlugin: Decoding failed."); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-22 16:13:22 -04:00
										 |  |  |     if (m_context->state() < JPEGXLLoadingContext::State::FrameDecoded) | 
					
						
							| 
									
										
										
										
											2024-07-21 17:23:28 -04:00
										 |  |  |         TRY(m_context->decode_image()); | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 23:27:54 -04:00
										 |  |  |     if (index >= m_context->frame_descriptors().size()) | 
					
						
							|  |  |  |         return Error::from_string_literal("JPEGXLImageDecoderPlugin: Invalid frame index requested."); | 
					
						
							|  |  |  |     return m_context->frame_descriptors()[index]; | 
					
						
							| 
									
										
										
										
											2023-07-04 00:13:34 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ErrorOr<Optional<ReadonlyBytes>> JPEGXLImageDecoderPlugin::icc_data() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return OptionalNone {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | } |