Coverage Report

Created: 2025-09-05 06:52

/src/serenity/Userland/Libraries/LibGfx/ImageFormats/PNGShared.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2022, the SerenityOS developers.
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/Array.h>
10
#include <AK/Error.h>
11
#include <AK/SIMD.h>
12
#include <AK/SIMDMath.h>
13
14
namespace Gfx::PNG {
15
16
// https://www.w3.org/TR/PNG/#5PNG-file-signature
17
static constexpr Array<u8, 8> header = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 };
18
19
// https://www.w3.org/TR/PNG/#6Colour-values
20
enum class ColorType : u8 {
21
    Greyscale = 0,
22
    Truecolor = 2, // RGB
23
    IndexedColor = 3,
24
    GreyscaleWithAlpha = 4,
25
    TruecolorWithAlpha = 6,
26
};
27
28
// https://www.w3.org/TR/PNG/#9Filter-types
29
enum class FilterType : u8 {
30
    None,
31
    Sub,
32
    Up,
33
    Average,
34
    Paeth,
35
};
36
37
inline ErrorOr<FilterType> filter_type(u8 byte)
38
5.03M
{
39
5.03M
    if (byte <= 4)
40
5.03M
        return static_cast<FilterType>(byte);
41
0
    return Error::from_string_literal("PNGImageDecoderPlugin: Invalid PNG filter");
42
5.03M
}
43
44
// https://www.w3.org/TR/PNG/#9Filter-type-4-Paeth
45
ALWAYS_INLINE u8 paeth_predictor(u8 a, u8 b, u8 c)
46
3.67M
{
47
3.67M
    int p = a + b - c;
48
3.67M
    int pa = AK::abs(p - a);
49
3.67M
    int pb = AK::abs(p - b);
50
3.67M
    int pc = AK::abs(p - c);
51
3.67M
    if (pa <= pb && pa <= pc)
52
3.07M
        return a;
53
602k
    if (pb <= pc)
54
567k
        return b;
55
35.2k
    return c;
56
602k
}
57
58
ALWAYS_INLINE AK::SIMD::u8x4 paeth_predictor(AK::SIMD::u8x4 a, AK::SIMD::u8x4 b, AK::SIMD::u8x4 c)
59
0
{
60
0
    using namespace AK::SIMD;
61
0
    auto a16 = simd_cast<i16x4>(a);
62
0
    auto b16 = simd_cast<i16x4>(b);
63
0
    auto c16 = simd_cast<i16x4>(c);
64
0
65
0
    auto p16 = a16 + b16 - c16;
66
0
    auto pa16 = abs(p16 - a16);
67
0
    auto pb16 = abs(p16 - b16);
68
0
    auto pc16 = abs(p16 - c16);
69
0
70
0
    auto mask_a = simd_cast<u8x4>((pa16 <= pb16) & (pa16 <= pc16));
71
0
    auto mask_b = ~mask_a & simd_cast<u8x4>(pb16 <= pc16);
72
0
    auto mask_c = ~(mask_a | mask_b);
73
0
74
0
    return (a & mask_a) | (b & mask_b) | (c & mask_c);
75
0
}
76
77
};