aboutsummaryrefslogtreecommitdiff
path: root/packages/integrations/image/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/image/src/lib')
-rw-r--r--packages/integrations/image/src/lib/get-image.ts159
-rw-r--r--packages/integrations/image/src/lib/get-picture.ts105
2 files changed, 0 insertions, 264 deletions
diff --git a/packages/integrations/image/src/lib/get-image.ts b/packages/integrations/image/src/lib/get-image.ts
deleted file mode 100644
index 37f6a3bc4..000000000
--- a/packages/integrations/image/src/lib/get-image.ts
+++ /dev/null
@@ -1,159 +0,0 @@
-/// <reference types="astro/astro-jsx" />
-import type { ImageService, OutputFormat, TransformOptions } from '../loaders/index.js';
-import { isSSRService, parseAspectRatio } from '../loaders/index.js';
-import { isRemoteImage } from '../utils/paths.js';
-import type { ImageMetadata } from '../vite-plugin-astro-image.js';
-
-export interface GetImageTransform extends Omit<TransformOptions, 'src'> {
- src: string | ImageMetadata | Promise<{ default: ImageMetadata }>;
- alt: string;
-}
-
-function resolveSize(transform: TransformOptions): TransformOptions {
- // keep width & height as provided
- if (transform.width && transform.height) {
- return transform;
- }
-
- if (!transform.width && !transform.height) {
- throw new Error(`"width" and "height" cannot both be undefined`);
- }
-
- if (!transform.aspectRatio) {
- throw new Error(
- `"aspectRatio" must be included if only "${transform.width ? 'width' : 'height'}" is provided`
- );
- }
-
- let aspectRatio: number;
-
- // parse aspect ratio strings, if required (ex: "16:9")
- if (typeof transform.aspectRatio === 'number') {
- aspectRatio = transform.aspectRatio;
- } else {
- const [width, height] = transform.aspectRatio.split(':');
- aspectRatio = Number.parseInt(width) / Number.parseInt(height);
- }
-
- if (transform.width) {
- // only width was provided, calculate height
- return {
- ...transform,
- width: transform.width,
- height: Math.round(transform.width / aspectRatio),
- } as TransformOptions;
- } else if (transform.height) {
- // only height was provided, calculate width
- return {
- ...transform,
- width: Math.round(transform.height * aspectRatio),
- height: transform.height,
- };
- }
-
- return transform;
-}
-
-async function resolveTransform(input: GetImageTransform): Promise<TransformOptions> {
- // for remote images, only validate the width and height props
- if (typeof input.src === 'string') {
- return resolveSize(input as TransformOptions);
- }
-
- // resolve the metadata promise, usually when the ESM import is inlined
- const metadata = 'then' in input.src ? (await input.src).default : input.src;
-
- let { width, height, aspectRatio, background, format = metadata.format, ...rest } = input;
-
- if (!width && !height) {
- // neither dimension was provided, use the file metadata
- width = metadata.width;
- height = metadata.height;
- } else if (width) {
- // one dimension was provided, calculate the other
- let ratio = parseAspectRatio(aspectRatio) || metadata.width / metadata.height;
- height = height || Math.round(width / ratio);
- } else if (height) {
- // one dimension was provided, calculate the other
- let ratio = parseAspectRatio(aspectRatio) || metadata.width / metadata.height;
- width = width || Math.round(height * ratio);
- }
-
- return {
- ...rest,
- src: metadata.src,
- width,
- height,
- aspectRatio,
- format: format as OutputFormat,
- background,
- };
-}
-
-/**
- * Gets the HTML attributes required to build an `<img />` for the transformed image.
- *
- * @param transform @type {TransformOptions} The transformations requested for the optimized image.
- * @returns @type {ImageAttributes} The HTML attributes to be included on the built `<img />` element.
- */
-export async function getImage(
- transform: GetImageTransform
-): Promise<astroHTML.JSX.ImgHTMLAttributes> {
- if (!transform.src) {
- throw new Error('[@astrojs/image] `src` is required');
- }
-
- let loader = globalThis.astroImage?.loader;
-
- if (!loader) {
- // @ts-expect-error
- const { default: mod } = await import('virtual:image-loader').catch(() => {
- throw new Error(
- '[@astrojs/image] Builtin image loader not found. (Did you remember to add the integration to your Astro config?)'
- );
- });
- loader = mod as ImageService;
- globalThis.astroImage = globalThis.astroImage || {};
- globalThis.astroImage.loader = loader;
- }
-
- const resolved = await resolveTransform(transform);
-
- const attributes = await loader.getImageAttributes(resolved);
-
- // `.env` must be optional to support running in environments outside of `vite` (such as `astro.config`)
- // @ts-expect-error
- const isDev = import.meta.env?.DEV;
- const isLocalImage = !isRemoteImage(resolved.src);
-
- const _loader = isDev && isLocalImage ? globalThis.astroImage.defaultLoader : loader;
-
- if (!_loader) {
- throw new Error('@astrojs/image: loader not found!');
- }
-
- const { searchParams } = isSSRService(_loader)
- ? _loader.serializeTransform(resolved)
- : globalThis.astroImage.defaultLoader.serializeTransform(resolved);
-
- const imgSrc =
- !isLocalImage && resolved.src.startsWith('//') ? `https:${resolved.src}` : resolved.src;
- let src: string;
-
- if (/^[\/\\]?@astroimage/.test(imgSrc)) {
- src = `${imgSrc}?${searchParams.toString()}`;
- } else {
- searchParams.set('href', imgSrc);
- src = `/_image?${searchParams.toString()}`;
- }
-
- // cache all images rendered to HTML
- if (globalThis.astroImage?.addStaticImage) {
- src = globalThis.astroImage.addStaticImage(resolved);
- }
-
- return {
- ...attributes,
- src,
- };
-}
diff --git a/packages/integrations/image/src/lib/get-picture.ts b/packages/integrations/image/src/lib/get-picture.ts
deleted file mode 100644
index c0eaa4058..000000000
--- a/packages/integrations/image/src/lib/get-picture.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-/// <reference types="astro/astro-jsx" />
-import mime from 'mime';
-import { parseAspectRatio, type OutputFormat, type TransformOptions } from '../loaders/index.js';
-import { extname } from '../utils/paths.js';
-import type { ImageMetadata } from '../vite-plugin-astro-image.js';
-import { getImage } from './get-image.js';
-
-export interface GetPictureParams {
- src: string | ImageMetadata | Promise<{ default: ImageMetadata }>;
- alt: string;
- widths: number[];
- formats: OutputFormat[];
- aspectRatio?: TransformOptions['aspectRatio'];
- fit?: TransformOptions['fit'];
- background?: TransformOptions['background'];
- position?: TransformOptions['position'];
-}
-
-export interface GetPictureResult {
- image: astroHTML.JSX.ImgHTMLAttributes;
- sources: { type: string; srcset: string }[];
-}
-
-async function resolveAspectRatio({ src, aspectRatio }: GetPictureParams) {
- if (typeof src === 'string') {
- return parseAspectRatio(aspectRatio);
- } else {
- const metadata = 'then' in src ? (await src).default : src;
- return parseAspectRatio(aspectRatio) || metadata.width / metadata.height;
- }
-}
-
-async function resolveFormats({ src, formats }: GetPictureParams) {
- const unique = new Set(formats);
-
- if (typeof src === 'string') {
- unique.add(extname(src).replace('.', '') as OutputFormat);
- } else {
- const metadata = 'then' in src ? (await src).default : src;
- unique.add(extname(metadata.src).replace('.', '') as OutputFormat);
- }
-
- return Array.from(unique).filter(Boolean);
-}
-
-export async function getPicture(params: GetPictureParams): Promise<GetPictureResult> {
- const { src, alt, widths, fit, position, background } = params;
-
- if (!src) {
- throw new Error('[@astrojs/image] `src` is required');
- }
-
- if (!widths || !Array.isArray(widths)) {
- throw new Error('[@astrojs/image] at least one `width` is required. ex: `widths={[100]}`');
- }
-
- const aspectRatio = await resolveAspectRatio(params);
-
- if (!aspectRatio) {
- throw new Error('`aspectRatio` must be provided for remote images');
- }
-
- // always include the original image format
- const allFormats = await resolveFormats(params);
- const lastFormat = allFormats[allFormats.length - 1];
- const maxWidth = Math.max(...widths);
-
- let image: astroHTML.JSX.ImgHTMLAttributes;
-
- async function getSource(format: OutputFormat) {
- const imgs = await Promise.all(
- widths.map(async (width) => {
- const img = await getImage({
- src,
- alt,
- format,
- width,
- fit,
- position,
- background,
- aspectRatio,
- });
-
- if (format === lastFormat && width === maxWidth) {
- image = img;
- }
-
- return `${img.src?.replaceAll(' ', encodeURI)} ${width}w`;
- })
- );
-
- return {
- type: mime.getType(format) || format,
- srcset: imgs.join(','),
- };
- }
-
- const sources = await Promise.all(allFormats.map((format) => getSource(format)));
-
- return {
- sources,
- // @ts-expect-error image will always be defined
- image,
- };
-}