Commit graph

47 commits

Author SHA1 Message Date
Nico Weber
0079fad785 ICC: Prepare for eventually implementing conversions for LUT profiles
No behavior change yet (except for more detailed "not yet implemented"
messages), but it prepares for eventually implementing some of this.
2023-05-04 16:11:07 +02:00
Nico Weber
9c3e36e72c ICC: Implement TRC inversion in from_pcs for point curves
This allows converting to a color space that uses a non-parametric
curve, for example:

    Build/lagom/image -o foo.png \
        --convert-to-color-profile .../profiles/sRGB-v2-micro.icc \
        input.jpg

...where profiles/sRGB-v2-micro.icc is from
https://github.com/saucecontrol/Compact-ICC-Profiles/

(Parametric curves are new in ICC v4, which means all v2 profiles
use point curves.)
2023-05-03 15:05:13 +02:00
Nico Weber
926c0d8676 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.)
2023-05-03 15:05:13 +02:00
Nico Weber
9bd35fda56 ICC: Implement TRC inversion in from_pcs for parametric curves 2023-05-02 17:15:48 +01:00
Nico Weber
4169c94ebe ICC: Implement some of Profile::from_pcs()
This implements conversion from profile connection space to the
device-dependent color for matrix-based profiles.

It only does the inverse color transform but does not yet do the
inverse tone reproduction curve transform -- i.e. it doesn't
implement many cases (LUT transforms), and it does the one thing
it does implement incorrectly. But to vindicate the commit a bit,
it also does the incorrect thing very inefficiently.
2023-05-02 17:15:48 +01:00
Nico Weber
2319b2ffb5 ICC: Use snake_case instead of matching spec's camelCase in to_pcs() 2023-05-02 17:15:48 +01:00
Nico Weber
82bd7c33d1 ICC: Make a "not yet implemented" string more precise 2023-05-02 17:15:48 +01:00
Nico Weber
103f818afc ICC: Rename tag_for_rendering_intent()
To make clear it's for forward transforms, it's now called
forward_transform_tag_for_rendering_intent().

No behavior change.
2023-05-02 17:15:48 +01:00
Nico Weber
8ab6e0d3a5 ICC: Mark Profile::to_pcs() and to_lab() const 2023-04-30 05:57:20 +02:00
Nico Weber
adec1abf81 LibGfx: Move CIELAB to its own file 2023-04-30 05:57:20 +02:00
Nico Weber
f3dbfb85d9 ICC: Add Profile::to_lab()
This can be used to convert a profile-dependent color to the L*a*b*
color space.

(I'd like to use this to implement the DeltaE (CIE 2000) algorithm,
which is a metric for how similar two colors are perceived.
(And I'd like to use that to evaluate color conversion roundtrip
quality, once I've implemented full conversions.)
2023-04-30 00:46:11 +02:00
Nico Weber
ab98ad4e70 ICC: Add a missing " at the end of a comment 2023-04-29 06:49:36 +02:00
Nico Weber
227072a5af ICC: Rename XYZ and XYZNumber fields to uppercase
Given that XYZ and xyz are distinct things, let's use the correct
case for these member variables.

No behavior change.
2023-04-29 06:49:36 +02:00
Nico Weber
af453b246a ICC: Add method to convert a color to the profile connection space
Only implemented for matrix profiles so far.

This API won't be fast enough to color manage images, but let's
get something working before getting something fast.
2023-04-29 06:49:36 +02:00
Nico Weber
e76d2238bb ICC: Make number_of_components_in_color_space() external
...and make its return type unsigned.
2023-04-29 06:49:36 +02:00
Nico Weber
1f0b54c857 LibGfx: Limit ICC-size-is-multiple-of-4 check to v4 files
The v2 spec doesn't require it, and it's not true in practice
(e.g. Compact-ICC-Profiles/profiles/sRGB-v2-nano.icc has size 410).
2023-04-09 16:49:49 +02:00
Nico Weber
8f415e7b21 LibGfx: Introduce ICC::Profile::create
This can be used to programmatically create ICC::Profile objects.
2023-03-04 21:38:47 +00:00
Nico Weber
b161f5ea05 LibGfx: Make ICC reader check that profile size is a multiple of 4
With this, I would've found e8bd067ce5 earlier.

(If this turns out to be too strict in practice, we can always relax
it again.)
2023-02-24 19:17:20 +01:00
Nico Weber
9bd7048519 LibGfx: Move ICC TagTableEntry to BinaryFormat.h 2023-02-19 00:01:44 +01:00
Nico Weber
0ca620a286 LibGfx: Move ICC ProfileFileSignature into a constant in BinaryFormat.h
...so that it can be used by ICC writing code too.
2023-02-17 20:05:50 -07:00
Nico Weber
78d849bce2 LibGfx: Make ICCHeader use RenderingIntent enum
No behavior change.
2023-02-17 20:05:50 -07:00
Nico Weber
429467f46c LibGfx: Move ICC on-disk structs to new BinaryFormat.h
Removes some existing code duplication and allows future files to use
these structs too.
2023-02-17 20:05:50 -07:00
Nico Weber
9ba3c8e36d LibGfx: Move ICC::Profile towards "Fallible Constructors" pattern
Not quite there yet due to check_required_tags() / check_tag_types(),
but getting closer :^)
2023-02-15 10:15:24 +01:00
Nico Weber
db614b47dd LibGfx: Move ICC::Profile::read_header() out of class
This one is slightly more involved: To make it nice, extract
all the Profile fields that belong to the header into a separate
struct.
2023-02-15 10:15:24 +01:00
Nico Weber
272e5321e3 LibGfx: Move ICC::Profile::read_tag_table() out of class 2023-02-15 10:15:24 +01:00
Nico Weber
006dff6878 LibGfx: Move ICC::Profile::read_tag() out of class 2023-02-15 10:15:24 +01:00
Nico Weber
1c259b7a5a LibGfx: Validate ICC namedColor2Tag consistency 2023-02-14 19:28:13 +01:00
Nico Weber
45e391dae9 LibGfx: Add v2 "ncol" tag, expand comment
I had missed this in 21cc0c0cb2 because this tag is missing in
"Table 32 — Tag list" in the v2 ICC spec O_o. But it's in
"6.4.26 namedColorTag".

Also add a comment pointing to a page saying that all these tags
are very deprecated and not even recommended for new v2 profiles.
(That's how I noticed that namedColorTag was missing.)
2023-02-14 19:28:13 +01:00
Nico Weber
7e915b145b LibGfx: Let ICC code validate tag data alignment
Both when reading the main tag table and when reading embedded
curve data in lutAToBType or lutBToAType.
2023-02-12 20:07:45 +00:00
Nico Weber
cf73e15dc1 LibGfx: Make ICC code handle out-of-memory situations better
...by using adopt_nonnull_ref_or_enomem() via the try_make_ref_counted()
wrapper, instead of adopt_ref().
2023-02-11 10:02:24 +01:00
Nico Weber
4eebe753d1 LibGfx: Validate ICC cicpTag some more 2023-02-10 17:06:40 +00:00
Nico Weber
b232281d15 LibGfx+icc: Read chromaticityTag
This isn't terribly useful. But some profiles, for example the ones at
https://vpifg.com/help/icc-profiles/, do contain this tag and it seems
nice to be able to dump it, just for completeness.

I haven't seen any files that contain a phosphor or colorant type
different from "Unknown", even for the Rec2020 profile on that page.
(It has x,y coordinates that match the values required for Rec2020,
but it doesn't set the phosphor or colorant type to that.)
2023-02-10 14:23:37 +00:00
Nico Weber
c61cfdd5ed LibGfx+icc: Read viewingConditionsType
Not terribly useful in practice either and also mostly for
completionism. But with this, we can dump all types present
in Lightroom Classic-exported jpegs :^)
2023-02-10 14:16:52 +00:00
Nico Weber
664946c543 LibGfx+icc: Read measurementType
Also not terribly useful in practice and mostly for completionism.
Lightroom Classic-exported jpegs contain this type in their ICC data.
2023-02-10 14:02:19 +00:00
Nico Weber
2ff11bac3d LibGfx+icc: Implement half of lutAToBType and lutBToAType
These are among the permitted tag types of ATo0Tag and BToA0Tag,
which are among the required tags of most profiles. They are the
last permitted tag types for those profiles (the other are
lut8Type or lut16Type, which are already implemented).

They are pretty chonky types though, so this only implements
support for the E matrix and the CLUT. Support for the various
curves will be in a future PR.
2023-02-08 19:44:03 +00:00
Nico Weber
839bec14af LibGfx: Validate type of cicpTag in ICC Profile
This should've really been part of e8bbb3d915.
2023-02-08 17:18:54 +00:00
Nico Weber
e8bbb3d915 LibGfx+icc: Read cicpType
This is a very new tag used for HDR content. The only files I know that
use it are the jpegs on https://ccameron-chromium.github.io/hdr-jpeg/
But they have an invalid ICC creation date, so `icc` can't process them.
(Commenting out the check for that does allow to print them.)

If the CIPC tag is present, it takes precedence about the actual data
in the profile and from what I understand, the ICC profile is
basically ignored. See https://www.color.org/events/HDR_experts.xalter
for background, in particular
https://www.color.org/hdr/02-Luke_Wallis.pdf (but the other talks
are very interesting too).

(PNG also has a cICP chunk that's supposed to take precedence over
iCCP.)
2023-02-08 16:41:58 +00:00
Nico Weber
a434b89521 LibGfx: Add another profile ID to ICC quirk list 2023-02-08 16:37:47 +00:00
Nico Weber
21cc0c0cb2 LibGfx: Add ICC v2 tags to tag list 2023-02-08 16:36:31 +00:00
Nico Weber
8bd64f001c LibGfx+icc: Read signatureType
This isn't used by any mandatory tags, and it's not terribly useful.
But jpegs exported by Lightroom Classic write the 'tech' tag, and
it seems nice to be able to dump its contents.

signatureType stores a single u32 which for different tags with this
type means different things.

In each case, the value is one from a short table of valid values,
suggesting this should be a per-tag enum class instead of a
per-tag DistinctFourCC, per the comment at the top of DistincFourCC.h.
On the other hand, 3 of the 4 tables have an explicit "It is possible
that the ICC will define other signature values in the future" note,
which suggests the FourCC might actually be the way to go.

For now, just punt on that and manually dump the u32 in fourcc style
in icc.cpp and don't add any to_string() methods that return a readable
string based on the contents of these tables.
2023-02-08 16:35:57 +00:00
Nico Weber
cbcf8471a6 LibGfx+icc: Read namedColor2Type
This is the type of namedColor2Tag, which is a required tag in
NamedColor profiles.

The implementation is pretty basic for now and only exposes the
numbers stored in the file directly (after endian conversion).
2023-02-08 16:34:24 +00:00
Nico Weber
e9dcc49f9c LibGfx: Validate tag types of AToBNTag, BToANTag, gamutTag, previewNTag
Also rewrite a few of the existing tag type checks using a new helper.
2023-01-29 11:40:14 +00:00
Nico Weber
909c2a73c4 LibGfx+icc: Read and display lut16Type and lut8Type ICC tag types 2023-01-28 21:40:45 +00:00
Nico Weber
a0513a360a LibGfx: Use AssertSize<> in ICC/Profile.cpp 2023-01-28 21:40:45 +00:00
Nico Weber
b5deccf859 LibGfx: Split ICC/Profile.{h,cpp} into several files
s15Fixed16Number and XYZNumber are somewhat awkwardly duplicated
in both Profile.cpp and TagTypes.cpp. Other than that, this is a
pure code move.

No behavior change.
2023-01-28 00:27:07 +00:00
Nico Weber
6d51d8ad32 LibGfx: Bump copyright year in ICC/Profile.{h,cpp} 2023-01-28 00:27:07 +00:00
Nico Weber
721b280849 LibGfx: Move ICCProfile.{h,cpp} to ICC/Profile.{h,cpp} 2023-01-28 00:27:07 +00:00
Renamed from Userland/Libraries/LibGfx/ICCProfile.cpp (Browse further)