1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-06 14:47:36 +00:00
Commit graph

2003 commits

Author SHA1 Message Date
Lucas CHOLLET
67522fab2e LibGfx/TIFF: Add support for RGBPalette images
TIFF images with the PhotometricInterpretation tag set to RGBPalette are
based on indexed colors instead of explicitly describing the color for
each pixel. Let's add support for them.

The test case was generated with GIMP using the Indexed image mode after
adding an alpha layer. Not all decoders are able to open this image, but
GIMP can.
2023-12-23 20:41:48 +01:00
Shannon Booth
e2e7c4d574 Everywhere: Use to_number<T> instead of to_{int,uint,float,double}
In a bunch of cases, this actually ends up simplifying the code as
to_number will handle something such as:

```
Optional<I> opt;
if constexpr (IsSigned<I>)
    opt = view.to_int<I>();
else
    opt = view.to_uint<I>();
```

For us.

The main goal here however is to have a single generic number conversion
API between all of the String classes.
2023-12-23 20:41:07 +01:00
Nico Weber
80359517bd LibGfx: Do not use double negation in TIFFGenerator.py
No behavior change.
2023-12-23 12:25:08 -05:00
Lucas CHOLLET
2cfca633ca LibGfx/TIFF: Add support for images with UnassociatedAlpha
UnassociatedAlpha is the one used by GIMP when generating TIFF images
with transparency. Support is added for Grayscale and RGB images as it's
the two that we support right now but managing transparency should be
really straightforward for other types as well.
2023-12-22 08:08:47 +00:00
Lucas CHOLLET
796ece7b35 LibGfx/TIFF: Read the ExtraSamples tag 2023-12-22 08:08:47 +00:00
Nicolas Ramz
6ccdb1dc72 LibGfx/ILBMLoader: Add support for 24bit files 2023-12-21 09:19:30 +00:00
Nicolas Ramz
caa13d3960 LibGfx/ILBMLoader: Stop the decoding loop when plane buffer is full
This allows decoding files (eg. 24bit) that may have been badly encoded.
2023-12-21 09:19:30 +00:00
Lucas CHOLLET
b0e5aadf1a LibGfx/TIFF: Remove an unneeded parameter
This should have been done in f00e9540.
2023-12-20 12:19:30 +01:00
Lucas CHOLLET
caf9f00456 LibGfx/TIFF: Skip channels that we are unable to interpret
As per the specification, TIFF readers should gracefully skip samples
that they are not able to interpret.

This patch allow us to read `strike.tif` from the libtiff test suite as
an RGB image.
2023-12-20 12:19:30 +01:00
Lucas CHOLLET
a443d2955a LibGfx/TIFF: Don't use SamplesPerPixel to infer the "type" of image
The number of samples is not a good measure to deduce the type of image
we are decoding. As per the TIFF spec, the PhotometricInterpretation tag
is required and we should use that instead.
2023-12-20 12:19:30 +01:00
MacDue
d327104910 LibGfx: Add Path::place_text_along(text, font)
This method returns a new path with the input text placed along the edge
of the original path.
2023-12-19 21:29:03 +01:00
MacDue
8713968165 LibGfx: Preserve path order while splitting cubic/quadratic beziers
This changes the splitting to use a stack, which ensures the resulting
line segments follow the path in order. This will be important for SVG
`<textPath>`s which place text along a path.
2023-12-19 21:29:03 +01:00
Lucas CHOLLET
64912d4d02 LibGfx/TIFF: Add support for images with CCITT3 1D compression
This compression (tag Compression=2) is not very popular on its own, but
a base to implement CCITT3 2D and CCITT4 compressions.

As the format has no real benefits, it is quite hard to find an app that
accepts tho encode that for you. So I used the following program that
calls `libtiff` directly:
```cpp
#include <vector>
#include <cstdlib>
#include <iostream>

#include <tiffio.h>

// An array containing 0 and 1 of length width * height.
extern std::vector<uint8_t> array;
int main() {
    // From: https://stackoverflow.com/a/34257789

    TIFF *image = TIFFOpen("input.tif", "w");
    int const width = 400;
    int const height = 300;
    TIFFSetField(image, TIFFTAG_IMAGEWIDTH, width);
    TIFFSetField(image, TIFFTAG_IMAGELENGTH, height);
    TIFFSetField(image, TIFFTAG_PHOTOMETRIC, 0);
    TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_CCITTRLE);

    TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 1);
    TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, 1);
    TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, 1);

    std::vector<uint8_t> scan_line(width / 8 + 8, 0);
    int count = 0;
    for (int i = 0; i < height; i++) {
        std::fill(scan_line.begin(), scan_line.end(), 0);
        for (int x = 0; x < width; ++x) {
            uint8_t eight_pixels = scan_line.at(x / 8);
            eight_pixels = eight_pixels << 1;
            eight_pixels |= !array.at(i * width + x);
            scan_line.at(x / 8) = eight_pixels;
        }
        int bytes = int(width / 8.0 + 0.5);
        if (TIFFWriteScanline(image, scan_line.data(), i, bytes) != 1)
            std::cerr << "Something went wrong\n";
    }

    TIFFClose(image);
}
```
2023-12-19 21:01:24 +01:00
Lucas CHOLLET
7266d8c35d LibGfx/TIFF: Correctly upscale samples with a resolution lower than 8
As pointed out by @nico, while doing a right-shift to downscale is fine,
a left-shift to upscale gives wrong results. As an example, imagine a 2-
bits value containing 3, left-shifting it would give 192 instead of 255.
2023-12-19 21:01:24 +01:00
Lucas CHOLLET
5b62d877f2 LibGfx/TIFF: Parse more common tags
These tags are either part of the baseline specification or included by
default by GIMP when exporting TIFF files. Note that we don't add
support for them in the decoder yet. This commit only allows us to parse
the metadata and display it gracefully.
2023-12-18 07:14:11 +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
Nicolas Ramz
cd6c7f3fc4 LibGfx/ILBMLoader: Add support for PC DeluxePaint files 2023-12-13 10:39:13 +00:00
Aliaksandr Kalenik
df57d7ca68 LibGfx+LibWeb: Update for_each_glyph_position to use font cascade list
This change updates function that builds list of glyphs to use font
cascade list to find font for each code point.
2023-12-10 17:32:04 +01:00
Aliaksandr Kalenik
2cb0039a13 LibGfx+LibWeb: Produce font cascade list in CSS font matching algorithm
According to the CSS font matching algorithm specification, it is
supposed to be executed for each glyph instead of each text run, as is
currently done. This change partially implements this by having the
font matching algorithm produce a list of fonts against which each
glyph will be tested to find its suitable font.

Now, it becomes possible to have per-glyph fallback fonts: if the
needed glyph is not present in a font, we can check the subsequent
fonts in the list.
2023-12-10 17:32:04 +01:00
Aliaksandr Kalenik
f50bf00814 LibWeb+LibGfx: Move UnicodeRange from LibWeb to LibGfx
In upcoming changes UnicodeRange is going to be used in LibGfx in
a class that represents font cascade list.
2023-12-10 17:32:04 +01:00
Aliaksandr Kalenik
0d03257e69 LibGfx+LibAccelGfx+LibWeb: Use RefPtr for font in DrawGlyphOrEmoji 2023-12-10 17:32:04 +01:00
Kyle Pereira
649f1df771 LibGfx: Add RepeatingBitmapPaintStyle and OffsetPaintStyle
RepeatingBitmapPaintStyle tiles a bitmap passed on passed in parameters
and paints according to that.

OffsetPaintStyle offsets an existing paint style and paints with that.

These two will be useful in the PDF renderer.
2023-12-10 16:44:24 +01:00
Lucas CHOLLET
3ae29fdeec LibGfx/TIFF: Support WhiteIsZero parameter for grayscale images
PhotometricInterpretation::WhiteIsZero is used to inverse black and
white on bilevel and grayscale images.
2023-12-10 09:45:30 +01:00
Lucas CHOLLET
64d7e386d2 LibGfx/TIFF: Parse the PhotometricInterpretation tag 2023-12-10 09:45:30 +01:00
Lucas CHOLLET
234d084876 LibGfx/TIFF: Add support for bit-depth up to 32 bits per sample
This makes us support every "minisblack" and "rgb-contig" images from
the depth folder of libtiff's test suite:
https://libtiff.gitlab.io/libtiff/images.html
2023-12-09 21:47:33 +01:00
Aliaksandr Kalenik
8634820e73 LibGfx: Use east-mutable style in OpenType font class
No intended behavior change.
2023-12-09 19:05:30 +01:00
Aliaksandr Kalenik
7ae229ead7 LibGfx: Cache family, width, weight, and slope for OpenType fonts
These properties could be cached in the font object once they are
decoded from the table for the first time to make subsequent access
faster.

This change makes `Node::scaled_font()` in LibWeb go down from 6% to
1.5% in my profiles because building a font cache key is now a lot
cheaper.
2023-12-09 19:05:30 +01:00
Nicolas Ramz
8d68f94282 LibGfx/ILBMLoader: Add HAM6/HAM8 support 2023-12-07 10:08:29 -07:00
Lucas CHOLLET
965da551e3 LibGfx/TIFF: Print the corresponding enum value's name when possible
As an example, for the tag 262 if the value is 5, "LZW" will be
displayed instead of the numeric value.
2023-12-07 11:10:55 +01:00
Lucas CHOLLET
2691651abf LibGfx/TIFF: Generated the code to output debug prints
When the `TIFF_DEBUG` flag is set, the TIFF decoder logs every tag and
their values. This is already useful but require the developer to have
the spec handy in order to decrypt each value to its signification. None
of this information is available at runtime, but this is known by the
Python generator. So by generating these debug logs, we drastically
increase their value.

As a bonus point, most of these functions should be useful when we will
display image's metadata in Serenity.
2023-12-07 11:10:55 +01:00
Lucas CHOLLET
b82f5d7f3e LibGfx/TIFF: Add a C++ formatter for TIFF::Value 2023-12-07 11:10:55 +01:00
Lucas CHOLLET
6e282538cc LibGfx/TIFF: Generate a C++ helper function to print enums
For a given enum value, this function will return its corresponding name
as a `StringView`.
2023-12-07 11:10:55 +01:00
Lucas CHOLLET
f00e9540d5 LibGfx/TIFF: Add an intrinsic way to get the exportable name of Enums
The `TIFFType` enum is exported with a different name to C++. This
change of behavior was handled by manually setting the parameter of a
function. However, we will soon need the exported name in more places,
so let's make it a property of the Enum itself.
2023-12-07 11:10:55 +01:00
Lucas CHOLLET
1d345109c4 LibGfx/TIFF: Move Formatter<Rational>'s definition to TIFFMetadata.h
This will soon be used in TIFFTagHandler.cpp, so the definition needs to
be shared.
2023-12-07 11:10:55 +01:00
Lucas CHOLLET
da134f6867 LibGfx/TIFF: Add support for grayscale images
Images with a single sample per pixel should be interpreted as
grayscale.
2023-12-07 08:17:46 +00:00
Lucas CHOLLET
923d9e834f LibGfx/TIFF: Add support for the SamplesPerPixel tag 2023-12-07 08:17:46 +00:00
Lucas CHOLLET
d9b69c644e LibGfx/TIFF: Allow any number of values for the tag BitsPerSample
Only some specific number of values should be allowed, but let's accept
everything for now and add these checks when the generator will be more
mature.
2023-12-07 08:17:46 +00:00
Lucas CHOLLET
ff73d5464a LibGfx/TIFF: Make loop_over_pixels autonomous for reading samples
Let's make the "read a sample" part independent of the decoder. That
will soon allow us to read samples based on the image's parameter
without duplicating the code for every decoder.
2023-12-07 08:17:46 +00:00
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
Lucas CHOLLET
0a80daef90 LibGfx/TIFF: Don't include the null-byte terminator when reading strings 2023-12-03 20:27:00 +01:00
Lucas CHOLLET
a382ea7c1f LibGfx/TIFF: Consider ASCII and UTF-8 as containers
The generator will now create APIs that return a single `String`
instead of a `Vector<String>`.
2023-12-03 20:27:00 +01: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
Aliaksandr Kalenik
681771d210 LibGfx+LibWeb: Calculate and save glyph positions during layout
Previously, we determined the positions of glyphs for each text run at
the time of painting, which constituted a significant portion of the
painting process according to profiles. However, since we already go
through each glyph to figure out the width of each fragment during
layout, we can simultaneously gather data about the position of each
glyph in the layout phase and utilize this information in the painting
phase.

I had to update expectations for a couple of reference tests. These
updates are due to the fact that we now measure glyph positions during
layout using a 1x font, and then linearly scale each glyph's position
to device pixels during painting. This approach should be acceptable,
considering we measure a fragment's width and height with an unscaled
font during layout.
2023-12-02 22:06:11 +01:00
Idan Horowitz
1a35621930 LibGfx: Eliminate multiplication integer overflow in planar_to_chunky
Multiplying two u16s will result in a i32 sized result, which will
overflow to negative values for large input values.

Fixes ossfuzz-64198.
2023-12-02 11:46:03 +01:00