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#include "Image.h"
10#include "Layer.h"
11#include "Selection.h"
12#include <AK/Base64.h>
13#include <AK/JsonObject.h>
14#include <LibGUI/Painter.h>
15#include <LibGfx/BMPWriter.h>
16#include <LibGfx/Bitmap.h>
17#include <LibGfx/PNGWriter.h>
18#include <LibGfx/QOIWriter.h>
19#include <LibImageDecoderClient/Client.h>
20#include <stdio.h>
21
22namespace PixelPaint {
23
24ErrorOr<NonnullRefPtr<Image>> Image::create_with_size(Gfx::IntSize size)
25{
26 VERIFY(!size.is_empty());
27
28 if (size.width() > 16384 || size.height() > 16384)
29 return Error::from_string_literal("Image size too large");
30
31 return adopt_nonnull_ref_or_enomem(new (nothrow) Image(size));
32}
33
34Image::Image(Gfx::IntSize size)
35 : m_size(size)
36 , m_selection(*this)
37{
38}
39
40void Image::paint_into(GUI::Painter& painter, Gfx::IntRect const& dest_rect, float scale) const
41{
42 Gfx::PainterStateSaver saver(painter);
43 painter.add_clip_rect(dest_rect);
44 for (auto const& layer : m_layers) {
45 if (!layer->is_visible())
46 continue;
47 auto target = dest_rect.to_type<float>().translated(layer->location().x() * scale, layer->location().y() * scale);
48 target.set_size(layer->size().width() * scale, layer->size().height() * scale);
49 painter.draw_scaled_bitmap(target.to_type<int>(), layer->display_bitmap(), layer->rect(), (float)layer->opacity_percent() / 100.0f);
50 }
51}
52
53ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Image::decode_bitmap(ReadonlyBytes bitmap_data)
54{
55 // Spawn a new ImageDecoder service process and connect to it.
56 auto client = TRY(ImageDecoderClient::Client::try_create());
57
58 // FIXME: Find a way to avoid the memory copying here.
59 auto maybe_decoded_image = client->decode_image(bitmap_data);
60 if (!maybe_decoded_image.has_value())
61 return Error::from_string_literal("Image decode failed");
62
63 // FIXME: Support multi-frame images?
64 auto decoded_image = maybe_decoded_image.release_value();
65 if (decoded_image.frames.is_empty())
66 return Error::from_string_literal("Image decode failed (no frames)");
67
68 auto decoded_bitmap = decoded_image.frames.first().bitmap;
69 if (decoded_bitmap.is_null())
70 return Error::from_string_literal("Image decode failed (no bitmap for frame)");
71 return decoded_bitmap.release_nonnull();
72}
73
74ErrorOr<NonnullRefPtr<Image>> Image::create_from_bitmap(NonnullRefPtr<Gfx::Bitmap> const& bitmap)
75{
76 auto image = TRY(create_with_size({ bitmap->width(), bitmap->height() }));
77 auto layer = TRY(Layer::create_with_bitmap(*image, *bitmap, "Background"));
78 image->add_layer(move(layer));
79 return image;
80}
81
82ErrorOr<NonnullRefPtr<Image>> Image::create_from_pixel_paint_json(JsonObject const& json)
83{
84 // FIXME: Handle invalid JSON data
85 auto image = TRY(create_with_size({ json.get_i32("width"sv).value_or(0), json.get_i32("height"sv).value_or(0) }));
86
87 auto layers_value = json.get_array("layers"sv).value();
88 for (auto& layer_value : layers_value.values()) {
89 auto const& layer_object = layer_value.as_object();
90 auto name = layer_object.get_deprecated_string("name"sv).value();
91
92 auto bitmap_base64_encoded = layer_object.get_deprecated_string("bitmap"sv).value();
93 auto bitmap_data = TRY(decode_base64(bitmap_base64_encoded));
94 auto bitmap = TRY(decode_bitmap(bitmap_data));
95 auto layer = TRY(Layer::create_with_bitmap(*image, move(bitmap), name));
96
97 if (auto const& mask_object = layer_object.get_deprecated_string("mask"sv); mask_object.has_value()) {
98 auto mask_base64_encoded = mask_object.value();
99 auto mask_data = TRY(decode_base64(mask_base64_encoded));
100 auto mask = TRY(decode_bitmap(mask_data));
101 TRY(layer->set_bitmaps(layer->content_bitmap(), mask));
102 }
103
104 auto width = layer_object.get_i32("width"sv).value_or(0);
105 auto height = layer_object.get_i32("height"sv).value_or(0);
106
107 if (width != layer->size().width() || height != layer->size().height())
108 return Error::from_string_literal("Decoded layer bitmap has wrong size");
109
110 image->add_layer(*layer);
111
112 layer->set_location({ layer_object.get_i32("locationx"sv).value_or(0), layer_object.get_i32("locationy"sv).value_or(0) });
113 layer->set_opacity_percent(layer_object.get_i32("opacity_percent"sv).value());
114 layer->set_visible(layer_object.get_bool("visible"sv).value());
115 layer->set_selected(layer_object.get_bool("selected"sv).value());
116 }
117
118 return image;
119}
120
121ErrorOr<void> Image::serialize_as_json(JsonObjectSerializer<StringBuilder>& json) const
122{
123 TRY(json.add("width"sv, m_size.width()));
124 TRY(json.add("height"sv, m_size.height()));
125 {
126 auto json_layers = TRY(json.add_array("layers"sv));
127 for (auto const& layer : m_layers) {
128 auto json_layer = TRY(json_layers.add_object());
129 TRY(json_layer.add("width"sv, layer->size().width()));
130 TRY(json_layer.add("height"sv, layer->size().height()));
131 TRY(json_layer.add("name"sv, layer->name()));
132 TRY(json_layer.add("locationx"sv, layer->location().x()));
133 TRY(json_layer.add("locationy"sv, layer->location().y()));
134 TRY(json_layer.add("opacity_percent"sv, layer->opacity_percent()));
135 TRY(json_layer.add("visible"sv, layer->is_visible()));
136 TRY(json_layer.add("selected"sv, layer->is_selected()));
137 TRY(json_layer.add("bitmap"sv, TRY(encode_base64(TRY(Gfx::PNGWriter::encode(layer->content_bitmap()))))));
138 if (layer->is_masked())
139 TRY(json_layer.add("mask"sv, TRY(encode_base64(TRY(Gfx::PNGWriter::encode(*layer->mask_bitmap()))))));
140 TRY(json_layer.finish());
141 }
142
143 TRY(json_layers.finish());
144 }
145 return {};
146}
147
148ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Image::compose_bitmap(Gfx::BitmapFormat format) const
149{
150 auto bitmap = TRY(Gfx::Bitmap::create(format, m_size));
151 GUI::Painter painter(bitmap);
152 paint_into(painter, { 0, 0, m_size.width(), m_size.height() }, 1.0f);
153 return bitmap;
154}
155
156RefPtr<Gfx::Bitmap> Image::copy_bitmap(Selection const& selection) const
157{
158 if (selection.is_empty())
159 return {};
160 auto selection_rect = selection.bounding_rect();
161
162 // FIXME: Add a way to only compose a certain part of the image
163 auto bitmap_or_error = compose_bitmap(Gfx::BitmapFormat::BGRA8888);
164 if (bitmap_or_error.is_error())
165 return {};
166 auto full_bitmap = bitmap_or_error.release_value();
167
168 auto cropped_bitmap_or_error = full_bitmap->cropped(selection_rect);
169 if (cropped_bitmap_or_error.is_error())
170 return nullptr;
171 return cropped_bitmap_or_error.release_value_but_fixme_should_propagate_errors();
172}
173
174ErrorOr<void> Image::export_bmp_to_file(NonnullOwnPtr<Stream> stream, bool preserve_alpha_channel) const
175{
176 auto bitmap_format = preserve_alpha_channel ? Gfx::BitmapFormat::BGRA8888 : Gfx::BitmapFormat::BGRx8888;
177 auto bitmap = TRY(compose_bitmap(bitmap_format));
178
179 auto encoded_data = TRY(Gfx::BMPWriter::encode(*bitmap));
180 TRY(stream->write_until_depleted(encoded_data));
181 return {};
182}
183
184ErrorOr<void> Image::export_png_to_file(NonnullOwnPtr<Stream> stream, bool preserve_alpha_channel) const
185{
186 auto bitmap_format = preserve_alpha_channel ? Gfx::BitmapFormat::BGRA8888 : Gfx::BitmapFormat::BGRx8888;
187 auto bitmap = TRY(compose_bitmap(bitmap_format));
188
189 auto encoded_data = TRY(Gfx::PNGWriter::encode(*bitmap));
190 TRY(stream->write_until_depleted(encoded_data));
191 return {};
192}
193
194ErrorOr<void> Image::export_qoi_to_file(NonnullOwnPtr<Stream> stream) const
195{
196 auto bitmap = TRY(compose_bitmap(Gfx::BitmapFormat::BGRA8888));
197
198 auto encoded_data = TRY(Gfx::QOIWriter::encode(bitmap));
199 TRY(stream->write_until_depleted(encoded_data));
200 return {};
201}
202
203void Image::add_layer(NonnullRefPtr<Layer> layer)
204{
205 for (auto& existing_layer : m_layers) {
206 VERIFY(existing_layer != layer);
207 }
208 m_layers.append(move(layer));
209
210 for (auto* client : m_clients)
211 client->image_did_add_layer(m_layers.size() - 1);
212
213 did_modify_layer_stack();
214}
215
216ErrorOr<NonnullRefPtr<Image>> Image::take_snapshot() const
217{
218 auto snapshot = TRY(create_with_size(m_size));
219 for (auto const& layer : m_layers) {
220 auto layer_snapshot = TRY(Layer::create_snapshot(*snapshot, layer));
221 snapshot->add_layer(move(layer_snapshot));
222 }
223 snapshot->m_selection.set_mask(m_selection.mask());
224 return snapshot;
225}
226
227ErrorOr<void> Image::restore_snapshot(Image const& snapshot)
228{
229 m_layers.clear();
230 select_layer(nullptr);
231
232 bool layer_selected = false;
233 for (auto const& snapshot_layer : snapshot.m_layers) {
234 auto layer = TRY(Layer::create_snapshot(*this, snapshot_layer));
235 if (layer->is_selected()) {
236 select_layer(layer.ptr());
237 layer_selected = true;
238 }
239 layer->did_modify_bitmap({}, Layer::NotifyClients::No);
240 add_layer(*layer);
241 }
242
243 if (!layer_selected)
244 select_layer(&layer(0));
245
246 m_size = snapshot.size();
247
248 m_selection.set_mask(snapshot.m_selection.mask());
249
250 did_change_rect();
251 did_modify_layer_stack();
252 return {};
253}
254
255size_t Image::index_of(Layer const& layer) const
256{
257 for (size_t i = 0; i < m_layers.size(); ++i) {
258 if (m_layers[i] == &layer)
259 return i;
260 }
261 VERIFY_NOT_REACHED();
262}
263
264void Image::move_layer_to_back(Layer& layer)
265{
266 NonnullRefPtr<Layer> protector(layer);
267 auto index = index_of(layer);
268 m_layers.remove(index);
269 m_layers.prepend(layer);
270
271 did_modify_layer_stack();
272}
273
274void Image::move_layer_to_front(Layer& layer)
275{
276 NonnullRefPtr<Layer> protector(layer);
277 auto index = index_of(layer);
278 m_layers.remove(index);
279 m_layers.append(layer);
280
281 did_modify_layer_stack();
282}
283
284void Image::move_layer_down(Layer& layer)
285{
286 NonnullRefPtr<Layer> protector(layer);
287 auto index = index_of(layer);
288 if (!index)
289 return;
290 m_layers.remove(index);
291 m_layers.insert(index - 1, layer);
292
293 did_modify_layer_stack();
294}
295
296void Image::move_layer_up(Layer& layer)
297{
298 NonnullRefPtr<Layer> protector(layer);
299 auto index = index_of(layer);
300 if (index == m_layers.size() - 1)
301 return;
302 m_layers.remove(index);
303 m_layers.insert(index + 1, layer);
304
305 did_modify_layer_stack();
306}
307
308void Image::change_layer_index(size_t old_index, size_t new_index)
309{
310 VERIFY(old_index < m_layers.size());
311 VERIFY(new_index < m_layers.size());
312 auto layer = m_layers.take(old_index);
313 m_layers.insert(new_index, move(layer));
314 did_modify_layer_stack();
315}
316
317void Image::did_modify_layer_stack()
318{
319 for (auto* client : m_clients)
320 client->image_did_modify_layer_stack();
321
322 did_change();
323}
324
325void Image::remove_layer(Layer& layer)
326{
327 NonnullRefPtr<Layer> protector(layer);
328 auto index = index_of(layer);
329 m_layers.remove(index);
330
331 for (auto* client : m_clients)
332 client->image_did_remove_layer(index);
333
334 did_modify_layer_stack();
335}
336
337ErrorOr<void> Image::flatten_all_layers()
338{
339 return merge_layers(LayerMergeMode::All);
340}
341
342ErrorOr<void> Image::merge_visible_layers()
343{
344 return merge_layers(LayerMergeMode::VisibleOnly);
345}
346
347ErrorOr<void> Image::merge_layers(LayerMergeMode layer_merge_mode)
348{
349 if (m_layers.size() < 2)
350 return {};
351
352 Vector<NonnullRefPtr<Layer>> new_layers;
353 Gfx::IntRect merged_layer_bounding_rect = {};
354 size_t bottom_layer_index = 0;
355 for (auto const& layer : m_layers) {
356 if (!layer->is_visible()) {
357 if (layer_merge_mode == LayerMergeMode::VisibleOnly)
358 TRY(new_layers.try_append(layer));
359 if (merged_layer_bounding_rect.is_empty())
360 bottom_layer_index++;
361 continue;
362 }
363 merged_layer_bounding_rect = merged_layer_bounding_rect.united(layer->relative_rect());
364 }
365
366 if (merged_layer_bounding_rect.is_empty())
367 return {};
368
369 NonnullRefPtr<Layer> bottom_layer = m_layers.at(bottom_layer_index);
370 NonnullRefPtr<Layer> merged_layer = bottom_layer;
371 if (!merged_layer->relative_rect().contains(merged_layer_bounding_rect)) {
372 merged_layer = TRY(Layer::create_with_size(*this, merged_layer_bounding_rect.size(), bottom_layer->name()));
373 merged_layer->set_location(merged_layer_bounding_rect.location());
374 }
375
376 GUI::Painter painter(merged_layer->content_bitmap());
377 if (merged_layer.ptr() != bottom_layer.ptr())
378 painter.blit(bottom_layer->location() - merged_layer->location(), bottom_layer->display_bitmap(), bottom_layer->rect(), static_cast<float>(bottom_layer->opacity_percent()) / 100.0f);
379 for (size_t index = bottom_layer_index + 1; index < m_layers.size(); index++) {
380 auto& layer = m_layers.at(index);
381 if (!layer->is_visible())
382 continue;
383 painter.blit(layer->location() - merged_layer->location(), layer->display_bitmap(), layer->rect(), static_cast<float>(layer->opacity_percent()) / 100.0f);
384 }
385
386 TRY(new_layers.try_append(merged_layer));
387 m_layers = move(new_layers);
388 select_layer(merged_layer.ptr());
389 did_modify_layer_stack();
390 return {};
391}
392
393ErrorOr<void> Image::merge_active_layer_up(Layer& layer)
394{
395 return merge_active_layer(layer, LayerMergeDirection::Up);
396}
397
398ErrorOr<void> Image::merge_active_layer_down(Layer& layer)
399{
400 return merge_active_layer(layer, LayerMergeDirection::Down);
401}
402
403ErrorOr<void> Image::merge_active_layer(NonnullRefPtr<Layer> const& layer, LayerMergeDirection layer_merge_direction)
404{
405 if (m_layers.size() < 2)
406 return {};
407
408 if (!layer->is_visible())
409 return Error::from_string_literal("Layer must be visible");
410
411 auto layer_index = index_of(layer);
412 auto direction = layer_merge_direction == LayerMergeDirection::Up ? 1 : -1;
413 ssize_t layer_to_merge_index = layer_index + direction;
414 ssize_t layer_count = m_layers.size();
415
416 if (layer_to_merge_index < 0)
417 return Error::from_string_literal("Layer is already at the bottom");
418 if (layer_to_merge_index >= layer_count)
419 return Error::from_string_literal("Layer is already at the top");
420
421 Optional<NonnullRefPtr<Layer>> maybe_adjacent_layer;
422 while (layer_to_merge_index >= 0 && layer_to_merge_index < layer_count) {
423 auto const& layer = *m_layers[layer_to_merge_index];
424 if (layer.is_visible()) {
425 maybe_adjacent_layer = layer;
426 break;
427 }
428 layer_to_merge_index += direction;
429 }
430
431 if (!maybe_adjacent_layer.has_value()) {
432 auto error_message = layer_merge_direction == LayerMergeDirection::Up ? "No visible layers above this layer"sv : "No visible layers below this layer"sv;
433 return Error::from_string_view(error_message);
434 }
435
436 auto adjacent_layer = maybe_adjacent_layer.value();
437 auto bottom_layer = layer_merge_direction == LayerMergeDirection::Down ? adjacent_layer : layer;
438 auto top_layer = layer_merge_direction == LayerMergeDirection::Down ? layer : adjacent_layer;
439 auto merged_layer_bounding_rect = bottom_layer->relative_rect().united(top_layer->relative_rect());
440 auto merged_layer = bottom_layer;
441 if (!bottom_layer->relative_rect().contains(top_layer->relative_rect())) {
442 merged_layer = TRY(Layer::create_with_size(*this, merged_layer_bounding_rect.size(), adjacent_layer->name()));
443 merged_layer->set_location(merged_layer_bounding_rect.location());
444 } else if (merged_layer.ptr() != adjacent_layer.ptr()) {
445 merged_layer->set_name(adjacent_layer->name());
446 }
447
448 GUI::Painter painter(merged_layer->content_bitmap());
449 if (merged_layer.ptr() != bottom_layer.ptr())
450 painter.blit(bottom_layer->location() - merged_layer->location(), bottom_layer->display_bitmap(), bottom_layer->rect(), static_cast<float>(bottom_layer->opacity_percent()) / 100.0f);
451 painter.blit(top_layer->location() - merged_layer->location(), top_layer->display_bitmap(), top_layer->rect(), static_cast<float>(top_layer->opacity_percent()) / 100.0f);
452
453 auto top_layer_index = max(layer_index, layer_to_merge_index);
454 auto bottom_layer_index = min(layer_index, layer_to_merge_index);
455 m_layers.remove(top_layer_index);
456 m_layers.remove(bottom_layer_index);
457 m_layers.insert(top_layer_index - 1, merged_layer);
458 select_layer(merged_layer);
459 did_modify_layer_stack();
460 return {};
461}
462
463void Image::select_layer(Layer* layer)
464{
465 for (auto* client : m_clients)
466 client->image_select_layer(layer);
467}
468
469void Image::add_client(ImageClient& client)
470{
471 VERIFY(!m_clients.contains(&client));
472 m_clients.set(&client);
473}
474
475void Image::remove_client(ImageClient& client)
476{
477 VERIFY(m_clients.contains(&client));
478 m_clients.remove(&client);
479}
480
481void Image::layer_did_modify_bitmap(Badge<Layer>, Layer const& layer, Gfx::IntRect const& modified_layer_rect)
482{
483 auto layer_index = index_of(layer);
484 for (auto* client : m_clients)
485 client->image_did_modify_layer_bitmap(layer_index);
486
487 did_change(modified_layer_rect.translated(layer.location()));
488}
489
490void Image::layer_did_modify_properties(Badge<Layer>, Layer const& layer)
491{
492 auto layer_index = index_of(layer);
493 for (auto* client : m_clients)
494 client->image_did_modify_layer_properties(layer_index);
495
496 did_change();
497}
498
499void Image::did_change(Gfx::IntRect const& a_modified_rect)
500{
501 auto modified_rect = a_modified_rect.is_empty() ? this->rect() : a_modified_rect;
502 for (auto* client : m_clients)
503 client->image_did_change(modified_rect);
504}
505
506void Image::did_change_rect(Gfx::IntRect const& a_modified_rect)
507{
508 auto modified_rect = a_modified_rect.is_empty() ? this->rect() : a_modified_rect;
509 for (auto* client : m_clients)
510 client->image_did_change_rect(modified_rect);
511}
512
513ImageUndoCommand::ImageUndoCommand(Image& image, DeprecatedString action_text)
514 : m_snapshot(image.take_snapshot().release_value_but_fixme_should_propagate_errors())
515 , m_image(image)
516 , m_action_text(move(action_text))
517{
518}
519
520void ImageUndoCommand::undo()
521{
522 // FIXME: Handle errors.
523 (void)m_image.restore_snapshot(*m_snapshot);
524}
525
526void ImageUndoCommand::redo()
527{
528 undo();
529}
530
531ErrorOr<void> Image::flip(Gfx::Orientation orientation)
532{
533 Vector<NonnullRefPtr<Layer>> flipped_layers;
534 TRY(flipped_layers.try_ensure_capacity(m_layers.size()));
535
536 VERIFY(m_layers.size() > 0);
537
538 size_t selected_layer_index = 0;
539 for (size_t i = 0; i < m_layers.size(); ++i) {
540 auto& layer = m_layers[i];
541 auto new_layer = TRY(Layer::create_snapshot(*this, layer));
542
543 if (layer->is_selected())
544 selected_layer_index = i;
545
546 TRY(new_layer->flip(orientation, Layer::NotifyClients::No));
547
548 flipped_layers.unchecked_append(new_layer);
549 }
550
551 m_layers = move(flipped_layers);
552 for (auto& layer : m_layers)
553 layer->did_modify_bitmap({}, Layer::NotifyClients::No);
554
555 select_layer(m_layers[selected_layer_index]);
556
557 did_change();
558
559 return {};
560}
561
562ErrorOr<void> Image::rotate(Gfx::RotationDirection direction)
563{
564 Vector<NonnullRefPtr<Layer>> rotated_layers;
565 TRY(rotated_layers.try_ensure_capacity(m_layers.size()));
566
567 VERIFY(m_layers.size() > 0);
568
569 size_t selected_layer_index = 0;
570 for (size_t i = 0; i < m_layers.size(); ++i) {
571 auto& layer = m_layers[i];
572 auto new_layer = TRY(Layer::create_snapshot(*this, layer));
573
574 if (layer->is_selected())
575 selected_layer_index = i;
576
577 TRY(new_layer->rotate(direction, Layer::NotifyClients::No));
578
579 rotated_layers.unchecked_append(new_layer);
580 }
581
582 m_layers = move(rotated_layers);
583 for (auto& layer : m_layers)
584 layer->did_modify_bitmap({}, Layer::NotifyClients::Yes);
585
586 select_layer(m_layers[selected_layer_index]);
587
588 m_size = { m_size.height(), m_size.width() };
589 did_change_rect();
590
591 return {};
592}
593
594ErrorOr<void> Image::crop(Gfx::IntRect const& cropped_rect)
595{
596 Vector<NonnullRefPtr<Layer>> cropped_layers;
597 TRY(cropped_layers.try_ensure_capacity(m_layers.size()));
598
599 VERIFY(m_layers.size() > 0);
600
601 size_t selected_layer_index = 0;
602 for (size_t i = 0; i < m_layers.size(); ++i) {
603 auto& layer = m_layers[i];
604 auto new_layer = TRY(Layer::create_snapshot(*this, layer));
605
606 if (layer->is_selected())
607 selected_layer_index = i;
608
609 auto layer_location = new_layer->location();
610 auto layer_local_crop_rect = new_layer->relative_rect().intersected(cropped_rect).translated(-layer_location.x(), -layer_location.y());
611 TRY(new_layer->crop(layer_local_crop_rect, Layer::NotifyClients::No));
612
613 auto new_layer_x = max(0, layer_location.x() - cropped_rect.x());
614 auto new_layer_y = max(0, layer_location.y() - cropped_rect.y());
615
616 new_layer->set_location({ new_layer_x, new_layer_y });
617
618 cropped_layers.unchecked_append(new_layer);
619 }
620
621 m_layers = move(cropped_layers);
622 for (auto& layer : m_layers)
623 layer->did_modify_bitmap({}, Layer::NotifyClients::Yes);
624
625 select_layer(m_layers[selected_layer_index]);
626
627 m_size = { cropped_rect.width(), cropped_rect.height() };
628 did_change_rect(cropped_rect);
629
630 return {};
631}
632
633Optional<Gfx::IntRect> Image::nonempty_content_bounding_rect() const
634{
635 if (m_layers.is_empty())
636 return {};
637
638 Optional<Gfx::IntRect> bounding_rect;
639 for (auto const& layer : m_layers) {
640 auto layer_content_rect_in_layer_coordinates = layer->nonempty_content_bounding_rect();
641 if (!layer_content_rect_in_layer_coordinates.has_value())
642 continue;
643 auto layer_content_rect_in_image_coordinates = layer_content_rect_in_layer_coordinates->translated(layer->location());
644 if (!bounding_rect.has_value())
645 bounding_rect = layer_content_rect_in_image_coordinates;
646 else
647 bounding_rect = bounding_rect->united(layer_content_rect_in_image_coordinates);
648 }
649
650 return bounding_rect;
651}
652
653ErrorOr<void> Image::resize(Gfx::IntSize new_size, Gfx::Painter::ScalingMode scaling_mode)
654{
655 float scale_x = 1.0f;
656 float scale_y = 1.0f;
657
658 if (size().width() != 0.0f) {
659 scale_x = new_size.width() / static_cast<float>(size().width());
660 }
661
662 if (size().height() != 0.0f) {
663 scale_y = new_size.height() / static_cast<float>(size().height());
664 }
665
666 Vector<NonnullRefPtr<Layer>> resized_layers;
667 TRY(resized_layers.try_ensure_capacity(m_layers.size()));
668
669 VERIFY(m_layers.size() > 0);
670
671 size_t selected_layer_index = 0;
672 for (size_t i = 0; i < m_layers.size(); ++i) {
673 auto& layer = m_layers[i];
674 auto new_layer = TRY(Layer::create_snapshot(*this, layer));
675
676 if (layer->is_selected())
677 selected_layer_index = i;
678
679 Gfx::IntPoint new_location(scale_x * new_layer->location().x(), scale_y * new_layer->location().y());
680 TRY(new_layer->resize(new_size, new_location, scaling_mode, Layer::NotifyClients::No));
681
682 resized_layers.unchecked_append(new_layer);
683 }
684
685 m_layers = move(resized_layers);
686 for (auto& layer : m_layers)
687 layer->did_modify_bitmap({}, Layer::NotifyClients::Yes);
688
689 select_layer(m_layers[selected_layer_index]);
690
691 m_size = { new_size.width(), new_size.height() };
692 did_change_rect();
693
694 return {};
695}
696
697Color Image::color_at(Gfx::IntPoint point) const
698{
699 Color color;
700 for (auto const& layer : m_layers) {
701 if (!layer->is_visible() || !layer->rect().contains(point))
702 continue;
703
704 auto layer_color = layer->display_bitmap().get_pixel(point);
705 float layer_opacity = layer->opacity_percent() / 100.0f;
706 layer_color.set_alpha((u8)(layer_color.alpha() * layer_opacity));
707 color = color.blend(layer_color);
708 }
709 return color;
710}
711
712}