/* * Copyright (c) 2018-2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include namespace Gfx { class Bitmap; struct ImageFrameDescriptor { RefPtr image; int duration { 0 }; }; struct VectorImageFrameDescriptor { RefPtr image; int duration { 0 }; }; class Metadata { public: Metadata() = default; virtual ~Metadata() = default; HashMap const& main_tags() const { if (m_main_tags.is_empty()) fill_main_tags(); // This is designed to be used in a general GUI, don't include too much information here. VERIFY(m_main_tags.size() < 8); return m_main_tags; } protected: virtual void fill_main_tags() const {}; mutable HashMap m_main_tags; }; enum class NaturalFrameFormat { RGB, Grayscale, CMYK, Vector, }; class ImageDecoderPlugin { public: virtual ~ImageDecoderPlugin() = default; // Each plugin should implement these static functions and register them in ImageDecoder.cpp // Implement sniff() if the file includes a magic number // static bool sniff(ReadonlyBytes); // Implement validate_before_create() otherwise // static ErrorOr validate_before_create(ReadonlyBytes); // This function should be used to both create the context and parse the image header. // static ErrorOr> create(ReadonlyBytes); // This should always be available as gathered in create() virtual IntSize size() = 0; // Override this if the format supports animated images virtual bool is_animated() { return false; } virtual size_t loop_count() { return 0; } virtual size_t frame_count() { return 1; } virtual size_t first_animated_frame_index() { return 0; } virtual ErrorOr frame(size_t index, Optional ideal_size = {}) = 0; virtual Optional metadata() { return OptionalNone {}; } virtual ErrorOr> icc_data() { return OptionalNone {}; } virtual NaturalFrameFormat natural_frame_format() const { return NaturalFrameFormat::RGB; } virtual ErrorOr> cmyk_frame() { VERIFY_NOT_REACHED(); } virtual ErrorOr vector_frame(size_t) { VERIFY_NOT_REACHED(); } protected: ImageDecoderPlugin() = default; }; class ImageDecoder : public RefCounted { public: static ErrorOr> try_create_for_raw_bytes(ReadonlyBytes, Optional mime_type = {}); ~ImageDecoder() = default; IntSize size() const { return m_plugin->size(); } int width() const { return size().width(); } int height() const { return size().height(); } bool is_animated() const { return m_plugin->is_animated(); } size_t loop_count() const { return m_plugin->loop_count(); } size_t frame_count() const { return m_plugin->frame_count(); } size_t first_animated_frame_index() const { return m_plugin->first_animated_frame_index(); } ErrorOr frame(size_t index, Optional ideal_size = {}) const { return m_plugin->frame(index, ideal_size); } Optional metadata() const { return m_plugin->metadata(); } ErrorOr> icc_data() const { return m_plugin->icc_data(); } NaturalFrameFormat natural_frame_format() { return m_plugin->natural_frame_format(); } // Call only if natural_frame_format() == NaturalFrameFormat::CMYK. ErrorOr> cmyk_frame() { return m_plugin->cmyk_frame(); } // Call only if natural_frame_format() == NaturalFrameFormat::Vector. ErrorOr vector_frame(size_t index) { return m_plugin->vector_frame(index); } private: explicit ImageDecoder(NonnullOwnPtr); NonnullOwnPtr mutable m_plugin; }; }