1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 04:48:14 +00:00
Commit graph

150 commits

Author SHA1 Message Date
Nico Weber
92852b8477 LibGfx/ICC: Move MatrixMatrixConversion curve type check to ctor
A bit faster:

```
    N           Min           Max        Median         Avg       Stddev
x  50    0.97179127     1.0031381    0.98313618  0.98407591 0.0092019442
+  50    0.95996714    0.99507213    0.96965885  0.97242294 0.0095455053
Difference at 95.0% confidence
	-0.011653 +/- 0.00372012
	-1.18415% +/- 0.378032%
	(Student's t, pooled s = 0.0093753)
```
2024-01-12 12:37:56 +00:00
Nico Weber
5ff2a824cc LibGfx/ICC: Move MatrixMatrixConversion::map() inline
According to ministat, a bit faster to render page 3 of 0000849.pdf:

```
    N           Min           Max        Median         Avg       Stddev
x  50      1.000875     1.0427601     1.0208509   1.0201902   0.01066116
+  50    0.99707389       1.03614     1.0084391   1.0107864  0.010002724
Difference at 95.0% confidence
	-0.00940384 +/- 0.0041018
	-0.921773% +/- 0.402062%
	(Student's t, pooled s = 0.0103372)
```
2024-01-12 12:37:56 +00:00
Nico Weber
4704e6aa5f LibGfx/ICC: Refactor matrix/matrix conversion code a bit
No behavior change; the goal is to make it usable by LibPDF too.
2024-01-12 09:09:56 +01:00
Nico Weber
2fc6ec0f46 LibGfx/ICC: Fastpath for matrix->matrix image conversions
Doesn't help with PDF at all since that doesn't call convert_image()
(-‸ლ)
2024-01-12 09:09:56 +01:00
Nico Weber
89315787ae LibGfx/ICC: Cache presence of various tags
Reduces time spent rendering page 3 of 0000849.pdf from 1.45s to 1.32s
on my machine.

Also reduces the time to run Meta/test_pdf.py on 0000.zip
(without 0000849.pdf) from 58s to 55s.
2024-01-11 08:15:22 +00:00
Nico Weber
3365a92ead LibGfx/ICC: Cache inverted matrix on profile
Reduces time spent rendering page 3 of 0000849.pdf from 1.85s to 1.45s
on my machine.

As determined by running

    time Build/lagom/bin/pdf --page 3 --render out.png \
        ~/Downloads/0000/0000849.pdf

a few times and eyeballing the min time.

Also reduces the time to run Meta/test_pdf.py on 0000.zip
(without 0000849.pdf) from 1m7s to 58s.
2024-01-11 08:15:22 +00:00
Nico Weber
19d434b229 LibGfx/ICC: Extract matrix computation functions
No behavior (or perf) change.
2024-01-11 08:15:22 +00:00
Nico Weber
5c5a24c6b7 LibGfx/ICC: Move some Profile member vars up a bit
...so that they're not below a FIXME that doesn't apply to them.

No behavior change.
2024-01-11 08:15:22 +00:00
Nico Weber
701d56f7ad LibGfx/ICC: Implement LutBToATagData::evaluate() when there is no CLUT
This is enough to make these work:

    for f in VideoHD VideoNTSC VideoPAL; do
        Build/lagom/bin/icc --debug-roundtrip \
            ~/Downloads/Adobe\ ICC\ Profiles\ \(end-user\)/RGB/$f.icc
    done

It's also possible to convert images to those color spaces:

    Build/lagom/bin/image -o image-pal.png \
        --convert-to-color-profile path/to/RGB/VideoPAL.icc \
        image-srgb.png

(If there's no png file with an embedded sRGB profile at hand, do first:

    Build/lagom/bin/icc --reencode-to serenity-sRGB.icc -n sRGB
    Build/lagom/bin/image -o image-srgb.png \
        --assign-color-profile serenity-sRGB.icc image-no-color-space.png

)

In color-managed viewers, images-srgb.png and image-pal.png should
look identical.

But if you either explicitly assign the sRGB profile to the pal
image, or strip the embedded color space, they'll look different
(since image viewers then assume the image in the VideoPAL space
is in sRGB):

    Build/lagom/bin/image -o image-pal-strip.png --strip-color-profile \
        image-pal.png

    Build/lagom/bin/image -o image-not-actually-srgb.png \
        --assign-color-profile serenity-sRGB.icc image-pal.png
2024-01-07 15:42:35 +01:00
Nico Weber
a75533b46b LibGfx/ICC: Add a trailing , to an initialization
No behavior change.
2024-01-07 15:42:35 +01:00
Nico Weber
d17e8d1654 LibGfx/ICC: Plumb mBA conversion from profile to tag data
It's still implemented on the tag data side, so no real
behavior change.
2024-01-07 15:42:35 +01:00
Nico Weber
bcb1e548f1 LibGfx/ICC: Improve XYZ coordinates of gray colors
In XYZ space, gray doesn't have three equal values. Instead, it is
a line through the whitepoint.

(Multiplying by the whitepoint has the same effect as multiplying
the sRGB matrix with a (g, g, g) vector, since the numbers on
the matrix's rows add up to the whitepoint.)

Fixes the very slight red tint on all the figures in chapter 4
of the PDF 1.7 spec.
2023-12-31 13:20:37 +01:00
Ali Mohammad Pur
5e1499d104 Everywhere: Rename {Deprecated => Byte}String
This commit un-deprecates DeprecatedString, and repurposes it as a byte
string.
As the null state has already been removed, there are no other
particularly hairy blockers in repurposing this type as a byte string
(what it _really_ is).

This commit is auto-generated:
  $ xs=$(ack -l \bDeprecatedString\b\|deprecated_string AK Userland \
    Meta Ports Ladybird Tests Kernel)
  $ perl -pie 's/\bDeprecatedString\b/ByteString/g;
    s/deprecated_string/byte_string/g' $xs
  $ clang-format --style=file -i \
    $(git diff --name-only | grep \.cpp\|\.h)
  $ gn format $(git ls-files '*.gn' '*.gni')
2023-12-17 18:25:10 +03:30
Nico Weber
72f5461af4 LibGfx/ICC: Implement forward transform for mft1 and mft2 tags
mft1 and mft2 tags are very similar. The only difference is that
mft1 uses an u8 lookup table, while mft2 uses a u16 lookup table.
This means their PCS lookup encodings are different, and mft2 uses a
PCSLAB encoding that's different from other places in the v4 spec.
2023-12-05 09:56:50 +01:00
Nico Weber
b138bc0004 LibGfx/ICC: Simplify lerp_1d() a bit
No behavior change.
2023-12-05 09:56:50 +01:00
Nico Weber
9372f6d726 LibGfx/ICC: Extract a lerp_1d() function
Pure code move, no behavior change.
2023-12-05 09:56:50 +01:00
Nico Weber
b2a1130556 LibGfx/ICC: Implement conversion between different connection spaces
If one profile uses PCSXYZ and the other PCSLAB as connection space,
we now do the necessary XYZ/LAB conversion.

With this and the previous commits, we can now convert from profiles
that use PCSLAB with mAB, such as stress.jpeg from
https://littlecms.com/blog/2020/09/09/browser-check/ :

    % Build/lagom/icc --name sRGB --reencode-to serenity-sRGB.icc
    % Build/lagom/bin/image -o out.png \
        --convert-to-color-profile serenity-sRGB.icc \
        ~/src/jpegfiles/stress.jpeg
2023-12-04 08:02:36 +00:00
Nico Weber
9f7b33c31f LibGfx/ICC: Extract a lab_from_xyz() function
Pure code move, no behavior change.
2023-12-04 08:02:36 +00:00
Nico Weber
fda9840f48 LibGfx/ICC: Make mAB tags work for profiles that use PCSLAB
ICC profiles work by transforming from the input color space
(one of many: RGB, CMYK, YUV, etc) to a "profile connection space" (PCS)
and then from there to the output color space.

However, there's not one but two possible profile connection spaces,
PCSXYZ and PCSLAB. The matrix/curve tags can only be used with PCSXYZ,
but the mAB, mBA, mft1, mft2 tags can be used with PCSLAB as well.

The PCSLAB encoding has L going from 0 to 100 and ab from -128 to 127,
instead of from 0 to 1. So they need to be scaled up at the end.

That's also the reason for the "mystery conversion factor": PCSXYZ
doesn't go from 0 to 1 either, but from 0 to 65535/32768, per ICC v4
6.3.4.2 General PCS encoding, Table 11 - PCSXYZ X, Y or Z encoding.

Between input and output are various curves (and the CLUT) that
have domain and range of 0..1. For these, the color has to be linearly
scaled to 0..1 before the curve and back to the actual range after
the curve. Doing that back-to-back is a no-op, so scaling back at
the very end is sufficient.
2023-12-04 08:02:36 +00:00
Nico Weber
64ffae9c55 LibGfx/ICC: Move enums to dedicated Enums.{cpp,h}
We will need to use ColorSpace in TagTypes.h, and it can't include
Profile.h.

Also makes Profile.cpp a bit smaller.

No behavior change, pure code move.
2023-12-04 08:02:36 +00:00
Nico Weber
7f5e9a0236 LibGfx/ICC: Support for A curves and CLUT in LutAToBTagData::evaluate()
`lerp_nd()` is very similar to PDF::SampleFunction::evaluate(). But we
know that the result is a FloatVector3 in the ICC code (at least for
now), so we can save a bunch of redundant computation by returning
all three channels of the LUT at once.

This is enough for images using mAB with A curve / CLUT if the
profile connecting space is PCSXYZ, such as for Upper_Right.jpg
from https://www.color.org/version4html.xalter like so:

    % Build/lagom/icc --name sRGB --reencode-to serenity-sRGB.icc
    % Build/lagom/bin/image -o out.png \
        --convert-to-color-profile serenity-sRGB.icc \
        ~/Downloads/Upper_Right.jpg
2023-12-02 22:26:13 +01:00
Tim Ledbetter
f87d93b4ee LibGfx/ICC: Ensure Macintosh ScriptCode length is within expected range
Previously, it was possible for a `TextDescriptionTagData` object with
an incorrect Macintosh ScriptCode description length to cause a buffer
overflow.
2023-11-12 07:58:39 +01:00
Tim Ledbetter
10624a2beb LibGfx/ICC: Avoid overflow when creating MultiLocalizedUnicodeTagData
Previously, it was possible for a `MultiLocalizedUnicodeTagData` object
with a incorrect length  or offset fields to cause a buffer overflow.
2023-11-12 07:58:39 +01:00
Tim Schumacher
a2f60911fe AK: Rename GenericTraits to DefaultTraits
This feels like a more fitting name for something that provides the
default values for Traits.
2023-11-09 10:05:51 -05:00
Tim Ledbetter
c1d7a51391 LibGfx/ICC: Avoid buffer overrun when creating TextDescriptionTagData
We now validate that the offsets used cannot overflow, preventing
possible buffer overruns.
2023-11-08 09:37:30 +01:00
Nico Weber
c25538b2e3 LibGfx/ICC: Implement conversion to PCS for AToB*Tags using mAB
...as long as the mAB tag doesn't have A curves and a CLUT.

With this, we can convert images that use AToB* tags to the profile
connection space (and then from there to, say, sRGB), if the AToB* tag
uses the mAB format.

We can't yet do this if the mAB tag has A curves or a CLUT.

We can't convert back from PCS to this space yet.

We don't yet handle AToB* tags that use mft1 or mft2 instead of mAB.
2023-10-26 11:07:43 +02:00
Nico Weber
15bddf5de3 LibGfx/ICC: Gently rewrite CurveTagData::evaluate()
One less redundant expression. No behavior change.
2023-10-26 11:07:43 +02:00
Tim Ledbetter
1a4df4ffe7 LibGfx/ICC: Avoid overflow when constructing NamedColor2TagData 2023-10-26 10:59:22 +02:00
Tim Ledbetter
c21efdfc8a LibGfx/ICC: Avoid overflow when checking tag bounds 2023-10-07 09:48:01 +02:00
Nico Weber
563bb9d20c ICC: Implement Profile::to_pcs() for grayscale colors
There's probably a nicer way of doing this where we don't need to expand
the gray value into a full Vector3, but for now this is good enough.

Makes PDFs written by macOS 13.5.2's "Save as PDF..." feature show up.
2023-09-28 16:57:31 +01:00
Nico Weber
6b4da8680d ICC: Move a lambda up a bit
No behavior change.
2023-09-28 16:57:31 +01:00
Sam Atkins
835dada3d3 LibGfx: Add method to get String data from an ICC Profile tag 2023-07-20 08:02:12 +01:00
Sam Atkins
1066831b39 LibGfx: Add a method to get a specific tag from an ICC Profile 2023-07-20 08:02:12 +01:00
Matthew Olsson
fa1b1f8244 LibGfx: Forward-declare TagData in WellKnownProfiles 2023-07-20 06:56:41 +01:00
Nico Weber
3dd6638177 ICC: Strip trailing nul characters from MultiLocalizedUnicodeTagData
Having those trailing nuls is invalid per spec, but it happens in
practice (in already checked-in test files, no less).
2023-06-26 19:24:34 +01:00
Nico Weber
54448040ec ICC: Verify curve types have valid types
LutAToBTagData::from_bytes() and LutBToATagData::from_bytes() already
reject curves for which this isn't true with an error.

Ensure potential future callers of the constructors get it right too.
2023-05-04 16:11:07 +02:00
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
1e5ececf75 ICC: Add comment with a link to WellKnownProfiles.cpp 2023-04-29 06:49:36 +02:00