Commit graph

40 commits

Author SHA1 Message Date
Lucas CHOLLET
3f4bf7a0c7 LibGfx/ExifOrientedBitmap: Add support for CMYKBitmap 2024-01-24 22:16:22 -07:00
Lucas CHOLLET
8229a19081 LibGfx/ExifOrientedBitmap: Reorganize create parameters
No behavior change.
2024-01-24 22:16:22 -07:00
Lucas CHOLLET
ef10a58522 LibGfx: Remove ExifOrientedBitmap::Orientation in favor of TIFF's enum
ExifOrientedBitmap was implemented before the introduction of the TIFF
decoder. So we had to provide a definition of the Orientation enum. Now
that we have a TIFF implementation that comes with some enum
definitions, we should prefer this source.
2024-01-08 00:07:44 +01:00
Sergey Bugaev
8ebddc1ff6 LibGfx: Misc 32-bit build fixes 2023-09-06 07:21:07 -06:00
Lucas CHOLLET
ea85c99a01 LibGfx/JPEGXL: Add support for cropped images
Due to the way JPEG XL encodes its lossless images, it is sometimes
interesting to embed a large image and crop the result at the end. This
patch adds the functionality to crop a frame.

Note that JPEG XL supports image composition (almost like layers in
image editing software programs) and I tried to make these changes be
a step toward image composing. It's a small step as we are still unable
to read multiple frames, and we only support the `kReplace` blending
mode.
2023-08-12 08:46:10 +02:00
Lucas CHOLLET
49c55447d9 LibGfx/JPEGXL: Put frame's image inside the Frame struct
The image was previously managed as an output parameter of the
`read_frame` function. This reorganisation also brings us closer to the
spec. As it is specified that each frame have its own image that will
later on compose a greater bitmap.
2023-08-12 08:46:10 +02:00
Lucas CHOLLET
70e4d3a9b6 LibGfx/JPEGXL: Support images with the have_crop option in FrameHeader
This commit only allows us to read these values. The decoder will still
output the image as if no cropping was requested.
2023-08-12 08:46:10 +02:00
Lucas CHOLLET
729e35ef21 LibGfx/JPEGXL: Remove unused variables in JPEGXLLoadingContext
These two variables are already fields of `Frame`, they make no sense at
the context scope.
2023-08-12 00:15:58 +02:00
Lucas CHOLLET
f2c60b7716 LibGfx/JPEGXL: Support images encoded with the YCbCr color space
While being way less frequent than for classical JPEG images, JPEG XL
images can use the YCbCr color space. Supporting it makes us properly
decode the "The Smoke Machine" image on https://jpegxl.info/jxl-art.html
2023-08-11 10:30:48 +02:00
Lucas CHOLLET
7a5cd7e5f4 LibGfx/JPEGXL: Add support for LZ77 encoded stream
On top of the Brotli/ANS compression, the entropy stream can have
another compression layer, this time using LZ77. This patch adds support
for this last layer, which makes us decode the `lz77_flower` test. This
double-compression is also often used for ICC profiles.
2023-08-10 22:39:31 +02:00
Lucas CHOLLET
80cb377990 LibGfx/JPEGXL: Factorize the code to read symbols from distributions
This will soon be used by the LZ77 decoder, so let's avoid some
duplication.
2023-08-10 22:39:31 +02:00
Lucas CHOLLET
3fdc000b90 LibGfx/JPEGXL: Use a wider type for the context id
These numbers can be way bigger than 255, let's use a `u32` instead of a
`u8`, which is what other decoders do.
2023-08-10 22:39:31 +02:00
Lucas CHOLLET
07ea66528e LibGfx/JPEGXL: Make EntropyDecoder::read_config() static
This function will soon be used for the LZ77 decoder with a different
parameter than `m_log_alphabet_size`.
2023-08-10 22:39:31 +02:00
Lucas CHOLLET
a35f4bf14e LibGfx/JPEGXL: Honor the orientation parameter
Since the introduction of the JPEG XL decoder, we always read the
`orientation` field in the `ImageMetadata` bundle. This patch allows us
to render the bitmap accordingly to this transformation.
2023-08-09 13:18:40 +01:00
Lucas CHOLLET
a0ea87ffc6 LibGfx/JPEGXL: Compute the position inside the channel correctly
Turns out I only decoded square images until now, which make this code
work. A bit ashamed to have written that bug.
2023-08-09 08:28:05 +01:00
Lucas CHOLLET
eb6d41d99e LibGfx/JPEGXL: Allow ColourEncoding bundles with custom values
We don't do anything particular with images that contain a custom
ColourEncoding yet, but at least it allows us to know how to decode the
metadata of such images.
2023-08-09 05:43:19 +02:00
Lucas CHOLLET
a8f041ae11 LibGfx/JPEGXL: Add support for complex distribution clustering
Complex distribution - distributions that are encoded using an internal
symbol decoder with a single distribution, are very often used for lz77
compressed images. This is a requirement for the lz77_flower test case.
2023-08-09 05:42:17 +02:00
Lucas CHOLLET
18c511f54c LibGfx/JPEGXL: Support clusters with a single distribution
This type of cluster is an exception and has specific rules (but
simpler) to be read. This is a requirement to support complex
distributions as they use a symbol decoder initialized with a single
distribution.
2023-08-09 05:42:17 +02:00
Lucas CHOLLET
e83b04417b LibGfx/JPEGXL: Implement the ANS decoder
This allows us to read many more images. This decoder is one of the two
possibilities (along Brotli) that can be used for modular images. All
the logic is directly taken from the spec.

One of the image that can now be decoded is "Lucifer's Dominion:
Synthesis" that can be found on `https://jpegxl.info/art/`, it also
makes us pass one more test of the conformance test suite, namely
"alpha_triangles".
2023-08-08 20:03:16 +02:00
Lucas CHOLLET
4da8c45e43 LibGfx/JPEGXL: Store distributions in a Variant
JPEG XL supports two types of entropy encoding: the first one is
Huffman-based (Brotli) and the second one is based on ANS. To introduce
the latter, we start by storing the `Vector` of distributions in a
`Variant`. This will allow us to choose which entropy decoder we use
during execution.
2023-08-08 20:03:16 +02:00
Lucas CHOLLET
cd9bb985d4 LibGfx/JPEGXL: Add support for the self-correcting predictor
This predictor is much more complicated than the others. Indeed, to be
computed, it needs its own value but for other pixels. As you can guess,
implementing it involved the introduction of a structure to hold that
data.

Fundamentally, this predictor uses the value of the error between the
predicted value and the true value (aka decoded value) of pixels around.
One of this computed error (namely max_error) is used as a property, so
this patch also solves a FIXME in `get_properties`.

To ease the access to value that are close in the channel and moving
their values around, this patch adds a `Neighborhood` struct which holds
this data. It has been used in `prediction()` and it allowed to simplify
the signature and to remove the explicit retrieval of the underlying
data.

All this work allows us to decode the default image that appears when
loading `https://jxl-art.surma.technology`. However, we still render it
incorrectly due to the lack of support for orientation values different
from 1.
2023-08-05 06:30:59 +02:00
Lucas CHOLLET
00240cb0b3 LibGfx/JPEGXL: Fix property 8
The first implementation of this property was just plain wrong. Looks
like this property isn't used a lot as I found the issue by reviewing
the code and not because of a specific image.

The test image is a 32x32 mosaic of alternating black and yellow pixels,
it was generated using this code:

Bitdepth 8
RCT 1
Width 32
Height 32

if W-WW-NW+NWW > -300
 - Set -1000
 - Set 900
2023-08-01 05:35:01 +02:00
Lucas CHOLLET
6b41fef2e4 LibGfx/JPEGXL: Add default values for ToneMapping 2023-08-01 05:35:01 +02:00
Lucas CHOLLET
fa43c70951 LibGfx/JPEGXL: Include the alpha channel in the output bitmap
Now that we are able to read extra channels, it's time to include them
in the final bitmap. They are usually at a smaller resolution than the
final bitmap and the first step to render them is upscaling. Luckily,
this is not necessary for rendering the `alpha_nonpremultiplied` case of
the conformance test suite, so, as usual, I implemented this rendering
function as a check + no-op.

Then, we simply test if an alpha channel is present and emit the
corresponding data when creating the bitmap.

Finally, it means that we are now capable of rendering images with a
full size alpha channel, like `alpha_nonpremultiplied`. In other words,
we now successfully decode one of the image of the official test suite!
2023-07-30 09:29:19 +02:00
Lucas CHOLLET
b2a559ddb0 LibGfx/JPEGXL: Create Image with the correct number of channel
As a quick and dirty implementation, we used to assume that the final
image was always composed of three channels of the same size. However,
JPEG XL has support for more than three channels and extra channels can
have a smaller size. With this patch, we now create the image with the
correct number of channel and with their respective sizes.
2023-07-30 09:29:19 +02:00
Lucas CHOLLET
0612e8ec6a LibGfx/JPEGXL: Read data related to extra channels in FrameHeader
Thanks to previous patches, everything used in `read_frame_header`
supports extra channels. The last element to achieve the read of headers
of frame with extra channels is to add support in the function itself
and the `FrameHeader` struct, which that patch does.
2023-07-30 05:39:47 +02:00
Lucas CHOLLET
da0944f63d LibGfx/JPEGXL: Handle parsing BlendingInfo for extra channels
Extra channels have more parameters than basic one. This patch allows us
to read all these parameters.
2023-07-30 05:39:47 +02:00
Lucas CHOLLET
7cbf76586a LibGfx/JPEGXL: Start parsing the ExtraChannelInfo bundle
This implementation is not feature complete yet as it only supports
channels with a type different of `ExtraChannelType::kAlpha`.

This patch also introduces the `read_enum` function.
2023-07-30 05:39:47 +02:00
Lucas CHOLLET
9b9244150e LibGfx/JPEGXL: Move code to read a string in a utility function
This was only used for the name of the `Frame`, but this code will soon
be used to read `ExtraChannelInfo`'s name. So let's factorize it!
2023-07-30 05:39:47 +02:00
Lucas CHOLLET
c6731b0970 LibGfx/JPEGXL: Consider the HfGlobal section of the TOC
There is always a section for HfGlobal, even if it's empty like with
Modular images.

I also removed the outdated (and misinterpreted) spec comment and
replace it with the name of the section.
2023-07-30 05:39:47 +02:00
Lucas CHOLLET
ea8384219f LibGfx/JPEGXL: Perform size computation in a floating point type
The computation was copied from the spec, but I forgot that they mention
that every "/" should be performed without truncation or rounding. Let's
use `double`s instead of integers.
2023-07-30 05:39:47 +02:00
Lucas CHOLLET
b5b17269c4 LibGfx/JPEGXL: Support reading LfGroups with an empty ModularLfGroup
I recently discovered a bug when we count the number of LfGroups, and it
turns out that this number can't be null. So that means that we need to
support reading them. The trick is that we only have support for images
that contains an empty LfGroup, so this patch implement a dummy reader
that just check that we are indeed facing an empty one and `TODO()`
otherwise.
2023-07-30 05:39:47 +02:00
Lucas CHOLLET
fee3eff947 LibGfx/JPEGXL: Use the correct condition to read save_before_ct
During the original implementation, I mixed the condition for
`save_before_ct` and the one for `save_before_ct`, resulting in a bogus
code. That's fixed now!
2023-07-30 05:39:47 +02:00
Lucas CHOLLET
697803efcc LibGfx/JPEGXL: Remove the BitmapDecoded state
There was a confusion between both `BitmapDecoded` and `FrameDecoded`
states. Removing one of them, solves the issue.
This patch removes the crash caused by requesting the same frame twice.
2023-07-26 08:44:17 +02:00
Lucas CHOLLET
33ca35f1c7 LibGfx/JPEGXL: Apply transformations after all PassGroups
The original image this decoder was written for has a single PassGroup,
so applying transformations after each PassGroup or after all of them
was equivalent. This patch fix the behavior for images with 0 or more
than one PassGroup.
2023-07-26 08:44:17 +02:00
Lucas CHOLLET
271d0015fe LibGfx/JPEGXL: Add support for x4 and x8 upsampling
All the logic is exactly the same as for x2 upsampling, so this commit
essentially boils down to adding arrays for default weights and the
logic to select the correct array.
2023-07-24 10:28:36 -04:00
Lucas CHOLLET
9975bdb2d1 LibGfx/JPEGXL: Align the stream to byte boundary before reading a frame
As this is stated in the spec, all frames are byte-aligned.
2023-07-22 08:52:57 -04:00
Lucas CHOLLET
a2955501d3 LibGfx/JPEGXL: Don't decode the header twice
This is something I missed when I ported the JPEG XL decoder to the new
plugin interface (decoding the header at creation). First sorry because
that's entirely my fault, second sorry because a test should have caught
that.
2023-07-21 22:25:56 -04:00
Lucas CHOLLET
65565d377b LibGfx/JPEGXL: Accept images with high bit depth
Instead of rejecting them, we truncate each value to 8 bits. This is
clearly a hack, but given the lack of support of variable bit-depth in
`Bitmap` this is the only sensible change.

This allows us to display "Iceberg" on https://jpegxl.info/art/.
2023-07-21 19:34:21 -04:00
Lucas CHOLLET
e8a63eeb0e LibGfx/JPEGXL: Add a JPEG-XL decoder :^)
JPEG-XL is a new image format standardized by the same committee as the
original JPEG image format. It has all the nice feature of recent
formats, and great compression ratios. For more details, look at:
https://jpegxl.info/

This decoder is far from being feature-complete, as it features a grand
total of 60 FIXMEs and TODOs but anyway, it's still a good start.

I developed this decoder in the Serenity way, I just try to decode a
specific image while staying as close as possible to the specification.

Considering that the format supports a lot of options, and that we
basically support only one possibility for each of them, I'm pretty sure
that we can only decode the image I've developed this decoder for.

Which is:
0aff 3ffa 9101 0688 0001 004c 384b bc41
5ced 86e5 2a19 0696 03e5 4920 8038 000b
2023-07-21 10:47:34 -06:00