1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 09:04:59 +00:00

image: Add an --invert-cmyk option

This is useful for working with CMYK jpegs extracted from PDFs
by mutool. CMYK channels for jpegs in PDFs are inverted compared to
CMYK channels in standalone jpegs (!), and mutool doesn't compensate
for that.

You can now do:

    mutool extract  ~/Downloads/0000/0000711.pdf 461

Followed by:

    Build/lagom/bin/image -o out.png \
        --invert-cmyk \
        --assign-color-profile \
            Build/lagom/Root/res/icc/Adobe/CMYK/USWebCoatedSWOP.icc \
        --convert-to-color-profile serenity-sRGB.icc \
        cmyk.jpg

Doesn't exactly roll off the keyboard, but at least it's possible.

(We should probably add an implicit default CMYK color profile if
the input file doesn't have one, and assume conversion to sRGB when
saving to a format that can only store RGB.)
This commit is contained in:
Nico Weber 2024-02-02 19:41:08 -05:00 committed by Jelle Raaijmakers
parent fa3fead7a4
commit c4780f4ee1

View file

@ -42,6 +42,21 @@ static ErrorOr<LoadedImage> load_image(RefPtr<Gfx::ImageDecoder> const& decoder,
return LoadedImage { internal_format, move(bitmap), TRY(decoder->icc_data()) };
}
static ErrorOr<void> invert_cmyk(LoadedImage& image)
{
if (!image.bitmap.has<RefPtr<Gfx::CMYKBitmap>>())
return Error::from_string_view("Can't --invert-cmyk with RGB bitmaps"sv);
auto& frame = image.bitmap.get<RefPtr<Gfx::CMYKBitmap>>();
for (auto& pixel : *frame) {
pixel.c = ~pixel.c;
pixel.m = ~pixel.m;
pixel.y = ~pixel.y;
pixel.k = ~pixel.k;
}
return {};
}
static ErrorOr<void> move_alpha_to_rgb(LoadedImage& image)
{
if (!image.bitmap.has<RefPtr<Gfx::Bitmap>>())
@ -173,6 +188,7 @@ struct Options {
StringView out_path;
bool no_output = false;
int frame_index = 0;
bool invert_cmyk = false;
bool move_alpha_to_rgb = false;
bool strip_alpha = false;
StringView assign_color_profile_path;
@ -190,6 +206,7 @@ static ErrorOr<Options> parse_options(Main::Arguments arguments)
args_parser.add_option(options.out_path, "Path to output image file", "output", 'o', "FILE");
args_parser.add_option(options.no_output, "Do not write output (only useful for benchmarking image decoding)", "no-output", {});
args_parser.add_option(options.frame_index, "Which frame of a multi-frame input image (0-based)", "frame-index", {}, "INDEX");
args_parser.add_option(options.invert_cmyk, "Invert CMYK channels", "invert-cmyk", {});
args_parser.add_option(options.move_alpha_to_rgb, "Copy alpha channel to rgb, clear alpha", "move-alpha-to-rgb", {});
args_parser.add_option(options.strip_alpha, "Remove alpha channel", "strip-alpha", {});
args_parser.add_option(options.assign_color_profile_path, "Load color profile from file and assign it to output image", "assign-color-profile", {}, "FILE");
@ -216,6 +233,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
LoadedImage image = TRY(load_image(*decoder, options.frame_index));
if (options.invert_cmyk)
TRY(invert_cmyk(image));
if (options.move_alpha_to_rgb)
TRY(move_alpha_to_rgb(image));