/* * Copyright (c) 2024, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include namespace Gfx { struct PAM { static constexpr auto binary_magic_number = '7'; static constexpr StringView image_type = "PAM"sv; u16 max_val { 0 }; u16 depth { 0 }; String tupl_type {}; Optional> cmyk_bitmap {}; }; using PAMLoadingContext = PortableImageMapLoadingContext; template ErrorOr read_pam_header(Context& context) { // https://netpbm.sourceforge.net/doc/pam.html TRY(read_magic_number(context)); Optional width; Optional height; Optional depth; Optional max_val; Optional tupltype; while (true) { TRY(read_whitespace(context)); auto const token = TRY(read_token(*context.stream)); if (token == "ENDHDR") { auto newline = TRY(context.stream->template read_value()); if (newline != '\n') return Error::from_string_view("PAM ENDHDR not followed by newline"sv); break; } TRY(read_whitespace(context)); if (token == "WIDTH") { if (width.has_value()) return Error::from_string_view("Duplicate PAM WIDTH field"sv); width = TRY(read_number(*context.stream)); } else if (token == "HEIGHT") { if (height.has_value()) return Error::from_string_view("Duplicate PAM HEIGHT field"sv); height = TRY(read_number(*context.stream)); } else if (token == "DEPTH") { if (depth.has_value()) return Error::from_string_view("Duplicate PAM DEPTH field"sv); depth = TRY(read_number(*context.stream)); } else if (token == "MAXVAL") { if (max_val.has_value()) return Error::from_string_view("Duplicate PAM MAXVAL field"sv); max_val = TRY(read_number(*context.stream)); } else if (token == "TUPLTYPE") { // FIXME: tupltype should be all text until the next newline, with leading and trailing space stripped. // FIXME: If there are multipe TUPLTYPE lines, their values are all appended. tupltype = TRY(read_token(*context.stream)); } else { return Error::from_string_view("Unknown PAM token"sv); } } if (!width.has_value() || !height.has_value() || !depth.has_value() || !max_val.has_value()) return Error::from_string_view("Missing PAM header fields"sv); context.width = *width; context.height = *height; context.format_details.depth = *depth; context.format_details.max_val = *max_val; if (tupltype.has_value()) context.format_details.tupl_type = *tupltype; context.state = Context::State::HeaderDecoded; return {}; } using PAMImageDecoderPlugin = PortableImageDecoderPlugin; ErrorOr read_image_data(PAMLoadingContext& context); }