/src/serenity/Userland/Libraries/LibGfx/ImageFormats/PAMLoader.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2024, the SerenityOS developers. |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include "PAMLoader.h" |
8 | | #include "PortableImageLoaderCommon.h" |
9 | | |
10 | | namespace Gfx { |
11 | | |
12 | | ErrorOr<void> read_image_data(PAMLoadingContext& context) |
13 | 640 | { |
14 | 640 | VERIFY(context.type == PAMLoadingContext::Type::RAWBITS); |
15 | | |
16 | | // FIXME: Technically it's more to spec to check that a known tupl type has a minimum depth and then skip additional channels. |
17 | 640 | bool is_gray = context.format_details.depth == 1 && context.format_details.tupl_type == "GRAYSCALE"sv; |
18 | 640 | bool is_gray_alpha = context.format_details.depth == 2 && context.format_details.tupl_type == "GRAYSCALE_ALPHA"sv; |
19 | 640 | bool is_rgb = context.format_details.depth == 3 && context.format_details.tupl_type == "RGB"sv; |
20 | 640 | bool is_rgba = context.format_details.depth == 4 && context.format_details.tupl_type == "RGB_ALPHA"sv; |
21 | | |
22 | 640 | bool is_cmyk = context.format_details.depth == 4 && context.format_details.tupl_type == "CMYK"sv; |
23 | | |
24 | 640 | if (!is_gray && !is_gray_alpha && !is_rgb && !is_rgba && !is_cmyk) |
25 | 192 | return Error::from_string_view("Unsupported PAM depth"sv); |
26 | | |
27 | 448 | auto& stream = *context.stream; |
28 | | |
29 | 448 | if (is_cmyk) { |
30 | 153 | context.format_details.cmyk_bitmap = TRY(CMYKBitmap::create_with_size({ context.width, context.height })); |
31 | 0 | CMYK* data = context.format_details.cmyk_bitmap.value()->begin(); |
32 | 205k | for (u64 i = 0; i < context.width * context.height; ++i) { |
33 | 205k | Array<u8, 4> pixel; |
34 | 205k | TRY(stream.read_until_filled(pixel)); |
35 | 0 | data[i] = { pixel[0], pixel[1], pixel[2], pixel[3] }; |
36 | 205k | } |
37 | 295 | } else { |
38 | 295 | TRY(create_bitmap(context)); |
39 | 319k | for (u64 i = 0; i < context.width * context.height; ++i) { |
40 | 319k | if (is_gray) { |
41 | 65.4k | Array<u8, 1> pixel; |
42 | 65.4k | TRY(stream.read_until_filled(pixel)); |
43 | 0 | context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[0], pixel[0] }); |
44 | 253k | } else if (is_gray_alpha) { |
45 | 65.4k | Array<u8, 2> pixel; |
46 | 65.4k | TRY(stream.read_until_filled(pixel)); |
47 | 0 | context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[0], pixel[0], pixel[1] }); |
48 | 188k | } else if (is_rgb) { |
49 | 116k | Array<u8, 3> pixel; |
50 | 116k | TRY(stream.read_until_filled(pixel)); |
51 | 0 | context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[1], pixel[2] }); |
52 | 116k | } else if (is_rgba) { |
53 | 71.6k | Array<u8, 4> pixel; |
54 | 71.6k | TRY(stream.read_until_filled(pixel)); |
55 | 0 | context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[1], pixel[2], pixel[3] }); |
56 | 71.6k | } |
57 | 319k | } |
58 | 288 | } |
59 | | |
60 | 71 | return {}; |
61 | 448 | } |
62 | | } |