Coverage Report

Created: 2026-02-16 07:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibGfx/ImageFormats/ImageDecoder.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/ByteBuffer.h>
10
#include <AK/HashMap.h>
11
#include <AK/OwnPtr.h>
12
#include <AK/RefCounted.h>
13
#include <AK/RefPtr.h>
14
#include <AK/String.h>
15
#include <LibGfx/Bitmap.h>
16
#include <LibGfx/CMYKBitmap.h>
17
#include <LibGfx/Size.h>
18
#include <LibGfx/VectorGraphic.h>
19
20
namespace Gfx {
21
22
class Bitmap;
23
24
struct ImageFrameDescriptor {
25
    RefPtr<Bitmap> image;
26
    int duration { 0 };
27
};
28
29
struct VectorImageFrameDescriptor {
30
    RefPtr<VectorGraphic> image;
31
    int duration { 0 };
32
};
33
34
class Metadata {
35
public:
36
21.0k
    Metadata() = default;
37
36.7k
    virtual ~Metadata() = default;
38
39
    HashMap<StringView, String> const& main_tags() const
40
0
    {
41
0
        if (m_main_tags.is_empty())
42
0
            fill_main_tags();
43
0
44
0
        // This is designed to be used in a general GUI, don't include too much information here.
45
0
        VERIFY(m_main_tags.size() < 8);
46
0
47
0
        return m_main_tags;
48
0
    }
49
50
protected:
51
0
    virtual void fill_main_tags() const { }
52
53
    mutable HashMap<StringView, String> m_main_tags;
54
};
55
56
enum class NaturalFrameFormat {
57
    RGB,
58
    Grayscale,
59
    CMYK,
60
    Vector,
61
};
62
63
class ImageDecoderPlugin {
64
public:
65
60.8k
    virtual ~ImageDecoderPlugin() = default;
66
67
    // Each plugin should implement these static functions and register them in ImageDecoder.cpp
68
    // Implement sniff() if the file includes a magic number
69
    // static bool sniff(ReadonlyBytes);
70
    // Implement validate_before_create() otherwise
71
    // static ErrorOr<bool> validate_before_create(ReadonlyBytes);
72
73
    // This function should be used to both create the context and parse the image header.
74
    // static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> create(ReadonlyBytes);
75
76
    // This should always be available as gathered in create()
77
    virtual IntSize size() = 0;
78
79
    // Override this if the format supports animated images
80
0
    virtual bool is_animated() { return false; }
81
0
    virtual size_t loop_count() { return 0; }
82
0
    virtual size_t frame_count() { return 1; }
83
0
    virtual size_t first_animated_frame_index() { return 0; }
84
85
    virtual ErrorOr<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) = 0;
86
87
0
    virtual Optional<Metadata const&> metadata() { return OptionalNone {}; }
88
89
0
    virtual ErrorOr<Optional<ReadonlyBytes>> icc_data() { return OptionalNone {}; }
90
91
0
    virtual NaturalFrameFormat natural_frame_format() const { return NaturalFrameFormat::RGB; }
92
0
    virtual ErrorOr<NonnullRefPtr<CMYKBitmap>> cmyk_frame() { VERIFY_NOT_REACHED(); }
93
0
    virtual ErrorOr<VectorImageFrameDescriptor> vector_frame(size_t) { VERIFY_NOT_REACHED(); }
94
95
protected:
96
60.8k
    ImageDecoderPlugin() = default;
97
};
98
99
class ImageDecoder : public RefCounted<ImageDecoder> {
100
public:
101
    static ErrorOr<RefPtr<ImageDecoder>> try_create_for_raw_bytes(ReadonlyBytes, Optional<ByteString> mime_type = {});
102
0
    ~ImageDecoder() = default;
103
104
0
    IntSize size() const { return m_plugin->size(); }
105
0
    int width() const { return size().width(); }
106
0
    int height() const { return size().height(); }
107
0
    bool is_animated() const { return m_plugin->is_animated(); }
108
0
    size_t loop_count() const { return m_plugin->loop_count(); }
109
0
    size_t frame_count() const { return m_plugin->frame_count(); }
110
0
    size_t first_animated_frame_index() const { return m_plugin->first_animated_frame_index(); }
111
112
0
    ErrorOr<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) const { return m_plugin->frame(index, ideal_size); }
113
114
0
    Optional<Metadata const&> metadata() const { return m_plugin->metadata(); }
115
0
    ErrorOr<Optional<ReadonlyBytes>> icc_data() const { return m_plugin->icc_data(); }
116
117
0
    NaturalFrameFormat natural_frame_format() { return m_plugin->natural_frame_format(); }
118
119
    // Call only if natural_frame_format() == NaturalFrameFormat::CMYK.
120
0
    ErrorOr<NonnullRefPtr<CMYKBitmap>> cmyk_frame() { return m_plugin->cmyk_frame(); }
121
122
    // Call only if natural_frame_format() == NaturalFrameFormat::Vector.
123
0
    ErrorOr<VectorImageFrameDescriptor> vector_frame(size_t index) { return m_plugin->vector_frame(index); }
124
125
private:
126
    explicit ImageDecoder(NonnullOwnPtr<ImageDecoderPlugin>);
127
128
    NonnullOwnPtr<ImageDecoderPlugin> mutable m_plugin;
129
};
130
131
}