Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: Fails to apply HSL colors with a decimal point in the hue. #602

Open
Ashwin-Mahadevan opened this issue Mar 12, 2024 · 7 comments
Open

Comments

@Ashwin-Mahadevan
Copy link

Bug report

Description / Observed Behavior

When a decimal point is provided

Expected Behavior

How did you expect Satori to behave here?

Reproduction

Note: Satori functions correctly in the OG-Image Playground (Reproduction)

However, in any Next.js app, the bug occurs. I've tried the lastest next-js and satori releases as well as a few versions back. To reproduce this, git clone https://github.com/ashwin-mahadevan/satori-decimal-hue-reproduction, start the Next server, and navigate to / or /?decimal=true.

or use the following code in an app-router route.tsx file:

import { ImageResponse } from "next/og";

export function GET(request) {
  const decimal = request.nextUrl.searchParams.get("decimal") === "true";

  const element = (
    <div
      style={{
        display: "flex",
        width: 256,
        height: 256,
        backgroundColor: decimal
          ? "hsl(20.5 90.2% 48.2%)" // Shows black image with decimal hue.
          : "hsl(21 90.2% 48.2%)", // Shows correct orange image with integer hue.
      }}
    />
  );

  return new ImageResponse(element, { width: 256, height: 256 });
}
@Jackie1210
Copy link
Contributor

It seems rendered correct result by your (Reproduction)

@Ashwin-Mahadevan
Copy link
Author

Hi, thanks for taking the time to view this issue!

The problem is that, while it does work in the Vercel OG playground, it does not work in Next.js!
You can see this by cloning the repository I've linked (https://github.com/ashwin-mahadevan/satori-decimal-hue-reproduction).

Is there any difference between @vercel/satori and next/og?

@Ashwin-Mahadevan
Copy link
Author

Just checked again to confirm and the linked repository still has the issue.

@Jackie1210
Copy link
Contributor

My guess is that next.js has it own bundle of satori, which might not same with latest satori

@erxclau
Copy link

erxclau commented Nov 30, 2024

Testing on the latest Next canary (15.0.4-canary.32), this issue is still reproducible (see https://github.com/erxclau/satori-decimal-hue-reproduction). The Next bundle of Satori was recently bumped to 0.12.0 in vercel/next.js#72954, as shown by the ability to use WebkitTextStroke in the reproduction.

http://localhost:3000 http://localhost:3000?decimal=true
Screenshot 2024-11-29 at 11 58 02 PM Screenshot 2024-11-29 at 11 57 57 PM

I'm not really sure how next/og works but I imagine it could have to do with some processing done after Satori like resvg.

Relatedly, although the playground link sent above does work in the default tab, the PNG tag shows a black square:

Screenshot 2024-11-30 at 12 04 38 AM

@erxclau
Copy link

erxclau commented Nov 30, 2024

This can be reproduced in the resvg-js playground:

<svg width="600" height="300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <rect x="10" y="10" width="20" height="20" fill="hsl(20 90.2% 48.2%)"></rect>
  <rect x="40" y="10" width="20" height="20" fill="hsl(20.5 90.2% 48.2%)"></rect>
</svg>
Screenshot 2024-11-30 at 12 10 55 AM

@erxclau
Copy link

erxclau commented Nov 30, 2024

Some more digging here. I think this happens in svgtypes, which resvg depends on.

When parsing HSL colors, the hue parsed as an integer. I can't confirm, but I imagine having a decimal hue with this would mangle parsing. I believe the CSS color spec (v3 and 4) both suggest that the hue can be a decimal number.

CSS color module 3 4.2.4:

HSL colors are encoding as a triple (hue, saturation, lightness). Hue is represented as an angle of the color circle (i.e. the rainbow represented in a circle). This angle is so typically measured in degrees that the unit is implicit in CSS; syntactically, only a number is given.

CSS color module 4 4.3.

github-merge-queue bot pushed a commit to linebender/svgtypes that referenced this issue Dec 3, 2024
Browsers support a color like `hsl(120.152, 100%, 75%)` but this library
would incorrectly parse the hue and fallback to black.

Changes parsing the hue as an integer to parsing as a number.

[CSS Color Module Level 3
4.2.4](https://www.w3.org/TR/css-color-3/#hsl-color) suggests that the
hue should be a number (and not strictly an integer):

> Hue is represented as an angle of the color circle (i.e. the rainbow
represented in a circle). This angle is so typically measured in degrees
that the unit is implicit in CSS; syntactically, only a \<number\> is
given.

CSS Color Module Level 4 is more explicit that hue [can be a
number](https://www.w3.org/TR/css-color/#typedef-hue).

This PR also comments out the `parse_integer` and `parse_list_integer`
functions (and relevant tests) from `src/stream.rs` because leaving them
in the code produced these warnings during build:

```
warning: methods `parse_integer` and `parse_list_integer` are never used
   --> src/stream.rs:417:12
    |
109 | impl<'a> Stream<'a> {
    | ------------------- methods in this implementation
...
417 |     pub fn parse_integer(&mut self) -> Result<i32, Error> {
    |            ^^^^^^^^^^^^^
...
447 |     pub fn parse_list_integer(&mut self) -> Result<i32, Error> {
    |            ^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(dead_code)]` on by default
```

Happy to uncomment or remove them completely if that's preferred.

Related to vercel/satori#602
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants