diff --git a/.changeset/two-days-look.md b/.changeset/two-days-look.md new file mode 100644 index 00000000..ce9dd2b2 --- /dev/null +++ b/.changeset/two-days-look.md @@ -0,0 +1,5 @@ +--- +"@imgproxy/imgproxy-js-core": minor +--- + +Add support for objw mode for [gravity option](https://docs.imgproxy.net/usage/processing#gravity) diff --git a/src/options/gravity.ts b/src/options/gravity.ts index 68b13a50..b1095aa3 100644 --- a/src/options/gravity.ts +++ b/src/options/gravity.ts @@ -3,6 +3,7 @@ import type { Gravity, FPGravity, ObjGravity, + ObjwGravity, BaseGravity, } from "../types/gravity"; import { @@ -33,6 +34,7 @@ const currentAllTypes = { sm: true, fp: true, obj: true, + objw: true, }; const getOpt = (options: GravityOptionsPartial): Gravity | undefined => @@ -64,6 +66,9 @@ const build = ( if (gravityOpts.class_names && type !== "obj") throw new Error("gravity.class_names can be used only with type obj"); // @ts-expect-error: Let's ignore an error. + if (gravityOpts.class_weights && type !== "objw") + throw new Error("gravity.class_weights can be used only with type objw"); + // @ts-expect-error: Let's ignore an error. if ((gravityOpts.x || gravityOpts.y) && type !== "fp") throw new Error("gravity.x and gravity.y can be used only with type fp"); @@ -90,6 +95,28 @@ const build = ( const class_names = gravityObj.class_names; return withHead(`${type}:${class_names.join(":")}`, headless); + } + + if (type === "objw") { + const gravityObjw = gravityOpts as ObjwGravity; + + guardIsUndef(gravityObjw.class_weights, "gravity.class_weights"); + guardIsNotArray(gravityObjw.class_weights, "gravity.class_weights"); + + const weightPairs = gravityObjw.class_weights.map(item => { + if ( + typeof item !== "object" || + !item.class || + typeof item.weight !== "number" + ) { + throw new Error( + "Each item in gravity.class_weights must have 'class' and 'weight' properties" + ); + } + return `${item.class}:${item.weight}`; + }); + + return withHead(`${type}:${weightPairs.join(":")}`, headless); } else { const gravityBase = gravityOpts as BaseGravity; const x_offset = diff --git a/src/types/gravity.ts b/src/types/gravity.ts index e979def5..e6f5e4cc 100644 --- a/src/types/gravity.ts +++ b/src/types/gravity.ts @@ -106,6 +106,26 @@ interface ObjGravity { class_names: string[]; } +/** + * **PRO feature.** + * + * Object-weighted gravity. imgproxy detects objects of provided classes on the image, calculates the resulting image center using their positions, and adds weights to these positions. + * + * If class weights are omited, imgproxy will use all the detected objects with equal weights. + * + * @param {string} type - Must be `objw`. + * @param {Array<{class: string, weight: number}>} class_weights - Array of objects with class names and their weights. + * + * @example + * {gravity: {type: "objw", class_weights: [{class: "face", weight: 1}, {class: "person", weight: 0.5}]}} + * + * @see https://docs.imgproxy.net/generating_the_url?id=gravity + */ +interface ObjwGravity { + type: "objw"; + class_weights: Array<{ class: string; weight: number }>; +} + /** * *Gravity option* * @@ -138,6 +158,12 @@ interface ObjGravity { * If class names are omited, imgproxy will use all the detected objects. * @param {string} type - Must be `obj`. * @param {string[]} class_names - Array of class names. + * + * *Object-weighted gravity*. **PRO feature.** + * imgproxy detects objects of provided classes on the image, calculates the resulting image center using their positions, and adds weights to these positions. + * If class weights are omited, imgproxy will use all the detected objects with equal weights. + * @param {string} type - Must be `objw`. + * @param {Array<{class: string, weight: number}>} class_weights - Array of objects with class names and their weights. * * *FP gravity*. * The gravity focus point. @@ -164,13 +190,21 @@ interface ObjGravity { * * @example