UNPKG

@thi.ng/imago

Version:

JSON & API-based declarative and extensible image processing trees/pipelines

493 lines 15.5 kB
import type { Fn, Fn3, IObjectOf, Keys, Range1_4, TypedArray, UIntArray } from "@thi.ng/api"; import type { ILogger } from "@thi.ng/logger"; import type { AvifOptions, Blend, Exif, ExtendWith, FitEnum, GifOptions, Jp2Options, JpegOptions, JxlOptions, KernelEnum, Metadata, OverlayOptions, PngOptions, Sharp, TiffOptions, TileOptions, WebpOptions } from "sharp"; /** * ```text * nw -- n -- ne * | | | * w -- c -- e * | | | * sw -- s -- se * ``` */ export type Gravity = "c" | "e" | "n" | "ne" | "nw" | "s" | "se" | "sw" | "w"; /** * See [thi.ng/pixel-dither](https://thi.ng/pixel-dither) for reference */ export type DitherMode = "atkinson" | "burkes" | "column" | "diffusion" | "floyd" | "jarvis" | "row" | "sierra" | "stucki" | "bayer"; export type Dim = [number, number]; export type Size = number | Dim; export type Sides = [number, number, number, number]; export type SizeRef = "min" | "max" | "w" | "h" | "both"; export type SizeUnit = "px" | "%"; /** * If given as array, the color is interpreted as `[r,g,b,a?]` */ export type Color = string | number[] | { r: number; g: number; b: number; alpha?: number; }; /** * Position defined by max. 2 components/coordinates. If none are defined, the * position will be interpreted as centered. */ export interface Position { l?: number; r?: number; t?: number; b?: number; } export type BufferLike = TypedArray | Buffer; /** * Simplified interface of thi.ng/pixel `IntBuffer`, only defining parts * relevant to the conversion for {@link processImage}. */ export interface IntBufferLike { width: number; height: number; format: { channels: unknown[]; }; data: UIntArray; } export type Processor = Fn3<ProcSpec, Sharp, ImgProcCtx, Promise<[Sharp, boolean]>>; export type CompLayerFn = Fn3<CompLayer, Sharp, ImgProcCtx, Promise<OverlayOptions>>; export interface ProcSpec { /** * Unique processor ID. Used to by {@link processor} to select correct * implementation. */ op: string; } export interface BlurSpec extends ProcSpec { op: "blur"; /** * Blur radius in pixels (can be fractional) */ radius: number; } export interface CompSpec extends ProcSpec { op: "composite"; layers: CompLayer[]; } export interface CompLayer { /** * Unique layer type, used by {@link composite} and {@link defLayer} to * select correct layer implementation. */ type: string; /** * Layer blend mode. See [Sharp * docs](https://sharp.pixelplumbing.com/api-composite#composite) for list * of available modes. * * @defaultValue "over" */ blend?: Blend; /** * Abstracted layer position. This option is only used if no * {@link CompLayer.pos} is specified. It also controls alignment * of tiling when {@link CompLayer.tile} is enabled. If neither gravity * or position are configured, the layer will be centered. */ gravity?: Gravity; /** * Partial layer position given in units of {@link CompLayer.unit}. At * most 2 coordinate can be given here (e.g. left & top). The right & bottom * values are overriding left/top (in case of conflict). * * @remarks * Note: This option takes precedence over {@link CompLayer.gravity}. If * neither gravity or position are configured, the layer will be centered. */ pos?: Position; /** * Origin/reference point for the given layer position * {@link CompLayer.pos}. Only used if position is given. * * @remarks * The given value specifies one of the 9 points in the layer which is to be * used for the layer position (e.g. "se" for south-east aka bottom-right * corner). * * If not given, it will be auto-determined by provided position config, * e.g. a `pos` with right & top coords will have an implicit origin of `ne` * (aka north-east). See gravity diagram {@link Gravity}. */ origin?: Gravity; /** * Only used if {@link CompLayer.unit} is percent (`%`). Reference side * ID for computing positions and sizes. See {@link SizeRef} for details. * * @defaultValue "both" */ ref?: SizeRef; /** * If true, the layer will be repeated across the entire image with the * given {@link CompLayer.gravity}. */ tile?: boolean; /** * Unit to use for {@link CompLayer.pos} and sizes (where * supported). If `%`, the given values are interpreted as percentages, * relative to configured {@link CompLayer.ref} side. * * @defaultValue "px" */ unit?: SizeUnit; [id: string]: any; } export interface ColorLayer extends CompLayer { type: "color"; /** * Layer fill/background color. */ bg: Color; size?: Size; } export interface ImgLayer extends CompLayer { type: "img"; /** * Image as buffer (must be in one of sharp's supported image formats, use * {@link rawLayer} / {@link RawLayer} for compositing raw image data) */ buffer?: BufferLike; /** * File path to image, alternative to {@link ImgLayer.buffer}. */ path?: string; /** * Layer target size (in units defined via {@link CompLayer.unit}) */ size?: Size; } export interface RawLayer extends CompLayer { type: "raw"; buffer: BufferLike; channels: Range1_4; size: [number, number]; } export interface SVGLayer extends CompLayer { type: "svg"; /** * Inline SVG document, alternative to {@link SVGLayer.path}. */ body?: string; /** * File path to SVG document. */ path?: string; } export interface TextLayer extends CompLayer { type: "text"; /** * Background color. * * @defaultValue "#0000" */ bg?: string; /** * Body text. Alternative to {@link TextLayer.path}. If given as function, * the function will be called with the processing context and must return a * string. * * @defaultValue "" */ body?: string | Fn<ImgProcCtx, string>; /** * Text color * * @defaultValue "#fff" */ color?: string; font?: string; fontSize?: number | string; padding?: number; path?: string; /** * Layer/textbox size. Required */ size: Dim; textGravity?: Gravity; } export interface CropSpec extends ProcSpec { op: "crop"; /** * Target aspect ratio. Only used if {@link CropSpec.size} is given as * single numeric value (pixels or percentage). If the aspect ratio is >1, * the general aspect of the cropped image will remain principally the same, * i.e. a portait image will remain portait (but cropped), ditto for * landscape. If the given aspect raatio is <1, the aspect of the image will * be flipped/swapped, i.e. a portait aspect becomes landscape and vice * versa. * * @example * ```js * // crop image to 3:2 aspect ratio * { op: "crop", size: 100, unit: "%", aspect: 3/2 } * ``` */ aspect?: number; border?: Size | Sides; gravity?: Gravity; origin?: Gravity; pos?: Position; ref?: SizeRef; size?: Size; unit?: SizeUnit; } export interface DitherSpec extends ProcSpec { op: "dither"; mode: DitherMode; num: number; rgb?: boolean; size?: 2 | 4 | 8; } export interface EXIFSpec extends ProcSpec { op: "exif"; tags: Exif; } export interface ExtendSpec extends ProcSpec { op: "extend"; bg?: Color; border: Size | Sides; mode?: ExtendWith; ref?: SizeRef; unit?: SizeUnit; } export interface GammaSpec extends ProcSpec { op: "gamma"; gamma: number; } export interface GrayscaleSpec extends ProcSpec { op: "gray"; gamma?: number | boolean; } export interface HSBLSpec extends ProcSpec { op: "hsbl"; h?: number; s?: number; b?: number; l?: number; } export interface ICCSpec extends ProcSpec { op: "icc"; /** * ICC profile preset name */ profile?: "srgb" | "p3" | "cmyk"; /** * ICC profile file path (can be relative) */ path?: string; } export interface NestSpec extends ProcSpec { op: "nest"; /** * Array of one or more arrays of processing pipeline specs. All pipelines * are spawned via `Promise.all()` and each one receives a separate clone of * the current input image. */ procs: ProcSpec[][]; } export interface OutputSpec extends ProcSpec { op: "output"; /** * Unique ID of this output, used to record the file path in the `outputs` * object returned by {@link processImage}. */ id: string; /** * Possibly templated output path. See {@link formatPath} for details. * Ignored if {@link OutputSpec.blurhash} is being used. * * Otherwise, if given, the image will be written to the result path and the * path stored in the `outputs` object returned by {@link processImage}. If * no path is given, no file will be written and the encoded image buffer * itself will be recorded in `outputs`. */ path?: string; /** * AVIF output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#avif) */ avif?: AvifOptions; /** * If given, ONLY the blurhash of the image will be computed and stored in * the `outputs` object returned by {@link processImage}. The * {@link OutputSpec.path} will be ignored and no file will be written. * * @remarks * The value given is the blurhash detail setting in the `[1,9]` range * (usual default is 4), possibly given separately for X/Y axes. * * Important: Ensure the image has already been downsized to ~50-500 pixels. * Larger images are causing unnecessary & long processing... */ blurhash?: true | number | [number, number]; /** * GIF output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#gif) */ gif?: GifOptions; /** * JPEG 2000 output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#jp2) */ jp2?: Jp2Options; /** * JPEG output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#jpeg) */ jpeg?: JpegOptions; /** * JPEG XL output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#jxl) */ jxl?: JxlOptions; /** * PNG output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#avif) */ png?: PngOptions; /** * Raw binary output options. */ raw?: boolean | { /** * If true, ensures the buffer has an alpha channel */ alpha?: boolean; /** * If true, writes a secondary file with this buffer's metadata (in * the same dir, using `.meta.json` as suffix) */ meta?: boolean; }; /** * Tiled format output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#tile) */ tile?: TileOptions; /** * TIFF output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#tiff) */ tiff?: TiffOptions; /** * WebP output options. See [Sharp docs](https://sharp.pixelplumbing.com/api-output#webp) */ webp?: WebpOptions; /** * Only used if {@link OutputSpec.path} is NOT set. If true, output will be * captured as data URL, otherwise as binary data/buffer. * * @remarks * Other conditions: * * - Requires {@link OutputSpec.format} to be set to a data URL compatible * image format. * - An error will be thrown during processing if the encoded image size * exceeds 32KB. */ dataURL?: boolean; } export interface ResizeSpec extends ProcSpec { op: "resize"; bg?: Color; filter?: Keys<KernelEnum>; fit?: Keys<FitEnum>; gravity?: Gravity; ref?: SizeRef; /** * New size of the image, expressed in pixels or percentages. * * @remarks * If using pixels and size is a single number, it will be interpreted as * the target size of the longest side and the other side scaled * proportionally, using current aspect ratio. * * If given as `[width,height]` tuple, a negative value for a side makes * that side proportionally scaled. relative to the other. E.g. a size of * `[1280,-1]` scales the image to 1280 pixels wide and the height computed * based on current aspect ratio. */ size: Size; unit?: SizeUnit; } export interface RotateSpec extends ProcSpec { op: "rotate"; angle?: number; bg?: Color; flipX?: boolean; flipY?: boolean; } export interface ImgProcOpts { /** * Logger instance to use (by default uses builtin module logger, linked to * umbrella `ROOT` logger) */ logger: ILogger; /** * Base directory for {@link output} steps */ outDir: string; /** * By default all input metadata will be lost in the output(s). If this * option is enabled, keeps existing EXIF data and attaches it to output * (also where the output format actually supports it). * * @remarks * TODO currently still unsupported */ keepEXIF: boolean; /** * By default all input metadata will be lost in the output(s). If this * option is enabled, keeps existing ICC profile from input image and * attaches it to output (also where the output format actually supports * it). */ keepICC: boolean; /** * An object with custom output path replacements for {@link formatPath}. If * a given replacement value is a function, it will be called with the * current {@link ImgProcCtx}, the current {@link OutputSpec} (e.g. to * obtain configured options) and the already serialized image as buffer. * * @remarks * Replacement IDs in this object will take precedence over built-in * replacement IDs, e.g. allowing to override `name`, `date` etc. */ pathParts: Record<string, Fn3<ImgProcCtx, OutputSpec, BufferLike, string> | string>; /** * User provided environment, i.e. an object to provide arbitrary values to * {@link Processor}s and for them to store results in. * * @remarks * Note: This option is optional. Processors should only access the * environment via {@link ImgProcCtx.env} which ensures the object is * defined and it is only that version which will also be returned as part * of the results from {@link processImage}... */ env?: IObjectOf<any>; } export interface ImgProcCtx { path?: string; size: Dim; meta: Metadata; exif: Exif; iccFile?: string; logger: ILogger; opts: Partial<ImgProcOpts>; /** * Paths of all exported images, keyed by IDs given via {@link OutputSpec} / * {@link output}. */ outputs: Record<string, string | Buffer>; /** * Recorded metadata of outputs which requested it, keyed by IDs given via * {@link OutputSpec} / {@link output} (current `raw` format only). */ outputMeta: Record<string, Record<string, any>>; /** * See {@link ImgProcOpts.env} for details/comments. */ env: IObjectOf<any>; } export declare const GRAVITY_POSITION: Record<Gravity, string>; export declare const GRAVITY_MAP: Record<Gravity, string>; //# sourceMappingURL=api.d.ts.map