/* * 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 namespace Gfx { template struct PortableImageMapLoadingContext { using FormatDetails = TFormatDetails; enum class Type { Unknown, ASCII, RAWBITS }; enum class State { NotDecoded = 0, Error, MagicNumber, Width, Height, Maxval, Bitmap, Decoded }; Type type { Type::Unknown }; State state { State::NotDecoded }; u8 const* data { nullptr }; size_t data_size { 0 }; size_t width { 0 }; size_t height { 0 }; FormatDetails format_details {}; RefPtr bitmap; }; template class PortableImageDecoderPlugin final : public ImageDecoderPlugin { public: static bool sniff(ReadonlyBytes); static ErrorOr> create(ReadonlyBytes); PortableImageDecoderPlugin(u8 const*, size_t); virtual ~PortableImageDecoderPlugin() override = default; virtual IntSize size() override; virtual void set_volatile() override; [[nodiscard]] virtual bool set_nonvolatile(bool& was_purged) override; virtual bool initialize() override; virtual bool is_animated() override; virtual size_t loop_count() override; virtual size_t frame_count() override; virtual ErrorOr frame(size_t index) override; virtual ErrorOr> icc_data() override; private: OwnPtr m_context; }; template PortableImageDecoderPlugin::PortableImageDecoderPlugin(u8 const* data, size_t size) { m_context = make(); m_context->data = data; m_context->data_size = size; } template IntSize PortableImageDecoderPlugin::size() { if (m_context->state == TContext::State::Error) return {}; if (m_context->state < TContext::State::Decoded) { bool success = decode(*m_context); if (!success) return {}; } return { m_context->width, m_context->height }; } template void PortableImageDecoderPlugin::set_volatile() { if (m_context->bitmap) m_context->bitmap->set_volatile(); } template bool PortableImageDecoderPlugin::set_nonvolatile(bool& was_purged) { if (!m_context->bitmap) return false; return m_context->bitmap->set_nonvolatile(was_purged); } template bool PortableImageDecoderPlugin::initialize() { using Context = TContext; if (m_context->data_size < 2) return false; if (m_context->data[0] == 'P' && m_context->data[1] == Context::FormatDetails::ascii_magic_number) return true; if (m_context->data[0] == 'P' && m_context->data[1] == Context::FormatDetails::binary_magic_number) return true; return false; } template ErrorOr> PortableImageDecoderPlugin::create(ReadonlyBytes data) { return adopt_nonnull_own_or_enomem(new (nothrow) PortableImageDecoderPlugin(data.data(), data.size())); } template bool PortableImageDecoderPlugin::sniff(ReadonlyBytes data) { using Context = TContext; if (data.size() < 2) return false; 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 bool PortableImageDecoderPlugin::is_animated() { return false; } template size_t PortableImageDecoderPlugin::loop_count() { return 0; } template size_t PortableImageDecoderPlugin::frame_count() { return 1; } template ErrorOr PortableImageDecoderPlugin::frame(size_t index) { 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::Decoded) { bool success = decode(*m_context); if (!success) return Error::from_string_literal("PortableImageDecoderPlugin: Decoding failed"); } VERIFY(m_context->bitmap); return ImageFrameDescriptor { m_context->bitmap, 0 }; } template ErrorOr> PortableImageDecoderPlugin::icc_data() { return OptionalNone {}; } }