/src/serenity/Userland/Libraries/LibGfx/ImageFormats/ExifOrientedBitmap.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2023-2024, Lucas Chollet <lucas.chollet@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/Concepts.h> |
10 | | #include <AK/NonnullOwnPtr.h> |
11 | | #include <LibGfx/Bitmap.h> |
12 | | #include <LibGfx/ImageFormats/TIFFMetadata.h> |
13 | | |
14 | | namespace Gfx { |
15 | | |
16 | | namespace Detail { |
17 | | |
18 | | template<typename BitmapLike> |
19 | | class ExifOrientedBitmap { |
20 | | public: |
21 | | static ErrorOr<ExifOrientedBitmap> create(TIFF::Orientation orientation, IntSize size, BitmapFormat format) |
22 | | requires(SameAs<BitmapLike, Bitmap>) |
23 | 157 | { |
24 | 157 | auto bitmap = TRY(Bitmap::create(format, oriented_size(size, orientation))); |
25 | 153 | return ExifOrientedBitmap(move(bitmap), size, orientation); |
26 | 157 | } |
27 | | |
28 | | static ErrorOr<ExifOrientedBitmap> create(TIFF::Orientation orientation, IntSize size) |
29 | | requires(SameAs<BitmapLike, CMYKBitmap>) |
30 | 62 | { |
31 | 62 | auto bitmap = TRY(CMYKBitmap::create_with_size(oriented_size(size, orientation))); |
32 | 62 | return ExifOrientedBitmap(move(bitmap), size, orientation); |
33 | 62 | } |
34 | | |
35 | | template<OneOf<ARGB32, CMYK> Value> |
36 | | void set_pixel(u32 x, u32 y, Value color) |
37 | 4.62M | { |
38 | 4.62M | auto const new_position = oriented_position(IntPoint(x, y)); |
39 | 4.62M | m_bitmap->scanline(new_position.y())[new_position.x()] = color; |
40 | 4.62M | } _ZN3Gfx6Detail18ExifOrientedBitmapINS_10CMYKBitmapEE9set_pixelITkN2AK8Concepts5OneOfIjNS_4CMYKEEES8_EEvjjT_ Line | Count | Source | 37 | 73.0k | { | 38 | 73.0k | auto const new_position = oriented_position(IntPoint(x, y)); | 39 | 73.0k | m_bitmap->scanline(new_position.y())[new_position.x()] = color; | 40 | 73.0k | } |
_ZN3Gfx6Detail18ExifOrientedBitmapINS_6BitmapEE9set_pixelITkN2AK8Concepts5OneOfIjNS_4CMYKEEEjEEvjjT_ Line | Count | Source | 37 | 4.54M | { | 38 | 4.54M | auto const new_position = oriented_position(IntPoint(x, y)); | 39 | 4.54M | m_bitmap->scanline(new_position.y())[new_position.x()] = color; | 40 | 4.54M | } |
|
41 | | |
42 | | NonnullRefPtr<BitmapLike>& bitmap() |
43 | 15 | { |
44 | 15 | return m_bitmap; |
45 | 15 | } Unexecuted instantiation: Gfx::Detail::ExifOrientedBitmap<Gfx::CMYKBitmap>::bitmap() Gfx::Detail::ExifOrientedBitmap<Gfx::Bitmap>::bitmap() Line | Count | Source | 43 | 15 | { | 44 | 15 | return m_bitmap; | 45 | 15 | } |
|
46 | | |
47 | | static IntSize oriented_size(IntSize size, TIFF::Orientation orientation) |
48 | 219 | { |
49 | 219 | switch (orientation) { |
50 | 203 | case Orientation::Default: |
51 | 207 | case Orientation::FlipHorizontally: |
52 | 208 | case Orientation::Rotate180: |
53 | 215 | case Orientation::FlipVertically: |
54 | 215 | return size; |
55 | 0 | case Orientation::Rotate90ClockwiseThenFlipHorizontally: |
56 | 0 | case Orientation::Rotate90Clockwise: |
57 | 0 | case Orientation::FlipHorizontallyThenRotate90Clockwise: |
58 | 4 | case Orientation::Rotate90CounterClockwise: |
59 | 4 | return { size.height(), size.width() }; |
60 | 219 | } |
61 | 0 | VERIFY_NOT_REACHED(); |
62 | 0 | } Gfx::Detail::ExifOrientedBitmap<Gfx::CMYKBitmap>::oriented_size(Gfx::Size<int>, Gfx::TIFF::Orientation) Line | Count | Source | 48 | 62 | { | 49 | 62 | switch (orientation) { | 50 | 62 | case Orientation::Default: | 51 | 62 | case Orientation::FlipHorizontally: | 52 | 62 | case Orientation::Rotate180: | 53 | 62 | case Orientation::FlipVertically: | 54 | 62 | return size; | 55 | 0 | case Orientation::Rotate90ClockwiseThenFlipHorizontally: | 56 | 0 | case Orientation::Rotate90Clockwise: | 57 | 0 | case Orientation::FlipHorizontallyThenRotate90Clockwise: | 58 | 0 | case Orientation::Rotate90CounterClockwise: | 59 | 0 | return { size.height(), size.width() }; | 60 | 62 | } | 61 | 0 | VERIFY_NOT_REACHED(); | 62 | 0 | } |
Gfx::Detail::ExifOrientedBitmap<Gfx::Bitmap>::oriented_size(Gfx::Size<int>, Gfx::TIFF::Orientation) Line | Count | Source | 48 | 157 | { | 49 | 157 | switch (orientation) { | 50 | 141 | case Orientation::Default: | 51 | 145 | case Orientation::FlipHorizontally: | 52 | 146 | case Orientation::Rotate180: | 53 | 153 | case Orientation::FlipVertically: | 54 | 153 | return size; | 55 | 0 | case Orientation::Rotate90ClockwiseThenFlipHorizontally: | 56 | 0 | case Orientation::Rotate90Clockwise: | 57 | 0 | case Orientation::FlipHorizontallyThenRotate90Clockwise: | 58 | 4 | case Orientation::Rotate90CounterClockwise: | 59 | 4 | return { size.height(), size.width() }; | 60 | 157 | } | 61 | 0 | VERIFY_NOT_REACHED(); | 62 | 0 | } |
|
63 | | |
64 | | private: |
65 | | using Orientation = TIFF::Orientation; |
66 | | |
67 | | ExifOrientedBitmap(NonnullRefPtr<BitmapLike> bitmap, IntSize size, Orientation orientation) |
68 | 215 | : m_bitmap(move(bitmap)) |
69 | 215 | , m_orientation(orientation) |
70 | 215 | , m_width(size.width()) |
71 | 215 | , m_height(size.height()) |
72 | 215 | { |
73 | 215 | } Gfx::Detail::ExifOrientedBitmap<Gfx::CMYKBitmap>::ExifOrientedBitmap(AK::NonnullRefPtr<Gfx::CMYKBitmap>, Gfx::Size<int>, Gfx::TIFF::Orientation) Line | Count | Source | 68 | 62 | : m_bitmap(move(bitmap)) | 69 | 62 | , m_orientation(orientation) | 70 | 62 | , m_width(size.width()) | 71 | 62 | , m_height(size.height()) | 72 | 62 | { | 73 | 62 | } |
Gfx::Detail::ExifOrientedBitmap<Gfx::Bitmap>::ExifOrientedBitmap(AK::NonnullRefPtr<Gfx::Bitmap>, Gfx::Size<int>, Gfx::TIFF::Orientation) Line | Count | Source | 68 | 153 | : m_bitmap(move(bitmap)) | 69 | 153 | , m_orientation(orientation) | 70 | 153 | , m_width(size.width()) | 71 | 153 | , m_height(size.height()) | 72 | 153 | { | 73 | 153 | } |
|
74 | | |
75 | | IntPoint oriented_position(IntPoint point) |
76 | 4.62M | { |
77 | 4.62M | auto const flip_horizontally = [this](IntPoint point) { |
78 | 8.53k | return IntPoint(m_width - point.x() - 1, point.y()); |
79 | 8.53k | }; Unexecuted instantiation: Gfx::Detail::ExifOrientedBitmap<Gfx::CMYKBitmap>::oriented_position(Gfx::Point<int>)::{lambda(Gfx::Point<int>)#1}::operator()(Gfx::Point<int>) constGfx::Detail::ExifOrientedBitmap<Gfx::Bitmap>::oriented_position(Gfx::Point<int>)::{lambda(Gfx::Point<int>)#1}::operator()(Gfx::Point<int>) constLine | Count | Source | 77 | 8.53k | auto const flip_horizontally = [this](IntPoint point) { | 78 | 8.53k | return IntPoint(m_width - point.x() - 1, point.y()); | 79 | 8.53k | }; |
|
80 | | |
81 | 4.62M | auto const rotate_90_clockwise = [this](IntPoint point) { |
82 | 0 | return IntPoint(m_height - point.y() - 1, point.x()); |
83 | 0 | }; Unexecuted instantiation: Gfx::Detail::ExifOrientedBitmap<Gfx::CMYKBitmap>::oriented_position(Gfx::Point<int>)::{lambda(Gfx::Point<int>)#2}::operator()(Gfx::Point<int>) constUnexecuted instantiation: Gfx::Detail::ExifOrientedBitmap<Gfx::Bitmap>::oriented_position(Gfx::Point<int>)::{lambda(Gfx::Point<int>)#2}::operator()(Gfx::Point<int>) const |
84 | | |
85 | 4.62M | switch (m_orientation) { |
86 | 4.59M | case Orientation::Default: |
87 | 4.59M | return point; |
88 | 8.53k | case Orientation::FlipHorizontally: |
89 | 8.53k | return flip_horizontally(point); |
90 | 0 | case Orientation::Rotate180: |
91 | 0 | return IntPoint(m_width - point.x() - 1, m_height - point.y() - 1); |
92 | 18.7k | case Orientation::FlipVertically: |
93 | 18.7k | return IntPoint(point.x(), m_height - point.y() - 1); |
94 | 0 | case Orientation::Rotate90ClockwiseThenFlipHorizontally: |
95 | 0 | return flip_horizontally(rotate_90_clockwise(point)); |
96 | 0 | case Orientation::Rotate90Clockwise: |
97 | 0 | return rotate_90_clockwise(point); |
98 | 0 | case Orientation::FlipHorizontallyThenRotate90Clockwise: |
99 | 0 | return rotate_90_clockwise(flip_horizontally(point)); |
100 | 0 | case Orientation::Rotate90CounterClockwise: |
101 | 0 | return IntPoint(point.y(), m_width - point.x() - 1); |
102 | 4.62M | } |
103 | 0 | VERIFY_NOT_REACHED(); |
104 | 0 | } Gfx::Detail::ExifOrientedBitmap<Gfx::CMYKBitmap>::oriented_position(Gfx::Point<int>) Line | Count | Source | 76 | 73.0k | { | 77 | 73.0k | auto const flip_horizontally = [this](IntPoint point) { | 78 | 73.0k | return IntPoint(m_width - point.x() - 1, point.y()); | 79 | 73.0k | }; | 80 | | | 81 | 73.0k | auto const rotate_90_clockwise = [this](IntPoint point) { | 82 | 73.0k | return IntPoint(m_height - point.y() - 1, point.x()); | 83 | 73.0k | }; | 84 | | | 85 | 73.0k | switch (m_orientation) { | 86 | 73.0k | case Orientation::Default: | 87 | 73.0k | return point; | 88 | 0 | case Orientation::FlipHorizontally: | 89 | 0 | return flip_horizontally(point); | 90 | 0 | case Orientation::Rotate180: | 91 | 0 | return IntPoint(m_width - point.x() - 1, m_height - point.y() - 1); | 92 | 0 | case Orientation::FlipVertically: | 93 | 0 | return IntPoint(point.x(), m_height - point.y() - 1); | 94 | 0 | case Orientation::Rotate90ClockwiseThenFlipHorizontally: | 95 | 0 | return flip_horizontally(rotate_90_clockwise(point)); | 96 | 0 | case Orientation::Rotate90Clockwise: | 97 | 0 | return rotate_90_clockwise(point); | 98 | 0 | case Orientation::FlipHorizontallyThenRotate90Clockwise: | 99 | 0 | return rotate_90_clockwise(flip_horizontally(point)); | 100 | 0 | case Orientation::Rotate90CounterClockwise: | 101 | 0 | return IntPoint(point.y(), m_width - point.x() - 1); | 102 | 73.0k | } | 103 | 0 | VERIFY_NOT_REACHED(); | 104 | 0 | } |
Gfx::Detail::ExifOrientedBitmap<Gfx::Bitmap>::oriented_position(Gfx::Point<int>) Line | Count | Source | 76 | 4.54M | { | 77 | 4.54M | auto const flip_horizontally = [this](IntPoint point) { | 78 | 4.54M | return IntPoint(m_width - point.x() - 1, point.y()); | 79 | 4.54M | }; | 80 | | | 81 | 4.54M | auto const rotate_90_clockwise = [this](IntPoint point) { | 82 | 4.54M | return IntPoint(m_height - point.y() - 1, point.x()); | 83 | 4.54M | }; | 84 | | | 85 | 4.54M | switch (m_orientation) { | 86 | 4.52M | case Orientation::Default: | 87 | 4.52M | return point; | 88 | 8.53k | case Orientation::FlipHorizontally: | 89 | 8.53k | return flip_horizontally(point); | 90 | 0 | case Orientation::Rotate180: | 91 | 0 | return IntPoint(m_width - point.x() - 1, m_height - point.y() - 1); | 92 | 18.7k | case Orientation::FlipVertically: | 93 | 18.7k | return IntPoint(point.x(), m_height - point.y() - 1); | 94 | 0 | case Orientation::Rotate90ClockwiseThenFlipHorizontally: | 95 | 0 | return flip_horizontally(rotate_90_clockwise(point)); | 96 | 0 | case Orientation::Rotate90Clockwise: | 97 | 0 | return rotate_90_clockwise(point); | 98 | 0 | case Orientation::FlipHorizontallyThenRotate90Clockwise: | 99 | 0 | return rotate_90_clockwise(flip_horizontally(point)); | 100 | 0 | case Orientation::Rotate90CounterClockwise: | 101 | 0 | return IntPoint(point.y(), m_width - point.x() - 1); | 102 | 4.54M | } | 103 | 0 | VERIFY_NOT_REACHED(); | 104 | 0 | } |
|
105 | | |
106 | | NonnullRefPtr<BitmapLike> m_bitmap; |
107 | | Orientation m_orientation; |
108 | | |
109 | | u32 m_width {}; |
110 | | u32 m_height {}; |
111 | | }; |
112 | | |
113 | | } |
114 | | |
115 | | using ExifOrientedBitmap = Detail::ExifOrientedBitmap<Bitmap>; |
116 | | using ExifOrientedCMYKBitmap = Detail::ExifOrientedBitmap<CMYKBitmap>; |
117 | | |
118 | | } |