mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 13:00:29 +03:00
556addc5cb
These are written by `mutool extract` for CMYK images. They don't contain color profiles so they're not super convenient. But `image` can convert them (*) to sRGB as long as you use it with `--assign-color-profile` pointing to some CMYK icc profile of your choice. *: Once #22922 is merged.
94 lines
3.1 KiB
C++
94 lines
3.1 KiB
C++
/*
|
|
* 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);
|
|
}
|