123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- /*
- * Copyright (c) 2024, the SerenityOS developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #pragma once
- #include <AK/StringView.h>
- #include <LibGfx/ImageFormats/ImageDecoder.h>
- #include <LibGfx/ImageFormats/PortableImageMapLoader.h>
- 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<NonnullRefPtr<CMYKBitmap>> cmyk_bitmap {};
- };
- using PAMLoadingContext = PortableImageMapLoadingContext<PAM>;
- template<class Context>
- ErrorOr<void> read_pam_header(Context& context)
- {
- // https://netpbm.sourceforge.net/doc/pam.html
- TRY(read_magic_number(context));
- Optional<u16> width;
- Optional<u16> height;
- Optional<u16> depth;
- Optional<u16> max_val;
- Optional<String> 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<u8>());
- 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<PAMLoadingContext>;
- ErrorOr<void> read_image_data(PAMLoadingContext& context);
- }
|