From bd8dc9aa2fd406331d1acde583dba48765901ed8 Mon Sep 17 00:00:00 2001 From: magdakwiecien <97024257+magdakwiecien@users.noreply.github.com> Date: Wed, 21 Feb 2024 19:24:17 +0100 Subject: [PATCH] Add autoPad resize action (#46) * Add autoPad resize action * Remove unneccessary model * Rename test case * Lint fixes --- .../Resize/AutoPadResizeAction.test.ts | 19 +++++++++ .../unit/fromJson/resize.fromJson.test.ts | 7 +++- __TESTS__/unit/toJson/resize.toJson.test.ts | 19 +++++++++ src/actions/resize.ts | 23 ++++++++++- src/actions/resize/ResizeAutoPadAction.ts | 40 +++++++++++++++++++ src/internal/fromJson.ts | 4 +- src/internal/internalConstants.ts | 3 +- 7 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 __TESTS__/unit/actions/Resize/AutoPadResizeAction.test.ts create mode 100644 src/actions/resize/ResizeAutoPadAction.ts diff --git a/__TESTS__/unit/actions/Resize/AutoPadResizeAction.test.ts b/__TESTS__/unit/actions/Resize/AutoPadResizeAction.test.ts new file mode 100644 index 0000000..85f968d --- /dev/null +++ b/__TESTS__/unit/actions/Resize/AutoPadResizeAction.test.ts @@ -0,0 +1,19 @@ +import {Transformation} from "../../../../src"; +import {Resize, autoPad} from "../../../../src/actions/resize"; +import {Background} from "../../../../src/qualifiers"; + +describe('Tests for Transformation Action -- Resize.autoPad', () => { + it('Ensures it generates the right transformation', () => { + const tx = new Transformation().resize(autoPad(250, 250)).toString(); + expect(tx).toContain('c_auto_pad,g_auto,h_250,w_250'); + }); + + it('Ensures it generates the right transformation using qualifiers', () => { + const tx = new Transformation().resize( + Resize.autoPad() + .width(250) + .height(250) + .background(Background.color('red'))).toString(); + expect(tx).toContain('b_red,c_auto_pad,g_auto,h_250,w_250'); + }); +}); diff --git a/__TESTS__/unit/fromJson/resize.fromJson.test.ts b/__TESTS__/unit/fromJson/resize.fromJson.test.ts index 12b76d9..d0e4441 100644 --- a/__TESTS__/unit/fromJson/resize.fromJson.test.ts +++ b/__TESTS__/unit/fromJson/resize.fromJson.test.ts @@ -60,6 +60,10 @@ describe('resize.fromJson', () => { } }, {actionType: 'auto', dimensions: {width: 100, height: 200}, gravity: {gravityType: 'direction', compass: 'south'}}, + {actionType: 'autoPad', dimensions: {width: 100, height: 200}, background: { + backgroundType: 'color', + color: 'red' + }} ]}); expect(transformation.toString()).toStrictEqual([ @@ -78,7 +82,8 @@ describe('resize.fromJson', () => { 'c_crop,g_dog:auto:bird_30:cat_avoid,w_200', 'b_gen_fill:prompt_hello,c_pad,w_200', 'ar_7.0,b_gen_fill,c_mpad,w_200', - 'c_auto,g_south,h_200,w_100' + 'c_auto,g_south,h_200,w_100', + 'b_red,c_auto_pad,g_auto,h_200,w_100' ].join('/')); }); diff --git a/__TESTS__/unit/toJson/resize.toJson.test.ts b/__TESTS__/unit/toJson/resize.toJson.test.ts index a93b573..f37d6c8 100644 --- a/__TESTS__/unit/toJson/resize.toJson.test.ts +++ b/__TESTS__/unit/toJson/resize.toJson.test.ts @@ -498,4 +498,23 @@ describe('resize.toJson()', () => { }); }); + it('autoPad', () => { + const transformation = new Transformation() + .addAction(Resize.autoPad().width(200).height(100).background('red')); + expect(transformation.toJson()).toStrictEqual({ + actions: [ + { + "actionType": "autoPad", + "dimensions": { + "width": 200, + "height": 100, + }, + background: { + backgroundType: "color", + color: "red" + }, + }, + ] + }); + }); }); diff --git a/src/actions/resize.ts b/src/actions/resize.ts index e255f87..33689e6 100644 --- a/src/actions/resize.ts +++ b/src/actions/resize.ts @@ -63,6 +63,7 @@ import {ResizeLimitFillAction} from "./resize/ResizeLimitFillAction.js"; import {ResizeLimitPadAction} from "./resize/ResizeLimitPadAction.js"; import {ResizeMinimumPadAction} from "./resize/ResizeMinimumPadAction.js"; import {ResizeAdvancedAction} from "./resize/ResizeAdvancedAction.js"; +import {ResizeAutoPadAction} from "./resize/ResizeAutoPadAction.js"; /** * @summary action @@ -309,6 +310,22 @@ function limitPad(width?: string|number, height?: string|number) :ResizeLimitPad } +/** + * @summary action + * @description + * Tries to prevent a "bad crop" by first attempting to use the auto cropping mode, but adding some padding + * if the algorithm determines that more of the original image needs to be included in the final image. + * + * @memberOf Actions.Resize + * @param {number|string} width The required width of a transformed asset. + * @param {number|string} height The required height of a transformed asset. + * @return {Actions.Resize.ResizeAutoPadAction} + */ +function autoPad(width?: string|number, height?: string|number): ResizeAutoPadAction { + return new ResizeAutoPadAction('auto_pad', width, height); +} + + const Resize = { imaggaScale, imaggaCrop, @@ -324,7 +341,8 @@ const Resize = { minimumFit, limitPad, fillPad, - auto + auto, + autoPad }; export { Resize, @@ -342,5 +360,6 @@ export { minimumFit, limitPad, fillPad, - auto + auto, + autoPad }; diff --git a/src/actions/resize/ResizeAutoPadAction.ts b/src/actions/resize/ResizeAutoPadAction.ts new file mode 100644 index 0000000..8897e4d --- /dev/null +++ b/src/actions/resize/ResizeAutoPadAction.ts @@ -0,0 +1,40 @@ +import {BackgroundQualifier} from "../../qualifiers/background/shared/base/BackgroundQualifier.js"; +import {Qualifier} from "../../internal/qualifier/Qualifier.js"; +import {IActionModel} from "../../internal/models/IActionModel.js"; +import {createBackgroundModel, IBackgroundModel} from "../../internal/models/createBackgroundModel.js"; +import {createBackgroundFromModel} from "../../internal/models/createBackgroundFromModel.js"; +import {ResizeSimpleAction} from "./ResizeSimpleAction.js"; + +/** + * @description Tries to prevent a "bad crop" by first attempting to use the auto cropping mode, but adding some padding if the algorithm determines that more of the original image needs to be included in the final image. + * @extends Actions.Resize.autoPad + * @memberOf Actions.Resize + * @see Visit {@link Actions.Resize| Resize} for examples + */ +class ResizeAutoPadAction extends ResizeSimpleAction { + constructor(cropType: string, cropWidth: number | string, cropHeight?: number | string) { + super(cropType, cropWidth, cropHeight); + + this.addQualifier(new Qualifier('g', 'auto')); + } + + /** + * @description Sets the background. + * @param {Qualifiers.Background} backgroundQualifier Defines the background color to use instead of + * transparent background areas or when resizing with padding. + */ + background(backgroundQualifier: BackgroundQualifier | string): this { + this._actionModel.background = createBackgroundModel(backgroundQualifier); + return this.addQualifier(backgroundQualifier); + } + + static fromJson(actionModel: IActionModel): ResizeAutoPadAction { + const result = super.fromJson.apply(this, [actionModel]); + actionModel.background && result.background(createBackgroundFromModel(actionModel.background as IBackgroundModel)); + + return result; + } +} + + +export {ResizeAutoPadAction}; diff --git a/src/internal/fromJson.ts b/src/internal/fromJson.ts index ce75885..c43b6e8 100644 --- a/src/internal/fromJson.ts +++ b/src/internal/fromJson.ts @@ -71,6 +71,7 @@ import { GenerativeReplace } from "../actions/effect/GenerativeReplace.js"; import { GenerativeRecolor } from "../actions/effect/GenerativeRecolor.js"; import {ResizeAdvancedAction} from "../actions/resize/ResizeAdvancedAction.js"; import {BackgroundColor} from "../actions/background/actions/BackgroundColor.js"; +import {ResizeAutoPadAction} from "../actions/resize/ResizeAutoPadAction.js"; const ActionModelMap: Record = { scale: ResizeScaleAction, @@ -152,7 +153,8 @@ const ActionModelMap: Record = { upscale: SimpleEffectAction, auto: ResizeAdvancedAction, backgroundColor: BackgroundColor, - enhance: SimpleEffectAction, + autoPad: ResizeAutoPadAction, + enhance: SimpleEffectAction }; /** diff --git a/src/internal/internalConstants.ts b/src/internal/internalConstants.ts index 017b220..f30d694 100644 --- a/src/internal/internalConstants.ts +++ b/src/internal/internalConstants.ts @@ -58,7 +58,8 @@ export const ACTION_TYPE_TO_CROP_MODE_MAP: Record = { minimumFit: 'mfit', thumbnail: 'thumb', limitPad: 'lpad', - minimumPad: 'mpad' + minimumPad: 'mpad', + autoPad: 'auto_pad' }; export const ACTION_TYPE_TO_DELIVERY_MODE_MAP: Record = {