Skip to content

Commit

Permalink
add support for extract transformation
Browse files Browse the repository at this point in the history
  • Loading branch information
lisa-kuzmina committed Aug 27, 2024
1 parent 265c5cb commit 1cffac7
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 4 deletions.
11 changes: 10 additions & 1 deletion __TESTS__/unit/fromJson/effect.fromJson.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ describe('effect.fromJson', () => {
{ actionType: 'enhance' },
{ actionType: 'generativeBackgroundReplace', prompt: 'dog' },
{ actionType: 'generativeBackgroundReplace'},
{ actionType: 'extract', 'prompts': 'blue sky' },
{ actionType: 'extract', 'prompts': ['blue sky', 'yellow sun'], detectMultiple: true },
{ actionType: 'extract', 'prompts': ['green grass'], mode: 'mask', invert: true },
{ actionType: 'extract', 'prompts': ['yellow sun', 'green grass'], mode: 'content' },

]});

expect(transformation.toString().split('/')).toStrictEqual([
Expand Down Expand Up @@ -101,7 +106,11 @@ describe('effect.fromJson', () => {
'e_upscale',
'e_enhance',
'e_gen_background_replace:prompt_dog',
'e_gen_background_replace'
'e_gen_background_replace',
'e_extract:prompt_blue sky',
'e_extract:prompt_(blue sky;yellow sun);multiple_true',
'e_extract:prompt_green grass;mode_mask;invert_true',
'e_extract:prompt_(yellow sun;green grass);mode_content',
]);
});
});
40 changes: 40 additions & 0 deletions __TESTS__/unit/toJson/effect.toJson.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,46 @@ describe('Effect toJson()', () => {
});
});

it('effect.extract', () => {
const transformation = new Transformation()
.addAction(Effect.extract('palms'))
.addAction(Effect.extract(['man']).mode('mask'))
.addAction(Effect.extract('woman').invert(true))
.addAction(Effect.extract(['cats', 'dogs']).detectMultiple(true))
.addAction(Effect.extract(['dogs', 'cats']).mode('content').detectMultiple(true).invert(false));


expect(transformation.toJson()).toStrictEqual({
actions: [
{
actionType: 'extract',
prompts: ['palms'],
},
{
actionType: 'extract',
prompts: ['man'],
mode: 'mask',
},
{
actionType: 'extract',
prompts: ['woman'],
invert: true,
},
{
actionType: 'extract',
prompts: ['cats', 'dogs'],
detectMultiple: true,
},
{
actionType: 'extract',
prompts: ['dogs', 'cats'],
mode: 'content',
detectMultiple: true
},
]
});
});

it('effect.GenerativeRecolor', () => {
const transformation = new Transformation()
.addAction(Effect.generativeRecolor('something', 'red'))
Expand Down
20 changes: 18 additions & 2 deletions src/actions/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { GenerativeRemove } from "./effect/GenerativeRemove.js";
import { GenerativeReplace } from "./effect/GenerativeReplace.js";
import { GenerativeRecolor } from "./effect/GenerativeRecolor.js";
import { GenerativeBackgroundReplace } from "./effect/GenerativeBackgroundReplace.js";
import { Extract } from "./effect/Extract.js";

/**
* @summary action
Expand Down Expand Up @@ -473,6 +474,18 @@ function generativeBackgroundReplace(): GenerativeBackgroundReplace {
return new GenerativeBackgroundReplace();
}

/**
* @summary action
* @description Extracts an area or multiple areas of an image, described in natural language.
* {@link https://cloudinary.com/documentation/transformation_reference#e_extract|Extract}
*
* @memberOf Actions.Effect
* @return {Actions.Effect.Extract}
*/
function extract(prompts: string | string[]): Extract {
return new Extract(prompts);
}

/**
* @summary action
* @description Uses generative AI to recolor objects from your image.
Expand Down Expand Up @@ -628,7 +641,8 @@ const Effect = {
generativeRestore,
upscale,
theme,
enhance
enhance,
extract
};

export declare type EffectActions =
Expand All @@ -652,7 +666,8 @@ export declare type EffectActions =
| GenerativeRemove
| GenerativeReplace
| GenerativeBackgroundReplace
| GenerativeRecolor;
| GenerativeRecolor
| Extract;

export {
Effect,
Expand Down Expand Up @@ -698,4 +713,5 @@ export {
upscale,
theme,
enhance,
extract
};
111 changes: 111 additions & 0 deletions src/actions/effect/Extract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { Action } from "../../internal/Action.js";
import { Qualifier } from "../../internal/qualifier/Qualifier.js";
import { IExtractModel } from "../../internal/models/IEffectActionModel.js";
import { ExtractModeType } from "../../types/types.js";
import { QualifierValue } from "../../internal/qualifier/QualifierValue.js";

/**
* @description Extracts an area or multiple areas of an image, described in natural language.
* @extends SDK.Action
* @memberOf Actions.Effect
* @see Visit {@link Actions.Effect|Effect} for an example
*/
class Extract extends Action {
private _prompts: Array<string> = [];
private _detectMultiple = false;
private _mode: ExtractModeType;
private _invert = false;

constructor(prompts: string | string[]) {
super();
this._actionModel.actionType = "extract";

this._prompts = Array.isArray(prompts) ? prompts : [prompts];
this._actionModel.prompts = this._prompts;
}

detectMultiple(value = false) {
this._detectMultiple = value;

if (this._detectMultiple) {
this._actionModel.detectMultiple = this._detectMultiple;
}

return this;
}

mode(mode?: ExtractModeType) {
this._mode = mode;
this._actionModel.mode = this._mode;

return this;
}

invert(value = false) {
this._invert = value;

if (this._invert) {
this._actionModel.invert = this._invert;
}

return this;
}

protected prepareQualifiers(): void {
const qualifierValue = new QualifierValue().setDelimiter(";");

if (this._prompts.length) {
qualifierValue.addValue(this.preparePromptValue());
}

if (this._detectMultiple) {
qualifierValue.addValue("multiple_true");
}

if (this._mode) {
qualifierValue.addValue(`mode_${this._mode}`);
}

if (this._invert) {
qualifierValue.addValue("invert_true");
}

this.addQualifier(
new Qualifier("e", `extract:${qualifierValue.toString()}`)
);
}

private preparePromptValue() {
const prompts = this._prompts;
const qualifierValue = new QualifierValue().setDelimiter(";");

if (prompts.length === 1) {
qualifierValue.addValue(`prompt_${prompts[0]}`);
} else {
qualifierValue.addValue(`prompt_(${prompts.join(";")})`);
}

return qualifierValue;
}

static fromJson(actionModel: IExtractModel): Extract {
const { prompts, detectMultiple, mode, invert } = actionModel;
const result = new this(prompts);

if (detectMultiple) {
result.detectMultiple(detectMultiple);
}

if (mode) {
result.mode(mode);
}

if (invert) {
result.invert(invert);
}

return result;
}
}

export { Extract };
4 changes: 3 additions & 1 deletion src/internal/fromJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import { ResizeAdvancedAction } from "../actions/resize/ResizeAdvancedAction.js"
import { BackgroundColor } from "../actions/background/actions/BackgroundColor.js";
import { ResizeAutoPadAction } from "../actions/resize/ResizeAutoPadAction.js";
import { GenerativeBackgroundReplace } from "../actions/effect/GenerativeBackgroundReplace.js";
import { Extract } from "../actions/effect/Extract.js";

const ActionModelMap: Record<string, IHasFromJson> = {
scale: ResizeScaleAction,
Expand Down Expand Up @@ -158,7 +159,8 @@ const ActionModelMap: Record<string, IHasFromJson> = {
backgroundColor: BackgroundColor,
autoPad: ResizeAutoPadAction,
enhance: SimpleEffectAction,
sharpen: EffectActionWithStrength
sharpen: EffectActionWithStrength,
extract: Extract
};

/**
Expand Down
10 changes: 10 additions & 0 deletions src/internal/models/IEffectActionModel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IActionModel } from "./IActionModel.js";
import { ForegroundObjectValue } from "../../qualifiers/foregroundObject.js";
import { SystemColors } from "../../qualifiers/color.js";
import { ExtractModeType } from "types/types.js";

interface IEffectActionWithLevelModel extends IActionModel {
level?: number;
Expand Down Expand Up @@ -143,6 +144,14 @@ interface IBackgroundColorModel extends IActionModel {
color?: SystemColors | string;
}


interface IExtractModel extends IActionModel {
prompts: Array<string>;
detectMultiple?: boolean;
mode?: ExtractModeType;
invert?: boolean;
}

export {
IEffectActionWithLevelModel,
ISimpleEffectActionModel,
Expand All @@ -169,4 +178,5 @@ export {
IGenerativeRecolorModel,
IGenerativeBackgroundReplaceModel,
IBackgroundColorModel,
IExtractModel
};
39 changes: 39 additions & 0 deletions src/qualifiers/extractMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @description Contains functions that decide whether to keep the content of the extracted area, or to replace it with a mask.
* @namespace Extract
* @memberOf Qualifiers
* @see Visit {@link Actions.Effect|Effect Action} for an example
*/

/**
* @summary qualifier
* @memberOf Qualifiers.Extract
*/
function content(): string {
return 'content';
}

/**
* @summary qualifier
* @memberOf Qualifiers.Extract
*/
function mask(): string {
return 'mask';
}

/**
* @summary qualifier
* @memberOf Qualifiers.Extract
*/


const ExtractMode = {
content,
mask
};

export {
ExtractMode,
content,
mask
};
4 changes: 4 additions & 0 deletions src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@ export type OutlineModeType =
"inner_fill"|
"fill";

export type ExtractModeType =
"content"|
"mask";

export type ProgressiveType =
"semi"|
"none"|
Expand Down

0 comments on commit 1cffac7

Please sign in to comment.