summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGfx/ImageFormats/PortableImageMapLoader.h
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibGfx/ImageFormats/PortableImageMapLoader.h')
-rw-r--r--Userland/Libraries/LibGfx/ImageFormats/PortableImageMapLoader.h194
1 files changed, 194 insertions, 0 deletions
diff --git a/Userland/Libraries/LibGfx/ImageFormats/PortableImageMapLoader.h b/Userland/Libraries/LibGfx/ImageFormats/PortableImageMapLoader.h
new file mode 100644
index 0000000000..9426bca36e
--- /dev/null
+++ b/Userland/Libraries/LibGfx/ImageFormats/PortableImageMapLoader.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2020, Hüseyin ASLITÜRK <asliturk@hotmail.com>
+ * Copyright (c) 2022, the SerenityOS developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/RefPtr.h>
+#include <AK/StringView.h>
+#include <AK/Types.h>
+#include <LibGfx/Bitmap.h>
+#include <LibGfx/ImageFormats/PortableImageLoaderCommon.h>
+
+namespace Gfx {
+
+template<class TFormatDetails>
+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<Gfx::Bitmap> bitmap;
+};
+
+template<typename TContext>
+class PortableImageDecoderPlugin final : public ImageDecoderPlugin {
+public:
+ static bool sniff(ReadonlyBytes);
+ static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> 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<ImageFrameDescriptor> frame(size_t index) override;
+ virtual ErrorOr<Optional<ReadonlyBytes>> icc_data() override;
+
+private:
+ OwnPtr<TContext> m_context;
+};
+
+template<typename TContext>
+PortableImageDecoderPlugin<TContext>::PortableImageDecoderPlugin(u8 const* data, size_t size)
+{
+ m_context = make<TContext>();
+ m_context->data = data;
+ m_context->data_size = size;
+}
+
+template<typename TContext>
+IntSize PortableImageDecoderPlugin<TContext>::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<typename TContext>
+void PortableImageDecoderPlugin<TContext>::set_volatile()
+{
+ if (m_context->bitmap)
+ m_context->bitmap->set_volatile();
+}
+
+template<typename TContext>
+bool PortableImageDecoderPlugin<TContext>::set_nonvolatile(bool& was_purged)
+{
+ if (!m_context->bitmap)
+ return false;
+
+ return m_context->bitmap->set_nonvolatile(was_purged);
+}
+
+template<typename TContext>
+bool PortableImageDecoderPlugin<TContext>::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<typename TContext>
+ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> PortableImageDecoderPlugin<TContext>::create(ReadonlyBytes data)
+{
+ return adopt_nonnull_own_or_enomem(new (nothrow) PortableImageDecoderPlugin<TContext>(data.data(), data.size()));
+}
+
+template<typename TContext>
+bool PortableImageDecoderPlugin<TContext>::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<typename TContext>
+bool PortableImageDecoderPlugin<TContext>::is_animated()
+{
+ return false;
+}
+
+template<typename TContext>
+size_t PortableImageDecoderPlugin<TContext>::loop_count()
+{
+ return 0;
+}
+
+template<typename TContext>
+size_t PortableImageDecoderPlugin<TContext>::frame_count()
+{
+ return 1;
+}
+
+template<typename TContext>
+ErrorOr<ImageFrameDescriptor> PortableImageDecoderPlugin<TContext>::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<typename TContext>
+ErrorOr<Optional<ReadonlyBytes>> PortableImageDecoderPlugin<TContext>::icc_data()
+{
+ return OptionalNone {};
+}
+
+}