summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/grumpy-monkeys-watch.md5
-rw-r--r--packages/integrations/image/README.md8
-rw-r--r--packages/integrations/image/src/loaders/index.ts4
-rw-r--r--packages/integrations/image/src/loaders/sharp.ts16
-rw-r--r--packages/integrations/image/test/background-color-image-ssg.test.js11
-rw-r--r--packages/integrations/image/test/background-color-image-ssr.test.js28
-rw-r--r--packages/integrations/image/test/fixtures/background-color-image/src/pages/index.astro10
7 files changed, 66 insertions, 16 deletions
diff --git a/.changeset/grumpy-monkeys-watch.md b/.changeset/grumpy-monkeys-watch.md
new file mode 100644
index 000000000..5eb33f6ce
--- /dev/null
+++ b/.changeset/grumpy-monkeys-watch.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/image': patch
+---
+
+Prevent background flattening on formats supporting transparency
diff --git a/packages/integrations/image/README.md b/packages/integrations/image/README.md
index fe3a69901..497479302 100644
--- a/packages/integrations/image/README.md
+++ b/packages/integrations/image/README.md
@@ -195,15 +195,17 @@ A `number` can also be provided, useful when the aspect ratio is calculated at b
**Default:** `undefined`
</p>
-The background color to use for replacing the alpha channel with `sharp`'s `flatten` method. In case the output format
+The background color is used to fill the remaining background when using `contain` for the `fit` property.
+
+The background color is also used for replacing the alpha channel with `sharp`'s `flatten` method. In case the output format
doesn't support transparency (i.e. `jpeg`), it's advisable to include a background color, otherwise black will be used
as default replacement for transparent pixels.
The parameter accepts a `string` as value.
The parameter can be a [named HTML color](https://www.w3schools.com/tags/ref_colornames.asp), a hexadecimal
-color representation with 3 or 6 hexadecimal characters in the form `#123[abc]`, or an RGB definition in the form
-`rgb(100,100,100)`.
+color representation with 3 or 6 hexadecimal characters in the form `#123[abc]`, an RGB definition in the form
+`rgb(100,100,100)`, an RGBA definition in the form `rgba(100,100,100, 0.5)`.
#### fit
diff --git a/packages/integrations/image/src/loaders/index.ts b/packages/integrations/image/src/loaders/index.ts
index 801a19300..50b33b9e4 100644
--- a/packages/integrations/image/src/loaders/index.ts
+++ b/packages/integrations/image/src/loaders/index.ts
@@ -19,7 +19,9 @@ export type ColorDefinition =
| NamedColor
| `#${string}`
| `rgb(${number}, ${number}, ${number})`
- | `rgb(${number},${number},${number})`;
+ | `rgb(${number},${number},${number})`
+ | `rgba(${number}, ${number}, ${number}, ${number})`
+ | `rgba(${number},${number},${number},${number})`
export type CropFit = 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
diff --git a/packages/integrations/image/src/loaders/sharp.ts b/packages/integrations/image/src/loaders/sharp.ts
index fe11295a5..e7ef57aa0 100644
--- a/packages/integrations/image/src/loaders/sharp.ts
+++ b/packages/integrations/image/src/loaders/sharp.ts
@@ -1,5 +1,10 @@
import sharp from 'sharp';
-import { ColorDefinition, isAspectRatioString, isOutputFormat } from '../loaders/index.js';
+import {
+ ColorDefinition,
+ isAspectRatioString,
+ isOutputFormat,
+ isOutputFormatSupportsAlpha,
+} from '../loaders/index.js';
import type { OutputFormat, SSRImageService, TransformOptions } from './index.js';
class SharpService implements SSRImageService {
@@ -119,13 +124,12 @@ class SharpService implements SSRImageService {
});
}
- // remove alpha channel and replace with background color if requested
- if (transform.background) {
- sharpImage.flatten({ background: transform.background });
- }
-
if (transform.format) {
sharpImage.toFormat(transform.format, { quality: transform.quality });
+
+ if (transform.background && !isOutputFormatSupportsAlpha(transform.format)) {
+ sharpImage.flatten({ background: transform.background });
+ }
}
const { data, info } = await sharpImage.toBuffer({ resolveWithObject: true });
diff --git a/packages/integrations/image/test/background-color-image-ssg.test.js b/packages/integrations/image/test/background-color-image-ssg.test.js
index 3c488a3ff..6c4423615 100644
--- a/packages/integrations/image/test/background-color-image-ssg.test.js
+++ b/packages/integrations/image/test/background-color-image-ssg.test.js
@@ -106,6 +106,17 @@ describe('SSG image with background - build', function () {
id: '#rgb-spaced',
bg: [105, 105, 105],
},
+
+ {
+ title: 'RGBA color',
+ id: '#rgba',
+ bg: [105, 105, 105],
+ },
+ {
+ title: 'RGBA color with spaces',
+ id: '#rgba-spaced',
+ bg: [105, 105, 105],
+ },
].forEach(({ title, id, bg }) => {
it(title, async () => {
const image = $(id);
diff --git a/packages/integrations/image/test/background-color-image-ssr.test.js b/packages/integrations/image/test/background-color-image-ssr.test.js
index ff4c208f8..148c57a5b 100644
--- a/packages/integrations/image/test/background-color-image-ssr.test.js
+++ b/packages/integrations/image/test/background-color-image-ssr.test.js
@@ -31,7 +31,7 @@ describe('SSR image with background', function () {
title: 'Hex color',
id: '#hex',
query: {
- f: 'avif',
+ f: 'jpeg',
w: '256',
h: '256',
href: /^\/assets\/file-icon.\w{8}.png/,
@@ -42,7 +42,7 @@ describe('SSR image with background', function () {
title: 'Hex color short',
id: '#hex-short',
query: {
- f: 'png',
+ f: 'jpeg',
w: '256',
h: '256',
href: /^\/assets\/file-icon.\w{8}.png/,
@@ -53,7 +53,7 @@ describe('SSR image with background', function () {
title: 'RGB color',
id: '#rgb',
query: {
- f: 'webp',
+ f: 'jpeg',
w: '256',
h: '256',
href: /^\/assets\/file-icon.\w{8}.png/,
@@ -71,6 +71,28 @@ describe('SSR image with background', function () {
bg: 'rgb(105, 105, 105)',
},
},
+ {
+ title: 'RGBA color',
+ id: '#rgba',
+ query: {
+ f: 'jpeg',
+ w: '256',
+ h: '256',
+ href: /^\/assets\/file-icon.\w{8}.png/,
+ bg: 'rgb(105,105,105,0.5)',
+ },
+ },
+ {
+ title: 'RGBA color with spaces',
+ id: '#rgba-spaced',
+ query: {
+ f: 'jpeg',
+ w: '256',
+ h: '256',
+ href: /^\/assets\/file-icon.\w{8}.png/,
+ bg: 'rgb(105, 105, 105, 0.5)',
+ },
+ },
].forEach(({ title, id, query }) => {
it(title, async () => {
const app = await fixture.loadTestAdapterApp();
diff --git a/packages/integrations/image/test/fixtures/background-color-image/src/pages/index.astro b/packages/integrations/image/test/fixtures/background-color-image/src/pages/index.astro
index 3ad137457..76f1fe936 100644
--- a/packages/integrations/image/test/fixtures/background-color-image/src/pages/index.astro
+++ b/packages/integrations/image/test/fixtures/background-color-image/src/pages/index.astro
@@ -9,13 +9,17 @@ import { Image } from '@astrojs/image/components';
<body>
<Image id="named" src={import('../assets/file-icon.png')} width={256} format="jpeg" background="dimgray" alt="named" />
<br />
- <Image id="hex" src={import('../assets/file-icon.png')} width={256} format="avif" background="#696969" alt="hex" />
+ <Image id="hex" src={import('../assets/file-icon.png')} width={256} format="jpeg" background="#696969" alt="hex" />
<br />
- <Image id="hex-short" src={import('../assets/file-icon.png')} width={256} background="#666" alt="hex-short" />
+ <Image id="hex-short" src={import('../assets/file-icon.png')} width={256} format="jpeg" background="#666" alt="hex-short" />
<br />
- <Image id="rgb" src={import('../assets/file-icon.png')} width={256} format="webp" background="rgb(105,105,105)" alt="rgb" />
+ <Image id="rgb" src={import('../assets/file-icon.png')} width={256} format="jpeg" background="rgb(105,105,105)" alt="rgb" />
<br />
<Image id="rgb-spaced" src={import('../assets/file-icon.png')} width={256} format="jpeg" background="rgb(105, 105, 105)" alt="rgb-spaced" />
<br />
+ <Image id="rgba" src={import('../assets/file-icon.png')} width={256} format="jpeg" background="rgb(105,105,105,0.5)" alt="rgba" />
+ <br />
+ <Image id="rgba-spaced" src={import('../assets/file-icon.png')} width={256} format="jpeg" background="rgb(105, 105, 105, 0.5)" alt="rgba-spaced" />
+ <br />
</body>
</html>