Serenity Operating System
1/*
2 * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2021-2022, Mustafa Quraish <mustafa@serenityos.org>
4 * Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 */
8
9#pragma once
10
11#include "Selection.h"
12#include <AK/HashTable.h>
13#include <AK/JsonObjectSerializer.h>
14#include <AK/RefCounted.h>
15#include <AK/RefPtr.h>
16#include <AK/Result.h>
17#include <LibGUI/Command.h>
18#include <LibGUI/Forward.h>
19#include <LibGfx/Bitmap.h>
20#include <LibGfx/Forward.h>
21#include <LibGfx/Painter.h>
22#include <LibGfx/Rect.h>
23#include <LibGfx/Size.h>
24
25namespace PixelPaint {
26
27class Layer;
28class Selection;
29
30class ImageClient {
31public:
32 virtual void image_did_add_layer(size_t) { }
33 virtual void image_did_remove_layer(size_t) { }
34 virtual void image_did_modify_layer_properties(size_t) { }
35 virtual void image_did_modify_layer_bitmap(size_t) { }
36 virtual void image_did_modify_layer_stack() { }
37 virtual void image_did_change(Gfx::IntRect const&) { }
38 virtual void image_did_change_rect(Gfx::IntRect const&) { }
39 virtual void image_select_layer(Layer*) { }
40
41protected:
42 virtual ~ImageClient() = default;
43};
44
45class Image : public RefCounted<Image> {
46public:
47 static ErrorOr<NonnullRefPtr<Image>> create_with_size(Gfx::IntSize);
48 static ErrorOr<NonnullRefPtr<Image>> create_from_pixel_paint_json(JsonObject const&);
49 static ErrorOr<NonnullRefPtr<Image>> create_from_bitmap(NonnullRefPtr<Gfx::Bitmap> const&);
50
51 static ErrorOr<NonnullRefPtr<Gfx::Bitmap>> decode_bitmap(ReadonlyBytes);
52
53 // This generates a new Bitmap with the final image (all layers composed according to their attributes.)
54 ErrorOr<NonnullRefPtr<Gfx::Bitmap>> compose_bitmap(Gfx::BitmapFormat format) const;
55 RefPtr<Gfx::Bitmap> copy_bitmap(Selection const&) const;
56
57 Selection& selection() { return m_selection; }
58 Selection const& selection() const { return m_selection; }
59
60 size_t layer_count() const { return m_layers.size(); }
61 Layer const& layer(size_t index) const { return m_layers.at(index); }
62 Layer& layer(size_t index) { return m_layers.at(index); }
63
64 Gfx::IntSize size() const { return m_size; }
65 Gfx::IntRect rect() const { return { {}, m_size }; }
66
67 void add_layer(NonnullRefPtr<Layer>);
68 ErrorOr<NonnullRefPtr<Image>> take_snapshot() const;
69 ErrorOr<void> restore_snapshot(Image const&);
70
71 void paint_into(GUI::Painter&, Gfx::IntRect const& dest_rect, float scale) const;
72
73 ErrorOr<void> serialize_as_json(JsonObjectSerializer<StringBuilder>& json) const;
74 ErrorOr<void> export_bmp_to_file(NonnullOwnPtr<Stream>, bool preserve_alpha_channel) const;
75 ErrorOr<void> export_png_to_file(NonnullOwnPtr<Stream>, bool preserve_alpha_channel) const;
76 ErrorOr<void> export_qoi_to_file(NonnullOwnPtr<Stream>) const;
77
78 void move_layer_to_front(Layer&);
79 void move_layer_to_back(Layer&);
80 void move_layer_up(Layer&);
81 void move_layer_down(Layer&);
82 void change_layer_index(size_t old_index, size_t new_index);
83 void remove_layer(Layer&);
84 void select_layer(Layer*);
85 ErrorOr<void> flatten_all_layers();
86 ErrorOr<void> merge_visible_layers();
87 ErrorOr<void> merge_active_layer_up(Layer& layer);
88 ErrorOr<void> merge_active_layer_down(Layer& layer);
89
90 void add_client(ImageClient&);
91 void remove_client(ImageClient&);
92
93 void layer_did_modify_bitmap(Badge<Layer>, Layer const&, Gfx::IntRect const& modified_layer_rect);
94 void layer_did_modify_properties(Badge<Layer>, Layer const&);
95
96 size_t index_of(Layer const&) const;
97
98 ErrorOr<void> flip(Gfx::Orientation orientation);
99 ErrorOr<void> rotate(Gfx::RotationDirection direction);
100 ErrorOr<void> crop(Gfx::IntRect const& rect);
101 ErrorOr<void> resize(Gfx::IntSize new_size, Gfx::Painter::ScalingMode scaling_mode);
102
103 Optional<Gfx::IntRect> nonempty_content_bounding_rect() const;
104
105 Color color_at(Gfx::IntPoint point) const;
106
107private:
108 enum class LayerMergeMode {
109 All,
110 VisibleOnly
111 };
112
113 enum class LayerMergeDirection {
114 Up,
115 Down
116 };
117
118 explicit Image(Gfx::IntSize);
119
120 void did_change(Gfx::IntRect const& modified_rect = {});
121 void did_change_rect(Gfx::IntRect const& modified_rect = {});
122 void did_modify_layer_stack();
123
124 ErrorOr<void> merge_layers(LayerMergeMode);
125 ErrorOr<void> merge_active_layer(NonnullRefPtr<Layer> const&, LayerMergeDirection);
126
127 Gfx::IntSize m_size;
128 Vector<NonnullRefPtr<Layer>> m_layers;
129
130 HashTable<ImageClient*> m_clients;
131
132 Selection m_selection;
133};
134
135class ImageUndoCommand : public GUI::Command {
136public:
137 ImageUndoCommand(Image&, DeprecatedString action_text);
138
139 virtual void undo() override;
140 virtual void redo() override;
141 virtual DeprecatedString action_text() const override { return m_action_text; }
142
143private:
144 RefPtr<Image> m_snapshot;
145 Image& m_image;
146 DeprecatedString m_action_text;
147};
148
149}