diff options
Diffstat (limited to 'packages/integrations/image/src/lib')
-rw-r--r-- | packages/integrations/image/src/lib/get-image.ts | 159 | ||||
-rw-r--r-- | packages/integrations/image/src/lib/get-picture.ts | 105 |
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, - }; -} |