89d76753a0
* moving all normalization logic out of the Image component
* refactor: only require loaders to provide the image src
* Adding a `<Picture />` component
* fixing types.ts imports
* refactor: moving getImage to it's own file
* updating component types to use astroHTML.JSX
* Revert "updating component types to use astroHTML.JSX"
This reverts commit 6e5f578da8
.
* going back to letting loaders add extra HTML attributes
* Always use lazy loading and async decoding
* Cleaning up the Picture component
* Adding test coverage for <Picture>
* updating the README
* using JSX types for the Image and Picture elements
* chore: adding changeset
* Update packages/integrations/image/src/get-image.ts
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
* allow users to override loading and async on the <img>
* renaming config to constants, exporting getPicture()
* found the right syntax to import astro-jsx
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
74 lines
1.8 KiB
TypeScript
74 lines
1.8 KiB
TypeScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import type { OutputFormat, TransformOptions } from './types';
|
|
|
|
export function isOutputFormat(value: string): value is OutputFormat {
|
|
return ['avif', 'jpeg', 'png', 'webp'].includes(value);
|
|
}
|
|
|
|
export function isAspectRatioString(value: string): value is `${number}:${number}` {
|
|
return /^\d*:\d*$/.test(value);
|
|
}
|
|
|
|
export function ensureDir(dir: string) {
|
|
fs.mkdirSync(dir, { recursive: true });
|
|
}
|
|
|
|
export function isRemoteImage(src: string) {
|
|
return /^http(s?):\/\//.test(src);
|
|
}
|
|
|
|
export async function loadLocalImage(src: string) {
|
|
try {
|
|
return await fs.promises.readFile(src);
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
export async function loadRemoteImage(src: string) {
|
|
try {
|
|
const res = await fetch(src);
|
|
|
|
if (!res.ok) {
|
|
return undefined;
|
|
}
|
|
|
|
return Buffer.from(await res.arrayBuffer());
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
export async function loadImage(src: string) {
|
|
return isRemoteImage(src) ? await loadRemoteImage(src) : await loadLocalImage(src);
|
|
}
|
|
|
|
export function propsToFilename({ src, width, height, format }: TransformOptions) {
|
|
const ext = path.extname(src);
|
|
let filename = src.replace(ext, '');
|
|
|
|
if (width && height) {
|
|
return `${filename}_${width}x${height}.${format}`;
|
|
} else if (width) {
|
|
return `${filename}_${width}w.${format}`;
|
|
} else if (height) {
|
|
return `${filename}_${height}h.${format}`;
|
|
}
|
|
|
|
return format ? src.replace(ext, format) : src;
|
|
}
|
|
|
|
export function parseAspectRatio(aspectRatio: TransformOptions['aspectRatio']) {
|
|
if (!aspectRatio) {
|
|
return undefined;
|
|
}
|
|
|
|
// parse aspect ratio strings, if required (ex: "16:9")
|
|
if (typeof aspectRatio === 'number') {
|
|
return aspectRatio;
|
|
} else {
|
|
const [width, height] = aspectRatio.split(':');
|
|
return parseInt(width) / parseInt(height);
|
|
}
|
|
}
|