/* * Copyright (c) 2020, Hüseyin ASLITÜRK * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include namespace Gfx { template struct PortableImageMapLoadingContext { using FormatDetails = TFormatDetails; enum class Type { Unknown, ASCII, RAWBITS }; enum class State { NotDecoded = 0, Error, HeaderDecoded, BitmapDecoded, }; Type type { Type::Unknown }; State state { State::NotDecoded }; size_t width { 0 }; size_t height { 0 }; FormatDetails format_details {}; RefPtr bitmap; NonnullOwnPtr stream; PortableImageMapLoadingContext(NonnullOwnPtr stream) : stream(move(stream)) { } }; template class PortableImageDecoderPlugin final : public ImageDecoderPlugin { public: static bool sniff(ReadonlyBytes); static ErrorOr> create(ReadonlyBytes); virtual ~PortableImageDecoderPlugin() override = default; virtual IntSize size() override; virtual ErrorOr frame(size_t index, Optional ideal_size = {}) override; private: PortableImageDecoderPlugin(NonnullOwnPtr stream); OwnPtr m_context; }; template PortableImageDecoderPlugin::PortableImageDecoderPlugin(NonnullOwnPtr stream) { m_context = make(move(stream)); } template IntSize PortableImageDecoderPlugin::size() { return { m_context->width, m_context->height }; } template ErrorOr> PortableImageDecoderPlugin::create(ReadonlyBytes data) { auto stream = TRY(try_make(data)); auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) PortableImageDecoderPlugin(move(stream)))); if constexpr (TContext::FormatDetails::binary_magic_number == '7') TRY(read_pam_header(*plugin->m_context)); else TRY(read_header(*plugin->m_context)); return plugin; } template bool PortableImageDecoderPlugin::sniff(ReadonlyBytes data) { using Context = TContext; if (data.size() < 2) return false; if constexpr (requires { Context::FormatDetails::ascii_magic_number; }) { if (data.data()[0] == 'P' && data.data()[1] == Context::FormatDetails::ascii_magic_number) return true; } if (data.data()[0] == 'P' && data.data()[1] == Context::FormatDetails::binary_magic_number) return true; return false; } template ErrorOr PortableImageDecoderPlugin::frame(size_t index, Optional) { if (index > 0) return Error::from_string_literal("PortableImageDecoderPlugin: Invalid frame index"); 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"); } } VERIFY(m_context->bitmap); return ImageFrameDescriptor { m_context->bitmap, 0 }; } }