Skip to content

Commit

Permalink
Add limitInputPixels option for sharp image service (#9546)
Browse files Browse the repository at this point in the history
* Add limitInputPixels option for sharp image service

* Fix types

* Update docs

Co-authored-by: sarah11918 <sarah11918@users.noreply.github.com>

---------

Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Co-authored-by: sarah11918 <sarah11918@users.noreply.github.com>
  • Loading branch information
3 people committed Jan 3, 2024
1 parent d239e2c commit 08402ad
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 8 deletions.
21 changes: 21 additions & 0 deletions .changeset/poor-apes-cheat.md
@@ -0,0 +1,21 @@
---
'astro': minor
---

Adds an option for the Sharp image service to allow large images to be processed. Set `limitInputPixels: false` to bypass the default image size limit:

```js
// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
image: {
service: {
entrypoint: 'astro/assets/services/sharp',
config: {
limitInputPixels: false,
},
},
},
});
```
3 changes: 2 additions & 1 deletion packages/astro/config.d.ts
Expand Up @@ -2,6 +2,7 @@ type ViteUserConfig = import('vite').UserConfig;
type ViteUserConfigFn = import('vite').UserConfigFn;
type AstroUserConfig = import('./dist/@types/astro.js').AstroUserConfig;
type ImageServiceConfig = import('./dist/@types/astro.js').ImageServiceConfig;
type SharpImageServiceConfig = import('./dist/assets/services/sharp.js').SharpImageServiceConfig;

/**
* See the full Astro Configuration API Documentation
Expand All @@ -17,7 +18,7 @@ export function getViteConfig(config: ViteUserConfig): ViteUserConfigFn;
/**
* Return the configuration needed to use the Sharp-based image service
*/
export function sharpImageService(): ImageServiceConfig;
export function sharpImageService(config?: SharpImageServiceConfig): ImageServiceConfig;

/**
* Return the configuration needed to use the Squoosh-based image service
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/config.mjs
@@ -1,9 +1,9 @@
export { defineConfig, getViteConfig } from './dist/config/index.js';

export function sharpImageService() {
export function sharpImageService(config = {}) {
return {
entrypoint: 'astro/assets/services/sharp',
config: {},
config,
};
}

Expand Down
9 changes: 7 additions & 2 deletions packages/astro/src/@types/astro.ts
Expand Up @@ -1096,8 +1096,13 @@ export interface AstroUserConfig {
* ```js
* {
* image: {
* // Example: Enable the Sharp-based image service
* service: { entrypoint: 'astro/assets/services/sharp' },
* // Example: Enable the Sharp-based image service with a custom config
* service: {
* entrypoint: 'astro/assets/services/sharp',
* config: {
* limitInputPixels: false,
* },
* },
* },
* }
* ```
Expand Down
17 changes: 14 additions & 3 deletions packages/astro/src/assets/services/sharp.ts
Expand Up @@ -8,6 +8,13 @@ import {
type LocalImageService,
} from './service.js';

export interface SharpImageServiceConfig {
/**
* The `limitInputPixels` option passed to Sharp. See https://sharp.pixelplumbing.com/api-constructor for more information
*/
limitInputPixels?: number;
}

let sharp: typeof import('sharp');

const qualityTable: Record<ImageQualityPreset, number> = {
Expand All @@ -28,13 +35,13 @@ async function loadSharp() {
return sharpImport;
}

const sharpService: LocalImageService = {
const sharpService: LocalImageService<SharpImageServiceConfig> = {
validateOptions: baseService.validateOptions,
getURL: baseService.getURL,
parseURL: baseService.parseURL,
getHTMLAttributes: baseService.getHTMLAttributes,
getSrcSet: baseService.getSrcSet,
async transform(inputBuffer, transformOptions) {
async transform(inputBuffer, transformOptions, config) {
if (!sharp) sharp = await loadSharp();

const transform: BaseServiceTransform = transformOptions as BaseServiceTransform;
Expand All @@ -43,7 +50,11 @@ const sharpService: LocalImageService = {
// TODO: Sharp has some support for SVGs, we could probably support this once Sharp is the default and only service.
if (transform.format === 'svg') return { data: inputBuffer, format: 'svg' };

let result = sharp(inputBuffer, { failOnError: false, pages: -1 });
const result = sharp(inputBuffer, {
failOnError: false,
pages: -1,
limitInputPixels: config.service.config.limitInputPixels,
});

// always call rotate to adjust for EXIF data orientation
result.rotate();
Expand Down

0 comments on commit 08402ad

Please sign in to comment.