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

Add limitInputPixels option for sharp image service #9546

Merged
merged 8 commits into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .changeset/poor-apes-cheat.md
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -1090,8 +1090,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
Original file line number Diff line number Diff line change
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,
Princesseuh marked this conversation as resolved.
Show resolved Hide resolved
});

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