From f31b5c5236b4fe202e5318cb51ba89108f2914d2 Mon Sep 17 00:00:00 2001 From: Maciej Komorowski Date: Tue, 11 Jul 2023 11:40:36 +0200 Subject: [PATCH] add support for genrative remove effect --- .../generativeRemove.fromJson.test.ts | 42 ++++ .../toJson/generativeRemove.toJson.test.ts | 59 +++++ src/actions/effect.ts | 213 ++++++++---------- src/actions/effect/GenerativeRemove.ts | 151 +++++++++++++ src/internal/fromJson.ts | 134 ++++++----- src/internal/models/IEffectActionModel.ts | 61 ++--- 6 files changed, 454 insertions(+), 206 deletions(-) create mode 100644 __TESTS__/unit/fromJson/generativeRemove.fromJson.test.ts create mode 100644 __TESTS__/unit/toJson/generativeRemove.toJson.test.ts create mode 100644 src/actions/effect/GenerativeRemove.ts diff --git a/__TESTS__/unit/fromJson/generativeRemove.fromJson.test.ts b/__TESTS__/unit/fromJson/generativeRemove.fromJson.test.ts new file mode 100644 index 0000000..58286c5 --- /dev/null +++ b/__TESTS__/unit/fromJson/generativeRemove.fromJson.test.ts @@ -0,0 +1,42 @@ +import { fromJson } from "../../../src/internal/fromJson"; + +describe("generativeRemove.fromJson", () => { + it("should generate a url with e_gen_remove", function () { + const transformation = fromJson({ + actions: [ + { actionType: "generativeRemove", prompts: ["dog"] }, + { + actionType: "generativeRemove", + prompts: ["dog"], + detectMultiple: true, + }, + { actionType: "generativeRemove", prompts: ["dog", "cat"] }, + { + actionType: "generativeRemove", + prompts: ["dog", "cat"], + detectMultiple: true, + }, // "detectMultiple" should be omitted from TX string for multiple prompts + { + actionType: "generativeRemove", + regions: [{ x: 10, y: 10, width: 100, height: 100 }], + }, + { + actionType: "generativeRemove", + regions: [ + { x: 10, y: 10, width: 100, height: 100 }, + { x: 500, y: 500, width: 200, height: 200 }, + ], + }, + ], + }); + + expect(transformation.toString().split("/")).toStrictEqual([ + "e_gen_remove:prompt_dog", + "e_gen_remove:prompt_dog;multiple_true", + "e_gen_remove:prompt_(dog;cat)", + "e_gen_remove:prompt_(dog;cat)", + "e_gen_remove:region_(x_10;y_10;w_100;h_100)", + "e_gen_remove:region_((x_10;y_10;w_100;h_100);(x_500;y_500;w_200;h_200))", + ]); + }); +}); diff --git a/__TESTS__/unit/toJson/generativeRemove.toJson.test.ts b/__TESTS__/unit/toJson/generativeRemove.toJson.test.ts new file mode 100644 index 0000000..b0ea0c8 --- /dev/null +++ b/__TESTS__/unit/toJson/generativeRemove.toJson.test.ts @@ -0,0 +1,59 @@ +import { Transformation } from "../../../src"; +import { Effect } from "../../../src/actions/effect"; +import { GenerativeRemove } from "../../../src/actions/effect/GenerativeRemove"; + +describe("GenerativeRemove.toJson()", () => { + it("produces correct action JSON", () => { + const testCases: Array<[GenerativeRemove, unknown]> = [ + [ + Effect.generativeRemove().prompt("dog"), + { actionType: "generativeRemove", prompts: ["dog"] }, + ], + [ + Effect.generativeRemove().prompt("dog").detectMultiple(), + { + actionType: "generativeRemove", + prompts: ["dog"], + detectMultiple: true, + }, + ], + [ + Effect.generativeRemove().prompts(["dog", "cat"]), + { actionType: "generativeRemove", prompts: ["dog", "cat"] }, + ], + [ + Effect.generativeRemove().region({ + x: 100, + y: 200, + width: 600, + height: 400, + }), + { + actionType: "generativeRemove", + regions: [{ x: 100, y: 200, width: 600, height: 400 }], + }, + ], + [ + Effect.generativeRemove().regions([ + { x: 100, y: 200, width: 600, height: 400 }, + { x: 300, y: 400, width: 50, height: 60 }, + ]), + { + actionType: "generativeRemove", + regions: [ + { x: 100, y: 200, width: 600, height: 400 }, + { x: 300, y: 400, width: 50, height: 60 }, + ], + }, + ], + ]; + + for (const [action, expectedProps] of testCases) { + const transformation = new Transformation().addAction(action); + + expect(transformation.toJson()).toStrictEqual({ + actions: [expectedProps], + }); + } + }); +}); diff --git a/src/actions/effect.ts b/src/actions/effect.ts index 2d32e98..a36283f 100644 --- a/src/actions/effect.ts +++ b/src/actions/effect.ts @@ -1,33 +1,33 @@ -import {BlurAction} from "./effect/blur/Blur.js"; -import {AccelerationEffectAction} from "./effect/leveled/Accelerate.js"; -import {LoopEffectAction} from "./effect/leveled/Loop.js"; -import {CartoonifyEffect} from "./effect/Cartoonify.js"; -import {EffectOutline} from "./effect/Outline.js"; -import {SimpleEffectAction} from "./effect/EffectActions/SimpleEffectAction.js"; -import {MakeTransparentEffectAction} from "./effect/leveled/MakeTransparent.js"; -import {VectorizeEffectAction} from "./effect/Vectorize.js"; -import {SimulateColorBlindEffectAction} from "./effect/SimulateColorBlind.js"; -import {EffectActionWithLevel}from "./effect/EffectActions/EffectActionWithLevel.js"; -import {AssistColorBlindEffectAction} from "./effect/AssistColorBlind.js"; -import {GradientFadeEffectAction} from "./effect/GradientFade.js"; -import {FadeOutEffectAction} from "./effect/leveled/FadeOut.js"; -import {ColorizeEffectAction} from "./effect/Colorize.js"; -import {ShadowEffectAction} from "./effect/Shadow.js"; -import {StyleTransfer} from "./effect/StyleTransfer.js"; -import {DitherEffectAction} from "./effect/Dither.js"; -import {DeshakeEffectAction} from "./effect/leveled/Deshake.js"; -import {Pixelate} from "./effect/pixelate/Pixelate.js"; -import {ImageSource} from "../qualifiers/source/sourceTypes/ImageSource.js"; -import {EffectActionWithStrength} from "./effect/EffectActions/EffectActionWithStrength.js"; -import {BlackwhiteEffectAction} from "./effect/leveled/Blackwhite.js"; -import {FadeInEffectAction} from "./effect/leveled/FadeIn.js"; -import {RemoveBackgroundAction} from "./effect/RemoveBackgroundAction.js"; -import {ThemeEffect} from "./effect/Theme.js"; -import {SystemColors} from "../qualifiers/color.js"; -import {ArtisticFilterType} from "../types/types.js"; -import {BackgroundRemoval} from "./effect/BackgroundRemoval.js"; -import {DropShadow} from "./effect/DropShadow.js"; - +import { BlurAction } from "./effect/blur/Blur.js"; +import { AccelerationEffectAction } from "./effect/leveled/Accelerate.js"; +import { LoopEffectAction } from "./effect/leveled/Loop.js"; +import { CartoonifyEffect } from "./effect/Cartoonify.js"; +import { EffectOutline } from "./effect/Outline.js"; +import { SimpleEffectAction } from "./effect/EffectActions/SimpleEffectAction.js"; +import { MakeTransparentEffectAction } from "./effect/leveled/MakeTransparent.js"; +import { VectorizeEffectAction } from "./effect/Vectorize.js"; +import { SimulateColorBlindEffectAction } from "./effect/SimulateColorBlind.js"; +import { EffectActionWithLevel } from "./effect/EffectActions/EffectActionWithLevel.js"; +import { AssistColorBlindEffectAction } from "./effect/AssistColorBlind.js"; +import { GradientFadeEffectAction } from "./effect/GradientFade.js"; +import { FadeOutEffectAction } from "./effect/leveled/FadeOut.js"; +import { ColorizeEffectAction } from "./effect/Colorize.js"; +import { ShadowEffectAction } from "./effect/Shadow.js"; +import { StyleTransfer } from "./effect/StyleTransfer.js"; +import { DitherEffectAction } from "./effect/Dither.js"; +import { DeshakeEffectAction } from "./effect/leveled/Deshake.js"; +import { Pixelate } from "./effect/pixelate/Pixelate.js"; +import { ImageSource } from "../qualifiers/source/sourceTypes/ImageSource.js"; +import { EffectActionWithStrength } from "./effect/EffectActions/EffectActionWithStrength.js"; +import { BlackwhiteEffectAction } from "./effect/leveled/Blackwhite.js"; +import { FadeInEffectAction } from "./effect/leveled/FadeIn.js"; +import { RemoveBackgroundAction } from "./effect/RemoveBackgroundAction.js"; +import { ThemeEffect } from "./effect/Theme.js"; +import { SystemColors } from "../qualifiers/color.js"; +import { ArtisticFilterType } from "../types/types.js"; +import { BackgroundRemoval } from "./effect/BackgroundRemoval.js"; +import { DropShadow } from "./effect/DropShadow.js"; +import { GenerativeRemove } from "./effect/GenerativeRemove.js"; /** * @summary action @@ -46,12 +46,10 @@ function blur(blurLevel?: number): BlurAction { * @memberOf Actions.Effect * @return {Actions.Effect.SimpleEffectAction} */ -function grayscale():SimpleEffectAction { - return new SimpleEffectAction('grayscale'); +function grayscale(): SimpleEffectAction { + return new SimpleEffectAction("grayscale"); } - - /** * @summary action * @description Changes the color scheme of the image to sepia. @@ -59,12 +57,10 @@ function grayscale():SimpleEffectAction { * @param {number} level The level of sepia to apply. (Range: 1 to 100, Server default: 80) * @return {Actions.Effect.EffectActionWithLevel} */ -function sepia(level?: number):EffectActionWithLevel { - return new EffectActionWithLevel('sepia', level); +function sepia(level?: number): EffectActionWithLevel { + return new EffectActionWithLevel("sepia", level); } - - /** * @summary action * @description Applies a shadow filter to the asset. @@ -72,11 +68,10 @@ function sepia(level?: number):EffectActionWithLevel { * @param shadowLevel * @return {Actions.Effect.ShadowEffectAction} */ -function shadow(shadowLevel?: number):ShadowEffectAction { - return new ShadowEffectAction('shadow', shadowLevel); +function shadow(shadowLevel?: number): ShadowEffectAction { + return new ShadowEffectAction("shadow", shadowLevel); } - /** * @summary action * @description Applies a colorizing filter to the asset. @@ -84,11 +79,10 @@ function shadow(shadowLevel?: number):ShadowEffectAction { * @param {number} colorizeLevel The strength of the color. (Range: 0 to 100, Server default: 100) * @return {Actions.Effect.ColorizeEffectAction} */ -function colorize(colorizeLevel?: number):ColorizeEffectAction { - return new ColorizeEffectAction('colorize', colorizeLevel); +function colorize(colorizeLevel?: number): ColorizeEffectAction { + return new ColorizeEffectAction("colorize", colorizeLevel); } - /** * @summary action * @description Applies an oilPaint filter to the asset. @@ -96,8 +90,8 @@ function colorize(colorizeLevel?: number):ColorizeEffectAction { * @param {number} oilPaintLevel The strength of the effect. (Range: 0 to 100, Server default: 30) * @return {Actions.Effect.EffectActionWithStrength} */ -function oilPaint(oilPaintLevel?: number):EffectActionWithStrength { - return new EffectActionWithStrength('oil_paint', oilPaintLevel); +function oilPaint(oilPaintLevel?: number): EffectActionWithStrength { + return new EffectActionWithStrength("oil_paint", oilPaintLevel); } /** @@ -107,11 +101,12 @@ function oilPaint(oilPaintLevel?: number):EffectActionWithStrength { * @param {ArtisticFilterType | string} artisticFilterType * @return {Actions.Effect.SimpleEffectAction} */ -function artisticFilter(artisticFilterType: ArtisticFilterType | string):SimpleEffectAction { - return new SimpleEffectAction('art', artisticFilterType); +function artisticFilter( + artisticFilterType: ArtisticFilterType | string +): SimpleEffectAction { + return new SimpleEffectAction("art", artisticFilterType); } - /** * @summary action * @description Applies a cartoonify effect to the asset. @@ -119,11 +114,10 @@ function artisticFilter(artisticFilterType: ArtisticFilterType | string):SimpleE * @param cartoonifyLevel The thickness of the lines. (Range: 0 to 100, Server default: 50) * @return {Actions.Effect.CartoonifyEffect} */ -function cartoonify(cartoonifyLevel?: number):CartoonifyEffect { - return new CartoonifyEffect('cartoonify', cartoonifyLevel); +function cartoonify(cartoonifyLevel?: number): CartoonifyEffect { + return new CartoonifyEffect("cartoonify", cartoonifyLevel); } - /** * @summary action * @description Adds an outline to a transparent image. For examples, see the Image Transformations guide. @@ -134,7 +128,6 @@ function outline(): EffectOutline { return new EffectOutline(); } - /** * @summary action * @description Applies a complex deep learning neural network algorithm that extracts artistic styles from a source image and applies them to the content of a target photograph.
@@ -147,8 +140,6 @@ function styleTransfer(imageSource: ImageSource): StyleTransfer { return new StyleTransfer(imageSource); } - - /** * @summary action * @description @@ -158,11 +149,10 @@ function styleTransfer(imageSource: ImageSource): StyleTransfer { * @memberOf Actions.Effect * @return {Actions.Effect.SimpleEffectAction} */ -function boomerang():SimpleEffectAction { - return new SimpleEffectAction('boomerang'); +function boomerang(): SimpleEffectAction { + return new SimpleEffectAction("boomerang"); } - /** * @summary action * @description @@ -171,11 +161,10 @@ function boomerang():SimpleEffectAction { * @memberOf Actions.Effect * @return {Actions.Effect.SimpleEffectAction} */ -function advancedRedEye():SimpleEffectAction { - return new SimpleEffectAction('adv_redeye'); +function advancedRedEye(): SimpleEffectAction { + return new SimpleEffectAction("adv_redeye"); } - /** * @summary action * @description Converts the image to black and white. @@ -183,44 +172,40 @@ function advancedRedEye():SimpleEffectAction { * @param {number | string} level The balance between black (100) and white (0). (Range: 0 to 100, Server default: 50) * @return {Actions.Effect.BlackwhiteEffectAction} */ -function blackwhite(level?: number | 'bw'):BlackwhiteEffectAction { - return new BlackwhiteEffectAction('blackwhite', level); +function blackwhite(level?: number | "bw"): BlackwhiteEffectAction { + return new BlackwhiteEffectAction("blackwhite", level); } - /** * @summary action * @description Negates the image colors (negative). * @memberOf Actions.Effect * @return {Actions.Effect.SimpleEffectAction} */ -function negate():SimpleEffectAction { - return new SimpleEffectAction('negate'); +function negate(): SimpleEffectAction { + return new SimpleEffectAction("negate"); } - /** * @summary action * @description Removes red eyes in the image. * @memberOf Actions.Effect * @return {Actions.Effect.SimpleEffectAction} */ -function redEye():SimpleEffectAction { - return new SimpleEffectAction('redeye'); +function redEye(): SimpleEffectAction { + return new SimpleEffectAction("redeye"); } - /** * @summary action * @description Plays the video or audio file in reverse. * @memberOf Actions.Effect * @return {Actions.Effect.SimpleEffectAction} */ -function reverse():SimpleEffectAction { - return new SimpleEffectAction('reverse'); +function reverse(): SimpleEffectAction { + return new SimpleEffectAction("reverse"); } - /** * @summary action * @description Changes the speed of the video playback. @@ -241,11 +226,10 @@ function accelerate(speedIncreasePercent?: number): AccelerationEffectAction { * @param {number} fadeLength The time in ms for the fade to occur. (Server default: 2000) * @return {Actions.Effect.FadeInEffectAction} */ -function fadeIn(fadeLength?: number):FadeInEffectAction { +function fadeIn(fadeLength?: number): FadeInEffectAction { return new FadeInEffectAction(fadeLength); } - /** * @summary action * @description @@ -255,11 +239,10 @@ function fadeIn(fadeLength?: number):FadeInEffectAction { * @param {number} fadeLength The time in ms for the fade to occur. (Server default: 2000) * @return {Actions.Effect.FadeoutEffectAction} */ -function fadeOut(fadeLength?: number):FadeOutEffectAction { +function fadeOut(fadeLength?: number): FadeOutEffectAction { return new FadeOutEffectAction(fadeLength); } - /** * @summary action * @description @@ -270,8 +253,8 @@ function fadeOut(fadeLength?: number):FadeOutEffectAction { * @param {number} additionalLoops The additional number of times to play the video or animated GIF. * @return {Actions.Effect.LoopEffectAction} */ -function loop(additionalLoops?: number):LoopEffectAction { - return new LoopEffectAction('loop', additionalLoops); +function loop(additionalLoops?: number): LoopEffectAction { + return new LoopEffectAction("loop", additionalLoops); } /** @@ -284,14 +267,10 @@ function loop(additionalLoops?: number):LoopEffectAction { * @param {number} tolerance The tolerance used to accommodate variance in the background color. (Range: 0 to 100, Server default: 10) * @return {Actions.Effect.MakeTransparentEffectAction} */ -function makeTransparent(tolerance?: number):MakeTransparentEffectAction { - return new MakeTransparentEffectAction('make_transparent', tolerance); +function makeTransparent(tolerance?: number): MakeTransparentEffectAction { + return new MakeTransparentEffectAction("make_transparent", tolerance); } - - - - /** * @summary action * @description Adds visual noise to the video, visible as a random flicker of "dots" or "snow". @@ -299,11 +278,10 @@ function makeTransparent(tolerance?: number):MakeTransparentEffectAction { * @param {number} percentage The percent of noise to apply. (Range: 0 to 100 Server default: 0) * @return {Actions.Effect.EffectActionWithLevel} */ -function noise(percentage?: number):EffectActionWithLevel { - return new EffectActionWithLevel('noise', percentage); +function noise(percentage?: number): EffectActionWithLevel { + return new EffectActionWithLevel("noise", percentage); } - /** * @summary action * @description Applies a vignette effect. @@ -311,11 +289,10 @@ function noise(percentage?: number):EffectActionWithLevel { * @param {number} strength The strength of the vignette. (Range: 0 to 100, Server default: 20) * @return {Actions.Effect.EffectActionWithStrength} */ -function vignette(strength?: number):EffectActionWithStrength { - return new EffectActionWithStrength('vignette', strength); +function vignette(strength?: number): EffectActionWithStrength { + return new EffectActionWithStrength("vignette", strength); } - /** * @summary action * @description @@ -325,8 +302,8 @@ function vignette(strength?: number):EffectActionWithStrength { * @param {Qualifiers.Dither} ditherType - The dither type applied to the image * @return {Actions.Effect.DitherEffectAction} */ -function dither(ditherType?: number):DitherEffectAction { - return new DitherEffectAction('ordered_dither', ditherType); +function dither(ditherType?: number): DitherEffectAction { + return new DitherEffectAction("ordered_dither", ditherType); } /** @@ -341,13 +318,10 @@ function dither(ditherType?: number):DitherEffectAction { * @memberOf Actions.Effect * @return {Actions.Effect.VectorizeEffectAction} */ -function vectorize():VectorizeEffectAction { +function vectorize(): VectorizeEffectAction { return new VectorizeEffectAction(); } - - - /** * @summary action * @description @@ -362,11 +336,10 @@ function vectorize():VectorizeEffectAction { * @memberOf Actions.Effect * @return {Actions.Effect.GradientFadeEffectAction} */ -function gradientFade():GradientFadeEffectAction { +function gradientFade(): GradientFadeEffectAction { return new GradientFadeEffectAction(); } - /** * @summary action * @description @@ -375,7 +348,7 @@ function gradientFade():GradientFadeEffectAction { * @memberOf Actions.Effect * @return {Actions.Effect.AssistColorBlindEffectAction} */ -function assistColorBlind():AssistColorBlindEffectAction { +function assistColorBlind(): AssistColorBlindEffectAction { return new AssistColorBlindEffectAction(); } @@ -391,19 +364,16 @@ function simulateColorBlind(): SimulateColorBlindEffectAction { return new SimulateColorBlindEffectAction(); } - - /** * @summary action * @description Removes small motion shifts from the video. with a maximum extent of movement in the horizontal and vertical direction of 32 pixels * @memberOf Actions.Effect * @return {Actions.Effect.DeshakeEffectAction} */ -function deshake(pixels?: number | string):DeshakeEffectAction { - return new DeshakeEffectAction('deshake', pixels); +function deshake(pixels?: number | string): DeshakeEffectAction { + return new DeshakeEffectAction("deshake", pixels); } - /** * @summary action * @description Supports the concatenation of videos with a custom transition by including a transition video as an @@ -411,8 +381,8 @@ function deshake(pixels?: number | string):DeshakeEffectAction { * @memberOf Actions.Effect * @return {Actions.Effect.SimpleEffectAction} */ -function transition():SimpleEffectAction { - return new SimpleEffectAction('transition'); +function transition(): SimpleEffectAction { + return new SimpleEffectAction("transition"); } /** @@ -426,7 +396,6 @@ function pixelate(squareSize?: number): Pixelate { return new Pixelate(squareSize); } - /** * @summary action * @description Makes the background of an image transparent (or solid white for JPGs).
@@ -440,7 +409,6 @@ function removeBackground(): RemoveBackgroundAction { return new RemoveBackgroundAction(); } - /** * @summary action * @description Uses the Cloudinary AI Background Removal add-on to make the background of an image transparent.
@@ -454,7 +422,6 @@ function backgroundRemoval(): BackgroundRemoval { return new BackgroundRemoval(); } - /** * @summary action * @description Adds a shadow to the object in an image. @@ -467,6 +434,17 @@ function dropShadow(): DropShadow { return new DropShadow(); } +/** + * @summary action + * @description Remove objects from an asset using Generative AI + * {@link https://cloudinary.com/documentation/transformation_reference#e_gen_remove|Generative Remove} + * + * @memberOf Actions.Effect + * @return {Actions.Effect.DropShadow} + */ +function generativeRemove(): GenerativeRemove { + return new GenerativeRemove(); +} /** * @@ -478,7 +456,6 @@ function theme(color: SystemColors): ThemeEffect { return new ThemeEffect(color); } - /** * @description Defines effects that you can apply to transform your assets. * @memberOf Actions @@ -567,13 +544,12 @@ const Effect = { removeBackground, backgroundRemoval, dropShadow, - theme + generativeRemove, + theme, }; - - export declare type EffectActions = - SimpleEffectAction + | SimpleEffectAction | EffectOutline | ShadowEffectAction | AssistColorBlindEffectAction @@ -589,8 +565,8 @@ export declare type EffectActions = | FadeOutEffectAction | AccelerationEffectAction | BackgroundRemoval - | DropShadow; - + | DropShadow + | GenerativeRemove; export { Effect, @@ -628,5 +604,6 @@ export { removeBackground, backgroundRemoval, dropShadow, - theme + generativeRemove, + theme, }; diff --git a/src/actions/effect/GenerativeRemove.ts b/src/actions/effect/GenerativeRemove.ts new file mode 100644 index 0000000..1f1a98e --- /dev/null +++ b/src/actions/effect/GenerativeRemove.ts @@ -0,0 +1,151 @@ +import { Action } from "../../internal/Action.js"; +import { QualifierValue } from "../../internal/qualifier/QualifierValue.js"; +import { Qualifier } from "../../internal/qualifier/Qualifier.js"; +import { IGenerativeRemoveModel } from "../../internal/models/IEffectActionModel.js"; + +type Region = { + x: number; + y: number; + width: number; + height: number; +}; // Internal type for regions parameter – it's not interchangeable with CustomRegion + +/** + * @description A class that defines how to remove objects from an asset using Generative AI + * @extends SDK.Action + * @memberOf Actions.Effect + * @see Visit {@link Actions.Effect|Effect} for an example + */ +class GenerativeRemove extends Action { + private _prompts: Array = []; + private _regions: Array = []; + private _detectMultiple = false; + + constructor() { + super(); + this._actionModel.actionType = "generativeRemove"; + } + + prompt(value: string) { + return this.prompts([value]); + } + + prompts(value: Array) { + this._prompts = value; + + if (this._prompts) { + this._actionModel.prompts = this._prompts; + } + return this; + } + + region(value: Region) { + return this.regions([value]); + } + + regions(value: Array) { + this._regions = value; + + if (this._regions) { + this._actionModel.regions = this._regions; + } + + return this; + } + + detectMultiple(value = true) { + this._detectMultiple = value; + + if (this._detectMultiple) { + this._actionModel.detectMultiple = this._detectMultiple; + } + + return this; + } + + protected prepareQualifiers(): void { + switch (true) { + case this._prompts.length === 1: { + return this.preparePromptQualifier(); + } + case this._prompts.length > 1: { + return this.preparePromptsQualifier(); + } + case this._regions.length === 1: { + return this.prepareRegionQualifier(); + } + case this._regions.length > 1: { + return this.prepareRegionsQualifier(); + } + } + } + + private preparePromptQualifier() { + const prompt = this._prompts[0]; + + let str = `gen_remove:${new QualifierValue(`prompt_${prompt}`).toString()}`; + + if (this._detectMultiple) { + str += `;${new QualifierValue(`multiple_true`).toString()}`; + } + + this.addQualifier(new Qualifier("e", str)); + } + + private preparePromptsQualifier() { + const prompts = this._prompts; + + const str = `gen_remove:${new QualifierValue( + `prompt_(${prompts.join(";")})` + ).toString()}`; + + this.addQualifier(new Qualifier("e", str)); + } + + private prepareRegionQualifier() { + const region = this.stringifyRegion(this._regions[0]); + + const str = `gen_remove:${new QualifierValue( + `region_${region}` + ).toString()}`; + + this.addQualifier(new Qualifier("e", str)); + } + + private prepareRegionsQualifier() { + const regions = this._regions.map((region) => this.stringifyRegion(region)); + + const str = `gen_remove:${new QualifierValue( + `region_(${regions.join(";")})` + ).toString()}`; + + this.addQualifier(new Qualifier("e", str)); + } + + private stringifyRegion(region: Region) { + const { x, y, width, height } = region; + + return `(x_${x};y_${y};w_${width};h_${height})`; + } + + static fromJson(actionModel: IGenerativeRemoveModel): GenerativeRemove { + const { prompts, regions, detectMultiple } = actionModel; + const result = new this(); + + if (regions) { + result.regions(regions); + } + + if (prompts) { + result.prompts(prompts); + } + + if (detectMultiple) { + result.detectMultiple(detectMultiple); + } + + return result; + } +} + +export { GenerativeRemove }; diff --git a/src/internal/fromJson.ts b/src/internal/fromJson.ts index 54770ad..0ee17af 100644 --- a/src/internal/fromJson.ts +++ b/src/internal/fromJson.ts @@ -1,52 +1,55 @@ -import {ResizeScaleAction} from "../actions/resize/ResizeScaleAction.js"; -import {ResizeFitAction} from "../actions/resize/ResizeFitAction.js"; -import {ResizeLimitFitAction} from "../actions/resize/ResizeLimitFitAction.js"; -import {Transformation} from "../transformation/Transformation.js"; -import {IActionModel} from "./models/IActionModel.js"; -import {Action} from "./Action.js"; -import {IErrorObject} from "./models/IErrorObject.js"; -import {createUnsupportedError} from "./utils/unsupportedError.js"; -import {IHasFromJson, ITransformationFromJson} from "./models/IHasFromJson.js"; -import {ResizeMinimumFitAction} from "../actions/resize/ResizeMinimumFitAction.js"; -import {ResizeCropAction} from "../actions/resize/ResizeCropAction.js"; -import {OpacityAdjustAction} from "../actions/adjust/OpacityAdjustAction.js"; -import {ResizeFillAction} from "../actions/resize/ResizeFillAction.js"; -import {ResizeLimitFillAction} from "../actions/resize/ResizeLimitFillAction.js"; -import {ThumbResizeAction} from "../actions/resize/ThumbnailAction.js"; -import {ResizePadAction} from "../actions/resize/ResizePadAction.js"; -import {ResizeLimitPadAction} from "../actions/resize/ResizeLimitPadAction.js"; -import {ResizeMinimumPadAction} from "../actions/resize/ResizeMinimumPadAction.js"; -import {DeliveryColorSpaceAction} from "../actions/delivery/DeliveryColorSpaceAction.js"; -import {DeliveryColorSpaceFromICCAction} from "../actions/delivery/DeliveryColorSpaceFromICCAction.js"; -import {DeliveryFormatAction} from "../actions/delivery/DeliveryFormatAction.js"; -import {DeliveryQualityAction} from "../actions/delivery/DeliveryQualityAction.js"; -import {EffectActionWithLevel} from "../actions/effect/EffectActions/EffectActionWithLevel.js"; -import {SimpleEffectAction} from "../actions/effect/EffectActions/SimpleEffectAction.js"; -import {ShadowEffectAction} from "../actions/effect/Shadow.js"; -import {ColorizeEffectAction} from "../actions/effect/Colorize.js"; -import {EffectActionWithStrength} from "../actions/effect/EffectActions/EffectActionWithStrength.js"; -import {CartoonifyEffect} from "../actions/effect/Cartoonify.js"; -import {EffectOutline} from "../actions/effect/Outline.js"; -import {BlackwhiteEffectAction} from "../actions/effect/leveled/Blackwhite.js"; -import {AccelerationEffectAction} from "../actions/effect/leveled/Accelerate.js"; -import {LoopEffectAction} from "../actions/effect/leveled/Loop.js"; -import {MakeTransparentEffectAction} from "../actions/effect/leveled/MakeTransparent.js"; -import {DitherEffectAction} from "../actions/effect/Dither.js"; -import {VectorizeEffectAction} from "../actions/effect/Vectorize.js"; -import {GradientFadeEffectAction} from "../actions/effect/GradientFade.js"; -import {AssistColorBlindEffectAction} from "../actions/effect/AssistColorBlind.js"; -import {SimulateColorBlindEffectAction} from "../actions/effect/SimulateColorBlind.js"; -import {DeshakeEffectAction} from "../actions/effect/leveled/Deshake.js"; -import {Pixelate} from "../actions/effect/pixelate/Pixelate.js"; -import {BlurAction} from "../actions/effect/blur/Blur.js"; -import {ImproveAction} from "../actions/adjust/ImproveAction.js"; -import {DeliveryDPRAction} from "../actions/delivery/DeliveryDPRAction.js"; +import { ResizeScaleAction } from "../actions/resize/ResizeScaleAction.js"; +import { ResizeFitAction } from "../actions/resize/ResizeFitAction.js"; +import { ResizeLimitFitAction } from "../actions/resize/ResizeLimitFitAction.js"; +import { Transformation } from "../transformation/Transformation.js"; +import { IActionModel } from "./models/IActionModel.js"; +import { Action } from "./Action.js"; +import { IErrorObject } from "./models/IErrorObject.js"; +import { createUnsupportedError } from "./utils/unsupportedError.js"; +import { + IHasFromJson, + ITransformationFromJson, +} from "./models/IHasFromJson.js"; +import { ResizeMinimumFitAction } from "../actions/resize/ResizeMinimumFitAction.js"; +import { ResizeCropAction } from "../actions/resize/ResizeCropAction.js"; +import { OpacityAdjustAction } from "../actions/adjust/OpacityAdjustAction.js"; +import { ResizeFillAction } from "../actions/resize/ResizeFillAction.js"; +import { ResizeLimitFillAction } from "../actions/resize/ResizeLimitFillAction.js"; +import { ThumbResizeAction } from "../actions/resize/ThumbnailAction.js"; +import { ResizePadAction } from "../actions/resize/ResizePadAction.js"; +import { ResizeLimitPadAction } from "../actions/resize/ResizeLimitPadAction.js"; +import { ResizeMinimumPadAction } from "../actions/resize/ResizeMinimumPadAction.js"; +import { DeliveryColorSpaceAction } from "../actions/delivery/DeliveryColorSpaceAction.js"; +import { DeliveryColorSpaceFromICCAction } from "../actions/delivery/DeliveryColorSpaceFromICCAction.js"; +import { DeliveryFormatAction } from "../actions/delivery/DeliveryFormatAction.js"; +import { DeliveryQualityAction } from "../actions/delivery/DeliveryQualityAction.js"; +import { EffectActionWithLevel } from "../actions/effect/EffectActions/EffectActionWithLevel.js"; +import { SimpleEffectAction } from "../actions/effect/EffectActions/SimpleEffectAction.js"; +import { ShadowEffectAction } from "../actions/effect/Shadow.js"; +import { ColorizeEffectAction } from "../actions/effect/Colorize.js"; +import { EffectActionWithStrength } from "../actions/effect/EffectActions/EffectActionWithStrength.js"; +import { CartoonifyEffect } from "../actions/effect/Cartoonify.js"; +import { EffectOutline } from "../actions/effect/Outline.js"; +import { BlackwhiteEffectAction } from "../actions/effect/leveled/Blackwhite.js"; +import { AccelerationEffectAction } from "../actions/effect/leveled/Accelerate.js"; +import { LoopEffectAction } from "../actions/effect/leveled/Loop.js"; +import { MakeTransparentEffectAction } from "../actions/effect/leveled/MakeTransparent.js"; +import { DitherEffectAction } from "../actions/effect/Dither.js"; +import { VectorizeEffectAction } from "../actions/effect/Vectorize.js"; +import { GradientFadeEffectAction } from "../actions/effect/GradientFade.js"; +import { AssistColorBlindEffectAction } from "../actions/effect/AssistColorBlind.js"; +import { SimulateColorBlindEffectAction } from "../actions/effect/SimulateColorBlind.js"; +import { DeshakeEffectAction } from "../actions/effect/leveled/Deshake.js"; +import { Pixelate } from "../actions/effect/pixelate/Pixelate.js"; +import { BlurAction } from "../actions/effect/blur/Blur.js"; +import { ImproveAction } from "../actions/adjust/ImproveAction.js"; +import { DeliveryDPRAction } from "../actions/delivery/DeliveryDPRAction.js"; import ConcatenateAction from "../actions/videoEdit/ConcatenateAction.js"; -import {ITransformationModel} from "./models/ITransformationModel.js"; -import {PreviewAction} from "../actions/videoEdit/PreviewAction.js"; +import { ITransformationModel } from "./models/ITransformationModel.js"; +import { PreviewAction } from "../actions/videoEdit/PreviewAction.js"; import TrimAction from "../actions/videoEdit/TrimAction.js"; import VolumeAction from "../actions/videoEdit/VolumeAction.js"; -import {LayerAction} from "../actions/layer/LayerAction.js"; +import { LayerAction } from "../actions/layer/LayerAction.js"; import KeyframeIntervalsAction from "../actions/transcode/KeyframeIntervalsAction.js"; import FPSAction from "../actions/transcode/FPSAction.js"; import BitRateAction from "../actions/transcode/BitRateAction.js"; @@ -54,15 +57,16 @@ import AudioCodecAction from "../actions/transcode/AudioCodecAction.js"; import AudioFrequencyAction from "../actions/transcode/AudioFrequencyAction.js"; import StreamingProfileAction from "../actions/transcode/StreamingProfile.js"; import ToAnimatedAction from "../actions/transcode/ToAnimatedAction.js"; -import {FadeInEffectAction} from "../actions/effect/leveled/FadeIn.js"; -import {FadeOutEffectAction} from "../actions/effect/leveled/FadeOut.js"; -import {VideoCodecAction} from "../actions/transcode/VideoCodecAction.js"; -import {ConditionalAction} from "../actions/conditional.js"; +import { FadeInEffectAction } from "../actions/effect/leveled/FadeIn.js"; +import { FadeOutEffectAction } from "../actions/effect/leveled/FadeOut.js"; +import { VideoCodecAction } from "../actions/transcode/VideoCodecAction.js"; +import { ConditionalAction } from "../actions/conditional.js"; import RotateAction from "../actions/rotate/RotateAction.js"; -import {BackgroundRemoval} from "../actions/effect/BackgroundRemoval.js"; -import {DropShadow} from "../actions/effect/DropShadow.js"; +import { BackgroundRemoval } from "../actions/effect/BackgroundRemoval.js"; +import { DropShadow } from "../actions/effect/DropShadow.js"; import RoundCornersAction from "../actions/roundCorners/RoundCornersAction.js"; -import {BorderAction} from "../actions/border.js"; +import { BorderAction } from "../actions/border.js"; +import { GenerativeRemove } from "../actions/effect/GenerativeRemove.js"; const ActionModelMap: Record = { scale: ResizeScaleAction, @@ -137,6 +141,7 @@ const ActionModelMap: Record = { dropshadow: DropShadow, roundCorners: RoundCornersAction, border: BorderAction, + generativeRemove: GenerativeRemove, }; /** @@ -146,12 +151,17 @@ const ActionModelMap: Record = { */ function actions(actionModels: IActionModel[]): Action[] { return actionModels.map((actionModel) => { - const actionClass = (ActionModelMap[actionModel.actionType]); + const actionClass = ActionModelMap[actionModel.actionType]; if (!actionClass) { - throw createUnsupportedError(`unsupported action ${actionModel.actionType}`); + throw createUnsupportedError( + `unsupported action ${actionModel.actionType}` + ); } - return actionClass.fromJson(actionModel, fromJson as unknown as ITransformationFromJson); + return actionClass.fromJson( + actionModel, + fromJson as unknown as ITransformationFromJson + ); }); } @@ -159,15 +169,19 @@ function actions(actionModels: IActionModel[]): Action[] { * Return array of action instances represented by given action models. * @param transformationModel */ -function fromJson(transformationModel: ITransformationModel ): Transformation | IErrorObject { +function fromJson( + transformationModel: ITransformationModel +): Transformation | IErrorObject { try { // Create a new Transformation and add all actions to it const transformation = new Transformation(); - actions(transformationModel.actions).forEach((action)=>transformation.addAction(action)); + actions(transformationModel.actions).forEach((action) => + transformation.addAction(action) + ); return transformation; } catch (error) { - return {error}; + return { error }; } } -export {fromJson}; +export { fromJson }; diff --git a/src/internal/models/IEffectActionModel.ts b/src/internal/models/IEffectActionModel.ts index 386787c..814d3d0 100644 --- a/src/internal/models/IEffectActionModel.ts +++ b/src/internal/models/IEffectActionModel.ts @@ -1,62 +1,60 @@ -import {IActionModel} from "./IActionModel.js"; -import {ForegroundObjectValue} from "../../qualifiers/foregroundObject.js"; +import { IActionModel } from "./IActionModel.js"; +import { ForegroundObjectValue } from "../../qualifiers/foregroundObject.js"; -interface IEffectActionWithLevelModel extends IActionModel{ +interface IEffectActionWithLevelModel extends IActionModel { level?: number; } -interface IAccelerateActionModel extends IActionModel{ +interface IAccelerateActionModel extends IActionModel { rate?: number | string; } -interface ISimpleEffectActionModel extends IActionModel{ +interface ISimpleEffectActionModel extends IActionModel {} -} - -interface IShadowEffectActionModel extends IActionModel{ +interface IShadowEffectActionModel extends IActionModel { strength?: number; - offsetX?: string|number; - offsetY?: string|number; - color?: string + offsetX?: string | number; + offsetY?: string | number; + color?: string; } -interface IColorizeModel extends IActionModel{ +interface IColorizeModel extends IActionModel { level?: number; color?: string; } -interface IBackgroundRemovalModel extends IActionModel{ +interface IBackgroundRemovalModel extends IActionModel { fineEdges?: boolean; hints?: Array; } -interface ICartoonifyEffectModel extends IActionModel{ +interface ICartoonifyEffectModel extends IActionModel { lineStrength?: number; blackAndWhite?: boolean; colorReductionLevel?: number; } -interface IEffectOutlineModel extends IActionModel{ +interface IEffectOutlineModel extends IActionModel { mode?: string; color?: string; width?: number; blurLevel?: number; } -interface IDropShadowModel extends IActionModel{ +interface IDropShadowModel extends IActionModel { azimuth?: number; elevation?: number; spread?: number; } -interface IMakeTransparentEffectModel extends IActionModel{ +interface IMakeTransparentEffectModel extends IActionModel { tolerance?: number; color?: string; } interface IDitherModel extends IActionModel { type?: number; } -interface IVectorizeEffectModel extends IActionModel{ +interface IVectorizeEffectModel extends IActionModel { numOfColors?: number; detailLevel?: number; despeckleLevel?: number; @@ -64,44 +62,50 @@ interface IVectorizeEffectModel extends IActionModel{ cornersLevel?: number; } -interface IGradientFadeEffecModel extends IActionModel{ +interface IGradientFadeEffecModel extends IActionModel { strength?: number; type?: string; verticalStartPoint?: string; horizontalStartPoint?: string; } -interface IAssistColorBlindEffectModel extends IActionModel{ +interface IAssistColorBlindEffectModel extends IActionModel { type?: string; stripesStrength?: number; } -interface ISimulateColorBlindEffectModel extends IActionModel{ +interface ISimulateColorBlindEffectModel extends IActionModel { condition?: string; } -interface IDeshakeEffectModel extends IActionModel{ +interface IDeshakeEffectModel extends IActionModel { pixels?: 16 | 32 | 48 | 64; } -interface IPixelateModel extends IActionModel{ +interface IPixelateModel extends IActionModel { squareSize?: number; - region?: {RegionType?: string}; + region?: { RegionType?: string }; } -interface IBlurModel extends IActionModel{ +interface IBlurModel extends IActionModel { strength?: number; - region?: {RegionType?: string}; + region?: { RegionType?: string }; } -interface IFadeInEffectActionModel extends IActionModel{ +interface IFadeInEffectActionModel extends IActionModel { length?: number; } -interface IFadeOutEffectActionModel extends IActionModel{ +interface IFadeOutEffectActionModel extends IActionModel { length?: number; } +interface IGenerativeRemoveModel extends IActionModel { + prompts?: Array; + regions?: Array<{ x: number; y: number; width: number; height: number }>; + detectMultiple?: boolean; +} + export { IEffectActionWithLevelModel, ISimpleEffectActionModel, @@ -123,4 +127,5 @@ export { IAccelerateActionModel, IBackgroundRemovalModel, IDropShadowModel, + IGenerativeRemoveModel, };