diff --git a/.changeset/smooth-goats-agree.md b/.changeset/smooth-goats-agree.md
index 13e65d6a7..efa7b8434 100644
--- a/.changeset/smooth-goats-agree.md
+++ b/.changeset/smooth-goats-agree.md
@@ -6,7 +6,9 @@ Add support for generating multiple widths when using the Image component and a
## `srcset` support
-The current usage is as follow:
+Two new properties have been added to `Image` and `getImage`: `densities` and `widths`.
+
+These props can be used to generate a `srcset` attribute with multiple sources. For example:
```astro
---
@@ -14,17 +16,13 @@ import { Image } from "astro";
import myImage from "./my-image.jpg";
---
-
+
```
-Alternatively to `densities`, `widths` can be used for specific widths. In both cases, according images and the following code will be generated:
-
```html
```
-(if `widths` is used the descriptor will be `w` instead of `x`)
-
## Picture component
The `Picture` component can be used to generate a `
```
-The `Picture` component takes all the same props as the `Image` component, including `densities` and `widths`.
+The `Picture` component takes all the same props as the `Image` component, including the new `densities` and `widths` properties.
diff --git a/packages/astro/src/assets/services/service.ts b/packages/astro/src/assets/services/service.ts
index f3738e20e..9812c95c3 100644
--- a/packages/astro/src/assets/services/service.ts
+++ b/packages/astro/src/assets/services/service.ts
@@ -45,7 +45,10 @@ interface SharedServiceProps = Record
*/
getURL: (options: ImageTransform, imageConfig: ImageConfig) => string | Promise;
/**
- * TODO: Document
+ * Generate additional `srcset` values for the image.
+ *
+ * While in most cases this is exclusively used for `srcset`, it can also be used in a more generic way to generate
+ * multiple variants of the same image. For instance, you can use this to generate multiple aspect ratios or multiple formats.
*/
getSrcSet?: (
options: ImageTransform,
@@ -226,8 +229,9 @@ export const baseService: Omit = {
const aspectRatio = targetWidth / targetHeight;
const imageWidth = isESMImportedImage(options.src) ? options.src.width : options.width;
- const maxWidth = options.width ?? imageWidth ?? Infinity;
+ const maxWidth = imageWidth ?? Infinity;
+ // REFACTOR: Could we merge these two blocks?
if (densities) {
const densityValues = densities.map((density) => {
if (typeof density === 'number') {
@@ -244,9 +248,12 @@ export const baseService: Omit = {
densityWidths.forEach((width, index) => {
const maxTargetWidth = Math.min(width, maxWidth);
+ // If the user passed dimensions, we don't want to add it to the srcset
+ const { width: transformWidth, height: transformHeight, ...rest } = options;
+
const srcSetValue = {
transform: {
- ...options,
+ ...rest,
},
descriptor: `${densityValues[index]}x`,
attributes: {
@@ -254,7 +261,7 @@ export const baseService: Omit = {
},
};
- // Only set width and height if they are different from the original image
+ // Only set width and height if they are different from the original image, to avoid duplicated final images
if (maxTargetWidth !== imageWidth) {
srcSetValue.transform.width = maxTargetWidth;
srcSetValue.transform.height = Math.round(maxTargetWidth / aspectRatio);
@@ -270,9 +277,11 @@ export const baseService: Omit = {
widths.forEach((width) => {
const maxTargetWidth = Math.min(width, maxWidth);
+ const { width: transformWidth, height: transformHeight, ...rest } = options;
+
const srcSetValue = {
transform: {
- ...options,
+ ...rest,
},
descriptor: `${width}w`,
attributes: {
@@ -280,7 +289,6 @@ export const baseService: Omit = {
},
};
- // Only set width and height if they are different from the original image
if (maxTargetWidth !== imageWidth) {
srcSetValue.transform.width = maxTargetWidth;
srcSetValue.transform.height = Math.round(maxTargetWidth / aspectRatio);
diff --git a/packages/astro/src/assets/services/sharp.ts b/packages/astro/src/assets/services/sharp.ts
index b7e856d85..215299138 100644
--- a/packages/astro/src/assets/services/sharp.ts
+++ b/packages/astro/src/assets/services/sharp.ts
@@ -50,9 +50,9 @@ const sharpService: LocalImageService = {
// Never resize using both width and height at the same time, prioritizing width.
if (transform.height && !transform.width) {
- result.resize({ height: transform.height });
+ result.resize({ height: Math.round(transform.height) });
} else if (transform.width) {
- result.resize({ width: transform.width });
+ result.resize({ width: Math.round(transform.width) });
}
if (transform.format) {
diff --git a/packages/astro/src/assets/services/squoosh.ts b/packages/astro/src/assets/services/squoosh.ts
index 32aee874d..5be5d4077 100644
--- a/packages/astro/src/assets/services/squoosh.ts
+++ b/packages/astro/src/assets/services/squoosh.ts
@@ -77,12 +77,12 @@ const service: LocalImageService = {
if (transform.height && !transform.width) {
operations.push({
type: 'resize',
- height: transform.height,
+ height: Math.round(transform.height),
});
} else if (transform.width) {
operations.push({
type: 'resize',
- width: transform.width,
+ width: Math.round(transform.width),
});
}