mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 10:07:44 +00:00
LibGFX/PAM: Allow reading CMYK .pam files
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.
This commit is contained in:
parent
187862ebe0
commit
556addc5cb
3 changed files with 70 additions and 18 deletions
|
@ -19,30 +19,41 @@ ErrorOr<void> read_image_data(PAMLoadingContext& context)
|
||||||
bool is_rgb = context.format_details.depth == 3 && context.format_details.tupl_type == "RGB"sv;
|
bool is_rgb = context.format_details.depth == 3 && context.format_details.tupl_type == "RGB"sv;
|
||||||
bool is_rgba = context.format_details.depth == 4 && context.format_details.tupl_type == "RGB_ALPHA"sv;
|
bool is_rgba = context.format_details.depth == 4 && context.format_details.tupl_type == "RGB_ALPHA"sv;
|
||||||
|
|
||||||
if (!is_gray && !is_gray_alpha && !is_rgb && !is_rgba)
|
bool is_cmyk = context.format_details.depth == 4 && context.format_details.tupl_type == "CMYK"sv;
|
||||||
return Error::from_string_view("Unsupported PAM depth"sv);
|
|
||||||
|
|
||||||
TRY(create_bitmap(context));
|
if (!is_gray && !is_gray_alpha && !is_rgb && !is_rgba && !is_cmyk)
|
||||||
|
return Error::from_string_view("Unsupported PAM depth"sv);
|
||||||
|
|
||||||
auto& stream = *context.stream;
|
auto& stream = *context.stream;
|
||||||
|
|
||||||
for (u64 i = 0; i < context.width * context.height; ++i) {
|
if (is_cmyk) {
|
||||||
if (is_gray) {
|
context.format_details.cmyk_bitmap = TRY(CMYKBitmap::create_with_size({ context.width, context.height }));
|
||||||
Array<u8, 1> pixel;
|
CMYK* data = context.format_details.cmyk_bitmap.value()->begin();
|
||||||
TRY(stream.read_until_filled(pixel));
|
for (u64 i = 0; i < context.width * context.height; ++i) {
|
||||||
context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[0], pixel[0] });
|
|
||||||
} else if (is_gray_alpha) {
|
|
||||||
Array<u8, 2> pixel;
|
|
||||||
TRY(stream.read_until_filled(pixel));
|
|
||||||
context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[0], pixel[0], pixel[1] });
|
|
||||||
} else if (is_rgb) {
|
|
||||||
Array<u8, 3> pixel;
|
|
||||||
TRY(stream.read_until_filled(pixel));
|
|
||||||
context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[1], pixel[2] });
|
|
||||||
} else if (is_rgba) {
|
|
||||||
Array<u8, 4> pixel;
|
Array<u8, 4> pixel;
|
||||||
TRY(stream.read_until_filled(pixel));
|
TRY(stream.read_until_filled(pixel));
|
||||||
context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[1], pixel[2], pixel[3] });
|
data[i] = { pixel[0], pixel[1], pixel[2], pixel[3] };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TRY(create_bitmap(context));
|
||||||
|
for (u64 i = 0; i < context.width * context.height; ++i) {
|
||||||
|
if (is_gray) {
|
||||||
|
Array<u8, 1> pixel;
|
||||||
|
TRY(stream.read_until_filled(pixel));
|
||||||
|
context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[0], pixel[0] });
|
||||||
|
} else if (is_gray_alpha) {
|
||||||
|
Array<u8, 2> pixel;
|
||||||
|
TRY(stream.read_until_filled(pixel));
|
||||||
|
context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[0], pixel[0], pixel[1] });
|
||||||
|
} else if (is_rgb) {
|
||||||
|
Array<u8, 3> pixel;
|
||||||
|
TRY(stream.read_until_filled(pixel));
|
||||||
|
context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[1], pixel[2] });
|
||||||
|
} else if (is_rgba) {
|
||||||
|
Array<u8, 4> pixel;
|
||||||
|
TRY(stream.read_until_filled(pixel));
|
||||||
|
context.bitmap->set_pixel(i % context.width, i / context.width, { pixel[0], pixel[1], pixel[2], pixel[3] });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct PAM {
|
||||||
u16 max_val { 0 };
|
u16 max_val { 0 };
|
||||||
u16 depth { 0 };
|
u16 depth { 0 };
|
||||||
String tupl_type {};
|
String tupl_type {};
|
||||||
|
Optional<NonnullRefPtr<CMYKBitmap>> cmyk_bitmap {};
|
||||||
};
|
};
|
||||||
|
|
||||||
using PAMLoadingContext = PortableImageMapLoadingContext<PAM>;
|
using PAMLoadingContext = PortableImageMapLoadingContext<PAM>;
|
||||||
|
|
|
@ -62,6 +62,9 @@ public:
|
||||||
|
|
||||||
virtual ErrorOr<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) override;
|
virtual ErrorOr<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) override;
|
||||||
|
|
||||||
|
virtual NaturalFrameFormat natural_frame_format() const override;
|
||||||
|
virtual ErrorOr<NonnullRefPtr<CMYKBitmap>> cmyk_frame() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PortableImageDecoderPlugin(NonnullOwnPtr<SeekableStream> stream);
|
PortableImageDecoderPlugin(NonnullOwnPtr<SeekableStream> stream);
|
||||||
|
|
||||||
|
@ -126,8 +129,45 @@ ErrorOr<ImageFrameDescriptor> PortableImageDecoderPlugin<TContext>::frame(size_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (requires { TContext::FormatDetails::cmyk_bitmap; }) {
|
||||||
|
if (m_context->format_details.cmyk_bitmap.has_value())
|
||||||
|
m_context->bitmap = TRY(m_context->format_details.cmyk_bitmap.value()->to_low_quality_rgb());
|
||||||
|
}
|
||||||
|
|
||||||
VERIFY(m_context->bitmap);
|
VERIFY(m_context->bitmap);
|
||||||
return ImageFrameDescriptor { m_context->bitmap, 0 };
|
return ImageFrameDescriptor { m_context->bitmap, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename TContext>
|
||||||
|
NaturalFrameFormat PortableImageDecoderPlugin<TContext>::natural_frame_format() const
|
||||||
|
{
|
||||||
|
if constexpr (requires { TContext::FormatDetails::cmyk_bitmap; }) {
|
||||||
|
if (m_context->format_details.depth == 4 && m_context->format_details.tupl_type == "CMYK"sv)
|
||||||
|
return NaturalFrameFormat::CMYK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NaturalFrameFormat::RGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TContext>
|
||||||
|
ErrorOr<NonnullRefPtr<CMYKBitmap>> PortableImageDecoderPlugin<TContext>::cmyk_frame()
|
||||||
|
{
|
||||||
|
if constexpr (requires { TContext::FormatDetails::cmyk_bitmap; }) {
|
||||||
|
VERIFY(natural_frame_format() == NaturalFrameFormat::CMYK);
|
||||||
|
if (m_context->state == TContext::State::Error)
|
||||||
|
return Error::from_string_literal("PortableImageDecoderPlugin: Decoding failed");
|
||||||
|
|
||||||
|
if (m_context->state < TContext::State::BitmapDecoded) {
|
||||||
|
if (decode(*m_context).is_error()) {
|
||||||
|
m_context->state = TContext::State::Error;
|
||||||
|
return Error::from_string_literal("PortableImageDecoderPlugin: Decoding failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *m_context->format_details.cmyk_bitmap.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue