| 
									
										
										
										
											2022-03-12 11:16:30 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2020, Hüseyin ASLITÜRK <asliturk@hotmail.com> | 
					
						
							|  |  |  |  * Copyright (c) 2022, the SerenityOS developers. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-12 20:08:29 -04:00
										 |  |  | #include <AK/BufferedStream.h>
 | 
					
						
							|  |  |  | #include <AK/MemoryStream.h>
 | 
					
						
							| 
									
										
										
										
											2022-03-12 11:16:30 -07:00
										 |  |  | #include <AK/RefPtr.h>
 | 
					
						
							|  |  |  | #include <AK/StringView.h>
 | 
					
						
							|  |  |  | #include <AK/Types.h>
 | 
					
						
							|  |  |  | #include <LibGfx/Bitmap.h>
 | 
					
						
							| 
									
										
										
										
											2023-03-21 14:58:06 -04:00
										 |  |  | #include <LibGfx/ImageFormats/PortableImageLoaderCommon.h>
 | 
					
						
							| 
									
										
										
										
											2022-03-12 11:16:30 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Gfx { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<class TFormatDetails> | 
					
						
							|  |  |  | struct PortableImageMapLoadingContext { | 
					
						
							|  |  |  |     using FormatDetails = TFormatDetails; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum class Type { | 
					
						
							|  |  |  |         Unknown, | 
					
						
							|  |  |  |         ASCII, | 
					
						
							|  |  |  |         RAWBITS | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     enum class State { | 
					
						
							|  |  |  |         NotDecoded = 0, | 
					
						
							|  |  |  |         Error, | 
					
						
							| 
									
										
										
										
											2023-07-10 16:41:42 -04:00
										 |  |  |         HeaderDecoded, | 
					
						
							|  |  |  |         BitmapDecoded, | 
					
						
							| 
									
										
										
										
											2022-03-12 11:16:30 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Type type { Type::Unknown }; | 
					
						
							|  |  |  |     State state { State::NotDecoded }; | 
					
						
							| 
									
										
										
										
											2023-03-12 20:08:29 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-12 11:16:30 -07:00
										 |  |  |     size_t width { 0 }; | 
					
						
							|  |  |  |     size_t height { 0 }; | 
					
						
							|  |  |  |     FormatDetails format_details {}; | 
					
						
							|  |  |  |     RefPtr<Gfx::Bitmap> bitmap; | 
					
						
							| 
									
										
										
										
											2023-03-12 20:08:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     NonnullOwnPtr<SeekableStream> stream; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PortableImageMapLoadingContext(NonnullOwnPtr<SeekableStream> stream) | 
					
						
							|  |  |  |         : stream(move(stream)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-12 11:16:30 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | template<typename TContext> | 
					
						
							|  |  |  | class PortableImageDecoderPlugin final : public ImageDecoderPlugin { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2023-02-26 18:02:50 +00:00
										 |  |  |     static bool sniff(ReadonlyBytes); | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  |     static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> create(ReadonlyBytes); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  |     virtual ~PortableImageDecoderPlugin() override = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual IntSize size() override; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-02 22:20:06 +01:00
										 |  |  |     virtual ErrorOr<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) override; | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-24 21:51:22 -05:00
										 |  |  |     virtual NaturalFrameFormat natural_frame_format() const override; | 
					
						
							|  |  |  |     virtual ErrorOr<NonnullRefPtr<CMYKBitmap>> cmyk_frame() override; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2023-03-12 20:08:29 -04:00
										 |  |  |     PortableImageDecoderPlugin(NonnullOwnPtr<SeekableStream> stream); | 
					
						
							| 
									
										
										
										
											2023-03-12 13:52:14 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  |     OwnPtr<TContext> m_context; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename TContext> | 
					
						
							| 
									
										
										
										
											2023-03-12 20:08:29 -04:00
										 |  |  | PortableImageDecoderPlugin<TContext>::PortableImageDecoderPlugin(NonnullOwnPtr<SeekableStream> stream) | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-12 20:08:29 -04:00
										 |  |  |     m_context = make<TContext>(move(stream)); | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename TContext> | 
					
						
							|  |  |  | IntSize PortableImageDecoderPlugin<TContext>::size() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return { m_context->width, m_context->height }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename TContext> | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> PortableImageDecoderPlugin<TContext>::create(ReadonlyBytes data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-12 20:08:29 -04:00
										 |  |  |     auto stream = TRY(try_make<FixedMemoryStream>(data)); | 
					
						
							| 
									
										
										
										
											2023-07-10 16:42:59 -04:00
										 |  |  |     auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) PortableImageDecoderPlugin<TContext>(move(stream)))); | 
					
						
							| 
									
										
										
										
											2024-01-24 21:27:24 -05:00
										 |  |  |     if constexpr (TContext::FormatDetails::binary_magic_number == '7') | 
					
						
							|  |  |  |         TRY(read_pam_header(*plugin->m_context)); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         TRY(read_header(*plugin->m_context)); | 
					
						
							| 
									
										
										
										
											2023-07-10 16:42:59 -04:00
										 |  |  |     return plugin; | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename TContext> | 
					
						
							| 
									
										
										
										
											2023-02-26 18:02:50 +00:00
										 |  |  | bool PortableImageDecoderPlugin<TContext>::sniff(ReadonlyBytes data) | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     using Context = TContext; | 
					
						
							|  |  |  |     if (data.size() < 2) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-24 21:27:24 -05:00
										 |  |  |     if constexpr (requires { Context::FormatDetails::ascii_magic_number; }) { | 
					
						
							|  |  |  |         if (data.data()[0] == 'P' && data.data()[1] == Context::FormatDetails::ascii_magic_number) | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-20 10:13:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (data.data()[0] == 'P' && data.data()[1] == Context::FormatDetails::binary_magic_number) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename TContext> | 
					
						
							| 
									
										
										
										
											2023-07-02 22:20:06 +01:00
										 |  |  | ErrorOr<ImageFrameDescriptor> PortableImageDecoderPlugin<TContext>::frame(size_t index, Optional<IntSize>) | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | { | 
					
						
							|  |  |  |     if (index > 0) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:57:32 +00:00
										 |  |  |         return Error::from_string_literal("PortableImageDecoderPlugin: Invalid frame index"); | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (m_context->state == TContext::State::Error) | 
					
						
							| 
									
										
										
										
											2022-07-11 17:57:32 +00:00
										 |  |  |         return Error::from_string_literal("PortableImageDecoderPlugin: Decoding failed"); | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-10 16:41:42 -04:00
										 |  |  |     if (m_context->state < TContext::State::BitmapDecoded) { | 
					
						
							| 
									
										
										
										
											2023-03-12 23:03:08 -04:00
										 |  |  |         if (decode(*m_context).is_error()) { | 
					
						
							|  |  |  |             m_context->state = TContext::State::Error; | 
					
						
							| 
									
										
										
										
											2022-07-11 17:57:32 +00:00
										 |  |  |             return Error::from_string_literal("PortableImageDecoderPlugin: Decoding failed"); | 
					
						
							| 
									
										
										
										
											2023-03-12 23:03:08 -04:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-24 21:51:22 -05:00
										 |  |  |     if constexpr (requires { TContext::FormatDetails::cmyk_bitmap; }) { | 
					
						
							|  |  |  |         if (m_context->format_details.cmyk_bitmap.has_value()) | 
					
						
							|  |  |  |             m_context->bitmap = TRY(m_context->format_details.cmyk_bitmap.value()->to_low_quality_rgb()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-13 11:58:58 -06:00
										 |  |  |     VERIFY(m_context->bitmap); | 
					
						
							|  |  |  |     return ImageFrameDescriptor { m_context->bitmap, 0 }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-01-26 07:23:59 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-24 21:51:22 -05:00
										 |  |  | template<typename TContext> | 
					
						
							|  |  |  | NaturalFrameFormat PortableImageDecoderPlugin<TContext>::natural_frame_format() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if constexpr (requires { TContext::FormatDetails::cmyk_bitmap; }) { | 
					
						
							|  |  |  |         if (m_context->format_details.depth == 4 && m_context->format_details.tupl_type == "CMYK"sv) | 
					
						
							|  |  |  |             return NaturalFrameFormat::CMYK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return NaturalFrameFormat::RGB; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename TContext> | 
					
						
							|  |  |  | ErrorOr<NonnullRefPtr<CMYKBitmap>> PortableImageDecoderPlugin<TContext>::cmyk_frame() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if constexpr (requires { TContext::FormatDetails::cmyk_bitmap; }) { | 
					
						
							|  |  |  |         VERIFY(natural_frame_format() == NaturalFrameFormat::CMYK); | 
					
						
							|  |  |  |         if (m_context->state == TContext::State::Error) | 
					
						
							|  |  |  |             return Error::from_string_literal("PortableImageDecoderPlugin: Decoding failed"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (m_context->state < TContext::State::BitmapDecoded) { | 
					
						
							|  |  |  |             if (decode(*m_context).is_error()) { | 
					
						
							|  |  |  |                 m_context->state = TContext::State::Error; | 
					
						
							|  |  |  |                 return Error::from_string_literal("PortableImageDecoderPlugin: Decoding failed"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return *m_context->format_details.cmyk_bitmap.value(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-12 11:16:30 -07:00
										 |  |  | } |