diff --git a/src/http/schemas/transformations.ts b/src/http/schemas/transformations.ts index 907dd154..2333c650 100644 --- a/src/http/schemas/transformations.ts +++ b/src/http/schemas/transformations.ts @@ -4,4 +4,10 @@ export const transformationOptionsSchema = { resize: { type: 'string', enum: ['cover', 'contain', 'fill'] }, format: { type: 'string', enum: ['origin', 'avif'] }, quality: { type: 'integer', minimum: 20, maximum: 100 }, + gravity: { + type: 'string', + enum: ['no', 'so', 'ea', 'we', 'noea', 'nowe', 'soea', 'sowe', 'ce', 'sm', 'fp'], + }, + x_offset: { type: 'number', examples: [0.1, 100] }, + y_offset: { type: 'number', examples: [0.1, -100] }, } as const diff --git a/src/storage/renderer/image.ts b/src/storage/renderer/image.ts index d09bdcdf..985dd101 100644 --- a/src/storage/renderer/image.ts +++ b/src/storage/renderer/image.ts @@ -17,6 +17,9 @@ export interface TransformOptions { resize?: 'cover' | 'contain' | 'fill' format?: 'origin' | 'avif' quality?: number + gravity?: 'no' | 'so' | 'ea' | 'we' | 'noea' | 'nowe' | 'soea' | 'sowe' | 'ce' | 'sm' | 'fp' + x_offset?: number + y_offset?: number } const { @@ -115,6 +118,40 @@ export class ImageRenderer extends Renderer { segments.push(`format:${options.format}`) } + if (options.gravity) { + switch (options.gravity) { + case 'sm': { + segments.push(`gravity:${options.gravity}`) + break + } + case 'fp': { + if ( + !( + options.x_offset && + options.y_offset && + options.x_offset <= 1 && + options.y_offset <= 1 && + options.x_offset >= 0 && + options.y_offset >= 0 + ) + ) { + throw new StorageBackendError( + 'Invalid focus point', + 400, + 'Focal point requires x and y coordinates within 0-1 range' + ) + } + segments.push(`gravity:${options.gravity}:${options.x_offset}:${options.y_offset}`) + break + } + default: { + segments.push( + `gravity:${options.gravity}:${options.x_offset ?? 0}:${options.y_offset ?? 0}` + ) + } + } + } + return segments } @@ -170,6 +207,15 @@ export class ImageRenderer extends Renderer { case 'quality': all.quality = parseInt(value, 10) break + case 'gravity': + all.gravity = value + break + case 'x_offset': + all.x_offset = parseFloat(value) + break + case 'y_offset': + all.y_offset = parseFloat(value) + break } return all }, {} as TransformOptions)