1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 05:07:35 +00:00

ICC+image: Add conversion between color spaces for images :^)

For now, only for color spaces that are supported by Profile::to_pcs()
and Profile::from_pcs(), which currently means that all matrix profiles
(but not LUT profiles) in the source color space work, and that
matrix profiles with parametric curves in the destination color
space work.

This adds Profile::convert_image(Bitmap, source_profile), and
adds a `--convert-to-color-profile file.icc` flag to `image`.

It only takes a file path, so to use it with the built-in
sRGB profile, you have to write it to a file first:

% Build/lagom/icc -n sRGB --reencode-to serenity-sRGB.icc

`image` by default writes the source image's color profile
to the output image, and most image viewers display images
looking at the profile.

For example, take `Seven_Coloured_Pencils_(rg-switch_sRGB).jpg`
from https://commons.wikimedia.org/wiki/User:Colin/BrowserTest.

It looks normal in image viewers because they apply the unusual
profile embedded in the profile. But if you run

% Build/lagom/image -o huh.png --strip-color-profile \
    'Seven_Coloured_Pencils_(rg-switch_sRGB).jpeg'

and then look at huh.png, you can see how the image's colors
look like when interpreted as sRGB (which is the color space
PNG data is in if the PNG doesn't store an embedded profile).

If you now run

% Build/lagom/image -o wow.png \
    --convert-to-color-profile serenity-sRGB.icc --strip-color-profile \
    'Seven_Coloured_Pencils_(rg-switch_sRGB).jpeg'

this will convert that image to sRGB, but then not write
the profile to the output image (verify with `Build/lagom/icc wow.png`).
It will look correct in image viewers, since they display PNGs without
an embedded color profile as sRGB.

(This works because 'Seven_Coloured_Pencils_(rg-switch_sRGB).jpeg'
contains a matrix profile, and Serenity's built-in sRGB profile
uses a matrix profile with a parametric curve.)
This commit is contained in:
Nico Weber 2023-05-01 15:42:29 -04:00 committed by Andreas Kling
parent 09d698e0a0
commit 926c0d8676
3 changed files with 40 additions and 0 deletions

View file

@ -1664,6 +1664,23 @@ ErrorOr<CIELAB> Profile::to_lab(ReadonlyBytes color) const
return CIELAB { L, a, b };
}
ErrorOr<void> Profile::convert_image(Gfx::Bitmap& bitmap, Profile const& source_profile) const
{
// FIXME: Convert XYZ<->Lab conversion when needed.
// Currently, to_pcs() and from_pcs() are only implemented for matrix profiles, which are always XYZ anyways.
if (connection_space() != source_profile.connection_space())
return Error::from_string_literal("ICC::Profile::convert_image: mismatching profile connection spaces not yet implemented");
for (auto& pixel : bitmap) {
u8 rgb[] = { Color::from_argb(pixel).red(), Color::from_argb(pixel).green(), Color::from_argb(pixel).blue() };
auto pcs = TRY(source_profile.to_pcs(rgb));
TRY(from_pcs(pcs, rgb));
pixel = Color(rgb[0], rgb[1], rgb[2], Color::from_argb(pixel).alpha()).value();
}
return {};
}
XYZ const& Profile::red_matrix_column() const { return xyz_data(redMatrixColumnTag); }
XYZ const& Profile::green_matrix_column() const { return xyz_data(greenMatrixColumnTag); }
XYZ const& Profile::blue_matrix_column() const { return xyz_data(blueMatrixColumnTag); }