Coverage Report

Created: 2026-05-16 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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>) const
Gfx::Detail::ExifOrientedBitmap<Gfx::Bitmap>::oriented_position(Gfx::Point<int>)::{lambda(Gfx::Point<int>)#1}::operator()(Gfx::Point<int>) const
Line
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>) const
Unexecuted 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
}