ladybird/Libraries/LibGfx/ImageFormats/ImageDecoder.h

133 lines
4.2 KiB
C
Raw Normal View History

/*
* Copyright (c) 2018-2021, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/HashMap.h>
#include <AK/OwnPtr.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <AK/String.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/CMYKBitmap.h>
LibGfx+LibWeb: Do some color management on images with an ICC profile This patch introduces the `Gfx::ColorSpace` class, this is basically a serializable wrapper for skia's SkColorSpace. Creation of the instances of this class (and thus ICC profiles parsing) is performed in the ImageDecoder process. Then the object is serialized and sent through IPC, to finally be handed to skia for rendering. However, to make sure that we're not making all LibGfx's users dependent on Skia as well, we need to ensure the `Gfx::ColorSpace` object has no dependency on objects from Skia. To that end, the only member of the `ColorSpace` class is the opaque `ColorSpaceImpl` struct. Though, there is on issue with that design, the code in `DisplayListPlayer.cpp` needs access to the underlying `sk_sp<SkColorSpace>`. It is provided by a template function, that is only specialized for this type. Doing this work allows us to pass the following WPT tests: - https://wpt.live/css/css-color/tagged-images-001.html - https://wpt.live/css/css-color/tagged-images-003.html - https://wpt.live/css/css-color/tagged-images-004.html - https://wpt.live/css/css-color/untagged-images-001.html Other test cases can also be found here: - https://github.com/svgeesus/PNG-ICC-tests Note that SkColorSpace support quite a limited amount of color spaces, so color profiles like the ones in [1] or the v4 profiles in [2] are not supported yet. In fact, SkColorSpace only accepts skcms_ICCProfile with a linear conversion to XYZ D50. [1] https://www.color.org/browsertest.xalter [2] https://www.color.org/version4html.xalter
2024-12-02 18:55:43 -05:00
#include <LibGfx/ColorSpace.h>
2020-02-06 12:04:00 +01:00
#include <LibGfx/Size.h>
#include <LibGfx/VectorGraphic.h>
namespace Gfx {
class Bitmap;
struct ImageFrameDescriptor {
RefPtr<Bitmap> image;
int duration { 0 };
};
struct VectorImageFrameDescriptor {
RefPtr<VectorGraphic> image;
int duration { 0 };
};
class Metadata {
public:
Metadata() = default;
virtual ~Metadata() = default;
HashMap<StringView, String> 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<StringView, String> 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<bool> validate_before_create(ReadonlyBytes);
// This function should be used to both create the context and parse the image header.
// static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> 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<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) = 0;
virtual Optional<Metadata const&> metadata() { return OptionalNone {}; }
virtual ErrorOr<Optional<ReadonlyBytes>> icc_data() { return OptionalNone {}; }
virtual NaturalFrameFormat natural_frame_format() const { return NaturalFrameFormat::RGB; }
virtual ErrorOr<NonnullRefPtr<CMYKBitmap>> cmyk_frame() { VERIFY_NOT_REACHED(); }
virtual ErrorOr<VectorImageFrameDescriptor> vector_frame(size_t) { VERIFY_NOT_REACHED(); }
protected:
ImageDecoderPlugin() = default;
};
class ImageDecoder : public RefCounted<ImageDecoder> {
public:
static ErrorOr<RefPtr<ImageDecoder>> try_create_for_raw_bytes(ReadonlyBytes, Optional<ByteString> 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<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) const { return m_plugin->frame(index, ideal_size); }
Optional<Metadata const&> metadata() const { return m_plugin->metadata(); }
LibGfx+LibWeb: Do some color management on images with an ICC profile This patch introduces the `Gfx::ColorSpace` class, this is basically a serializable wrapper for skia's SkColorSpace. Creation of the instances of this class (and thus ICC profiles parsing) is performed in the ImageDecoder process. Then the object is serialized and sent through IPC, to finally be handed to skia for rendering. However, to make sure that we're not making all LibGfx's users dependent on Skia as well, we need to ensure the `Gfx::ColorSpace` object has no dependency on objects from Skia. To that end, the only member of the `ColorSpace` class is the opaque `ColorSpaceImpl` struct. Though, there is on issue with that design, the code in `DisplayListPlayer.cpp` needs access to the underlying `sk_sp<SkColorSpace>`. It is provided by a template function, that is only specialized for this type. Doing this work allows us to pass the following WPT tests: - https://wpt.live/css/css-color/tagged-images-001.html - https://wpt.live/css/css-color/tagged-images-003.html - https://wpt.live/css/css-color/tagged-images-004.html - https://wpt.live/css/css-color/untagged-images-001.html Other test cases can also be found here: - https://github.com/svgeesus/PNG-ICC-tests Note that SkColorSpace support quite a limited amount of color spaces, so color profiles like the ones in [1] or the v4 profiles in [2] are not supported yet. In fact, SkColorSpace only accepts skcms_ICCProfile with a linear conversion to XYZ D50. [1] https://www.color.org/browsertest.xalter [2] https://www.color.org/version4html.xalter
2024-12-02 18:55:43 -05:00
ErrorOr<ColorSpace> color_space();
ErrorOr<Optional<ReadonlyBytes>> 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<NonnullRefPtr<CMYKBitmap>> cmyk_frame() { return m_plugin->cmyk_frame(); }
// Call only if natural_frame_format() == NaturalFrameFormat::Vector.
ErrorOr<VectorImageFrameDescriptor> vector_frame(size_t index) { return m_plugin->vector_frame(index); }
private:
explicit ImageDecoder(NonnullOwnPtr<ImageDecoderPlugin>);
NonnullOwnPtr<ImageDecoderPlugin> mutable m_plugin;
};
}