From 4405d0986d4aa3cb33901b8d143749a337e3d029 Mon Sep 17 00:00:00 2001 From: Lynn Date: Tue, 18 Apr 2023 20:11:23 +0800 Subject: [PATCH] fix: color in hsl with unit like `deg,turn` should render correctly in `@resvg/resvg-js` (#449) Close https://github.com/vercel/satori/issues/374 Releated issue: https://github.com/RazrFalcon/resvg/issues/579 --- package.json | 1 + pnpm-lock.yaml | 15 ++++- src/handler/expand.ts | 21 ++++++- ...pport-css-4-synatx-color-in-hsl-1-snap.png | Bin 0 -> 1443 bytes ...ynatx-color-in-hsl-if-inherited-1-snap.png | Bin 0 -> 620 bytes test/color-models.test.tsx | 55 ++++++++++++++++++ 6 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 test/__image_snapshots__/color-models-test-tsx-test-color-models-test-tsx-color-models-should-support-css-4-synatx-color-in-hsl-1-snap.png create mode 100644 test/__image_snapshots__/color-models-test-tsx-test-color-models-test-tsx-color-models-should-support-css-4-synatx-color-in-hsl-if-inherited-1-snap.png diff --git a/package.json b/package.json index edcf78db..c39893b3 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "css-to-react-native": "^3.0.0", "emoji-regex": "^10.2.1", "linebreak": "^1.1.0", + "parse-css-color": "^0.2.1", "postcss-value-parser": "^4.2.0", "yoga-wasm-web": "^0.3.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c97b5a20..a7d5d42e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,6 +25,7 @@ importers: jest-image-snapshot: ^5.2.0 linebreak: ^1.1.0 lint-staged: 13.1.0 + parse-css-color: ^0.2.1 postcss-value-parser: ^4.2.0 prettier: ^2.7.1 react: ^17.0.2 @@ -41,6 +42,7 @@ importers: css-to-react-native: 3.0.0 emoji-regex: 10.2.1 linebreak: 1.1.0 + parse-css-color: 0.2.1 postcss-value-parser: 4.2.0 yoga-wasm-web: 0.3.3 devDependencies: @@ -1316,7 +1318,6 @@ packages: /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true /colorette/2.0.19: resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} @@ -2299,6 +2300,11 @@ packages: dependencies: function-bind: 1.1.1 + /hex-rgb/4.3.0: + resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==} + engines: {node: '>=6'} + dev: false + /human-signals/2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -3004,6 +3010,13 @@ packages: callsites: 3.1.0 dev: true + /parse-css-color/0.2.1: + resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==} + dependencies: + color-name: 1.1.4 + hex-rgb: 4.3.0 + dev: false + /path-exists/4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} diff --git a/src/handler/expand.ts b/src/handler/expand.ts index 6c6529d4..970c4b5e 100644 --- a/src/handler/expand.ts +++ b/src/handler/expand.ts @@ -6,6 +6,7 @@ import { getPropertyName, getStylesForProperty } from 'css-to-react-native' import { parseElementStyle } from 'css-background-parser' import { parse as parseBoxShadow } from 'css-box-shadow' +import cssColorParse from 'parse-css-color' import CssDimension from '../vendor/parse-css-dimension/index.js' import parseTransformOrigin from '../transform-origin.js' @@ -369,12 +370,28 @@ export default function expand( return transformedStyle } +/** + * @see https://github.com/RazrFalcon/resvg/issues/579 + */ +function refineHSL(color: string) { + if (color.startsWith('hsl')) { + const t = cssColorParse(color) + const [h, s, l] = t.values + + return `hsl(${[h, `${s}%`, `${l}%`] + .concat(t.alpha === 1 ? [] : [t.alpha]) + .join(',')})` + } + + return color +} + function getCurrentColor(color: string | undefined, inheritedColor: string) { if (color && color.toLowerCase() !== 'currentcolor') { - return color + return refineHSL(color) } - return inheritedColor + return refineHSL(inheritedColor) } function convertCurrentColorToActualValue( diff --git a/test/__image_snapshots__/color-models-test-tsx-test-color-models-test-tsx-color-models-should-support-css-4-synatx-color-in-hsl-1-snap.png b/test/__image_snapshots__/color-models-test-tsx-test-color-models-test-tsx-color-models-should-support-css-4-synatx-color-in-hsl-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..d8618f547cd18f2ee92a43ba2640a4d50498d6cf GIT binary patch literal 1443 zcmchXeK^wz0LQnAFdf@U5oYspd6J%Vi*R}S&9;p4QWERMyDqt$))0CTqm0>@87noi zWXsNuEgn}JO2&ChbRtG#+9oAOocsI!?~m{I`#j%2zW;om=aX~P54%OrL=OZ4ZNcM! zfc1?0PdeJ`{_A*A5D27o4i9()k;~>vhy-@j*7kh52HN3{#kZQ2%xXEnb^_A+J}COE zBofBN6D-0W$2!2oVfsv&GFsP$JO~kvbZWU36R_b)R^wT@KIrq~)yB9exn5|t*)P|8 zyOU?$6!Y!&@e{gQ*O*O{OR*`MmA9WX>c2+y!Dx4ig9Tu0cu!x)UpsTxMo$J9*>Tk{ z>O0k0bDr8QTYA-dkWNUe?Xh)j!egF=M*qW2gYkOBwbr>O%EC$A1yV2sYfSI-;5;+r4{~l@U zLTm;7q0gPWX4~?D8hMo9xu+y#>bHokK95*l#nLATMB1WDYq09*tp~X#BeMn}nX==B zEtby{sDztw%8m`6RdE)h^rEIxMh{{djdFJVSz$+FX*6RN1HzI+Dp1C5+sH}3veNQB zu9lLNRB9E|UPGBKnn|k{J%4e3C8DN)c3PUGVB5~e*KpORFV43N$ZEvm9j6>N+a;_9 zTq$xcJx508=|HuIn^ss=%M-eA+iwE2`t~%Os-Ju)c77+=Xn&nWvs;g^s^6@N8CL5} zQA?IV88#te_Fci$k-F+lqJbp!;nlihxKSqE##i)8T)p@Sv}EuTt^LDTdFny*!Gzxa z9|nz_jdlEggj{s)p>awdgeY-i3WXsdNuO6J5YwH`pip!2WH z)5X-7MQ?%)4Eiw_Mjy^pQlJ1X+JC#k(b|(6@|f$6`(Zm{Nlb9RX(|J rB8T1aRZy-V>U>T3PI&o0(bhmD`JD}X*P$Eh@CD&9egNO|%=Lc(Sq_ST literal 0 HcmV?d00001 diff --git a/test/__image_snapshots__/color-models-test-tsx-test-color-models-test-tsx-color-models-should-support-css-4-synatx-color-in-hsl-if-inherited-1-snap.png b/test/__image_snapshots__/color-models-test-tsx-test-color-models-test-tsx-color-models-should-support-css-4-synatx-color-in-hsl-if-inherited-1-snap.png new file mode 100644 index 0000000000000000000000000000000000000000..8c75cb3d672141698d34b8bf6fb85f5d2434f240 GIT binary patch literal 620 zcmeAS@N?(olHy`uVBq!ia0vp^DImGV%{Ea~SC2UMLA?-f7F7d&LZ(c_rF!;~x_(R@IH<(Ps2TcaT@ zgl2Sde0uWMAk4n5cl!6)FXmW9rhS^#p|JheYr}tgrMrFg^WygfqV5 zMLTcwUR*!-#r?VZn=6;{fBJECd6iG>{F#02`euvk)9tF#ty5K(UvYG^FHd@S(@p2@ zjNWHK=3?{muFTz3u{Aub*h@C$>D{n3bsE!uHZSX0RJVT5{Z-Se!&WwLu}*sTC&Xr# zS+E;>xsO|Bb57mw!1q0I+k@Xvus!^?@XXxVT}x+gPMzX^OX2i-c2lqFneVUv%UsLr z_Vvasd9Cg#jFUwiVV|0=p0bRf28N+9*jX~PLRK(!v>gTe~DWM4fKq&S9 literal 0 HcmV?d00001 diff --git a/test/color-models.test.tsx b/test/color-models.test.tsx index 77b3f83c..9ff81591 100644 --- a/test/color-models.test.tsx +++ b/test/color-models.test.tsx @@ -279,6 +279,61 @@ describe('Color Models', () => { }) }) + it('should support css4 synatx color in hsl', async () => { + const svg = await satori( +
+ A + A + B + C + D +
, + { + width: 100, + height: 100, + fonts, + } + ) + expect(toImage(svg, 100)).toMatchImageSnapshot() + }) + + it('should support css4 synatx color in hsl if inherited', async () => { + const svg = await satori( +
+ A +
, + { + width: 100, + height: 100, + fonts, + } + ) + expect(toImage(svg, 100)).toMatchImageSnapshot() + }) + // Borders: shorthand, border-bottom-color, border-color, border-left-color, border-right-color, border-top-color // Box shadow