Skip to content

Commit 4602946

Browse files
author
Nir Maoz
authored
Feature/add auto gravity model (#479)
1 parent f87c4b3 commit 4602946

File tree

5 files changed

+196
-29
lines changed

5 files changed

+196
-29
lines changed

__TESTS_BUNDLE_SIZE__/bundleSizeTestCases.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import importFromPackage from "./utils/stringGenerators/importFromPackage";
1515
const bundleSizeTestCases:ITestCase[] = [
1616
{
1717
name: 'Tests CloudinaryImage with Resize',
18-
sizeLimitInKB: 20,
18+
sizeLimitInKB: 21,
1919
importsArray: [
2020
importFromDist('assets/CloudinaryImage', 'CloudinaryImage'),
2121
importFromDist('instance/Cloudinary', 'Cloudinary'),
@@ -24,7 +24,7 @@ const bundleSizeTestCases:ITestCase[] = [
2424
},
2525
{
2626
name: 'Tests CloudinaryImage with Resize and Adjust',
27-
sizeLimitInKB: 24,
27+
sizeLimitInKB: 25,
2828
importsArray: [
2929
importFromDist('assets/CloudinaryImage', 'CloudinaryImage'),
3030
importFromDist('instance/Cloudinary', 'Cloudinary'),
@@ -34,7 +34,7 @@ const bundleSizeTestCases:ITestCase[] = [
3434
},
3535
{
3636
name: 'Tests CloudinaryImage with Resize, Adjust and Border',
37-
sizeLimitInKB: 24,
37+
sizeLimitInKB: 25,
3838
importsArray: [
3939
importFromDist('assets/CloudinaryImage', 'CloudinaryImage'),
4040
importFromDist('instance/Cloudinary', 'Cloudinary'),
@@ -45,7 +45,7 @@ const bundleSizeTestCases:ITestCase[] = [
4545
},
4646
{
4747
name: 'Tests CloudinaryImage image with Resize, adjust and delivery',
48-
sizeLimitInKB: 25,
48+
sizeLimitInKB: 26,
4949
importsArray: [
5050
importFromDist('assets/CloudinaryImage', 'CloudinaryImage'),
5151
importFromDist('instance/Cloudinary', 'Cloudinary'),
@@ -56,7 +56,7 @@ const bundleSizeTestCases:ITestCase[] = [
5656
},
5757
{
5858
name: 'Tests Overlay imports',
59-
sizeLimitInKB: 21,
59+
sizeLimitInKB: 22,
6060
importsArray: [
6161
importFromDist('assets/CloudinaryImage', 'CloudinaryImage'),
6262
importFromDist('actions/overlay', 'Overlay'),
@@ -88,7 +88,7 @@ const bundleSizeTestCases:ITestCase[] = [
8888
},
8989
{
9090
name: 'Import All Actions',
91-
sizeLimitInKB: 36,
91+
sizeLimitInKB: 37,
9292
importsArray: [
9393
importFromPackage('Actions')
9494
]

__TESTS__/unit/fromJson/resize.fromJson.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import {fromJson} from "../../../src/internal/fromJson";
2+
import {scale} from "../../../src/actions/resize";
3+
import {Transformation} from '../../../src';
4+
import {IActionModel} from "../../../src/internal/models/IActionModel";
5+
import {IResizeAdvancedActionModel} from "../../../src/internal/models/IResizeAdvancedActionModel";
26

37
describe('resize.fromJson', () => {
48
it('should generate a url with resize actions from array of models', function () {
@@ -14,6 +18,17 @@ describe('resize.fromJson', () => {
1418
{actionType: 'pad', dimensions: {width: 100}, relative: true, gravity: {gravityType: 'direction', compass: 'south'}, x: 3, y:4, background: 'white'},
1519
{actionType: 'limitPad', dimensions: {width: 100}, relative: true, gravity: {gravityType: 'direction', compass: 'south'}, x: 3, y:4, background: 'white'},
1620
{actionType: 'minimumPad', dimensions: {width: 100}, relative: true, gravity: {gravityType: 'direction', compass: 'south'}, x: 3, y:4, background: 'white'},
21+
{
22+
actionType: 'crop',
23+
dimensions: {width: 200},
24+
gravity: {
25+
gravityType: 'auto',
26+
autoFocus: [
27+
{object: 'person', weight: 100},
28+
{object: 'cat', avoid: true}
29+
]
30+
}
31+
}
1732
]);
1833

1934
expect(transformation.toString()).toStrictEqual([
@@ -28,6 +43,17 @@ describe('resize.fromJson', () => {
2843
'b_white,c_pad,fl_relative,g_south,w_100,x_3,y_4',
2944
'b_white,c_lpad,fl_relative,g_south,w_100,x_3,y_4',
3045
'b_white,c_mpad,fl_relative,g_south,w_100,x_3,y_4',
46+
'c_crop,g_auto:person_100:cat_avoid,w_200',
3147
].join('/'));
3248
});
49+
50+
it('Should get original action when doing .toJson().fromJson()', ()=>{
51+
const transformation = new Transformation().addAction(scale('1.0'));
52+
const json = transformation.toJson() as IActionModel[];
53+
54+
expect((json[0] as IResizeAdvancedActionModel).dimensions.width).toStrictEqual('1.0');
55+
expect(transformation.toString()).toStrictEqual('c_scale,w_1.0');
56+
expect(transformation).toMatchObject(fromJson(json));
57+
expect(transformation.toString()).toStrictEqual(fromJson(json).toString());
58+
});
3359
});

__TESTS__/unit/toJson/resize.toJson.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {Resize} from "../../../src/actions";
33
import {AspectRatio} from "../../../src/qualifiers";
44
import {Gravity} from "../../../src/qualifiers";
55
import {FocusOn} from "../../../src/qualifiers/focusOn";
6+
import {AutoFocus} from "../../../src/qualifiers/autoFocus";
67

78
describe('resize.toJson()', () => {
89
it('scale', () => {
@@ -158,4 +159,27 @@ describe('resize.toJson()', () => {
158159
}
159160
]);
160161
});
162+
163+
it('should generate auto gravity model', ()=>{
164+
const gravity = Gravity.autoGravity().autoFocus(
165+
AutoFocus.focusOn(FocusOn.person()).weight(100),
166+
AutoFocus.focusOn(FocusOn.cat()).weight(50).avoid()
167+
);
168+
169+
const transformation = new Transformation()
170+
.addAction(Resize.crop(200).gravity(gravity));
171+
172+
const model = transformation.toJson();
173+
174+
expect(model).toStrictEqual([
175+
{
176+
"actionType": "crop", "dimensions": {"width": 200}, "gravity": {
177+
"autoFocus": [
178+
{"object": "person", "weight": 100},
179+
{"object": "cat", "avoid": true}
180+
]
181+
}
182+
}
183+
]);
184+
});
161185
});

src/internal/models/createGravityFromModel.ts

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
import {ICompassGravityModel, IGravityModel, IOcrGravityModel} from "./createGravityModel.js";
1+
import {
2+
IAutoGravityModel,
3+
IAutoGravityObjectModel,
4+
ICompassGravityModel,
5+
IGravityModel,
6+
IOcrGravityModel
7+
} from "./createGravityModel.js";
28
import {IGravity} from "../../qualifiers/gravity/GravityQualifier.js";
3-
import {focusOn} from "../../qualifiers/gravity.js";
4-
import {ocr} from "../../qualifiers/focusOn.js";
9+
import {autoGravity, focusOn} from "../../qualifiers/gravity.js";
10+
import {FocusOnValue, ocr} from "../../qualifiers/focusOn.js";
11+
import {AutoGravity} from "../../qualifiers/gravity/autoGravity/AutoGravity.js";
12+
import {AutoFocus} from "../../qualifiers/autoFocus.js";
513

614
/**
715
* Validates that gravityModel is an ICompassGravityModel
@@ -19,18 +27,54 @@ function isOcrGravityModel(gravityModel: IGravityModel): gravityModel is IOcrGra
1927
return gravityModel.gravityType === 'ocr';
2028
}
2129

30+
/**
31+
* Validates that gravityModel is an IAutoGravityModel
32+
* @param gravityModel
33+
*/
34+
function isAutoGravityModel(gravityModel: IGravityModel): gravityModel is IAutoGravityModel {
35+
return gravityModel.gravityType === 'auto';
36+
}
37+
38+
/**
39+
* Create AutoFocus from IAutoGravityObjectModel
40+
* @param autoGravityObjectModel
41+
*/
42+
function createAutoFocusFromModel(autoGravityObjectModel: IAutoGravityObjectModel): AutoFocus {
43+
const {object, weight, avoid} = autoGravityObjectModel;
44+
const autoFocus = new AutoFocus(new FocusOnValue(object));
45+
(weight || weight === 0) && autoFocus.weight(weight);
46+
avoid && autoFocus.avoid();
47+
48+
return autoFocus;
49+
}
50+
51+
/**
52+
* Create AutoGravity from IAutoGravityModel
53+
* @param gravityModel
54+
*/
55+
function createAutoGravityFromModel(gravityModel: IAutoGravityModel): AutoGravity {
56+
const autoFocusModel = gravityModel.autoFocus || [];
57+
const autoFocus = autoFocusModel.map(createAutoFocusFromModel);
58+
59+
return autoGravity().autoFocus(...autoFocus);
60+
}
61+
2262
/**
2363
* Create gravity instance from given gravity model
2464
* @param gravityModel
2565
*/
26-
function createGravityFromModel(gravityModel: IGravityModel): IGravity{
27-
if (isCompassGravityModel(gravityModel)){
66+
function createGravityFromModel(gravityModel: IGravityModel): IGravity {
67+
if (isCompassGravityModel(gravityModel)) {
2868
return gravityModel.compass;
2969
}
3070

3171
if (isOcrGravityModel(gravityModel)) {
3272
return focusOn(ocr());
3373
}
74+
75+
if (isAutoGravityModel(gravityModel)) {
76+
return createAutoGravityFromModel(gravityModel);
77+
}
3478
}
3579

3680
export {createGravityFromModel};
Lines changed: 91 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,69 @@
11
import {IGravity} from "../../qualifiers/gravity/GravityQualifier.js";
2-
import {ICompassGravity} from "../../qualifiers/gravity/compassGravity/CompassGravity.js";
2+
import {CompassGravity, ICompassGravity} from "../../qualifiers/gravity/compassGravity/CompassGravity.js";
3+
import {AutoGravity} from "../../qualifiers/gravity/autoGravity/AutoGravity.js";
4+
import {AutoFocus} from "../../qualifiers/autoFocus.js";
35

4-
export interface IGravityModel{
6+
export interface IGravityModel {
57
gravityType?: string;
68
}
79

8-
export interface ICompassGravityModel extends IGravityModel{
10+
export interface ICompassGravityModel extends IGravityModel {
911
compass: ICompassGravity
1012
}
1113

12-
export interface IOcrGravityModel extends IGravityModel{}
14+
export interface IOcrGravityModel extends IGravityModel {
15+
}
16+
17+
export interface IAutoGravityObjectModel {
18+
object: string, // 'cat' | 'dog' etc
19+
weight?: number,
20+
avoid?: boolean
21+
}
22+
23+
export interface IAutoGravityModel extends IGravityModel {
24+
autoFocus: IAutoGravityObjectModel[]
25+
}
26+
27+
export interface IFocusOnGravityModel extends IGravityModel {
28+
focusOnObjects: string[], // 'cat' | 'dog' etc
29+
fallbackGravity: IAutoGravityModel
30+
}
1331

1432
/**
1533
* Validate that given val is an ICompassGravity
16-
* @param val
34+
* @param gravity
35+
*/
36+
function isCompassGravity(gravity: unknown): gravity is CompassGravity {
37+
//const gravityString = `${(typeof gravity === "string" ? gravity : gravity.qualifierValue)}`;
38+
const gravityValue = getGravityValue(gravity);
39+
return ['north', 'center', 'east', 'west', 'south', 'north_west', 'south_east', 'south_west', 'north_east'].includes(gravityValue);
40+
}
41+
42+
/**
43+
* Get the value of given gravity
44+
* @param gravity
1745
*/
18-
function isICompassGravity(val: unknown): val is ICompassGravity{
19-
return ['north', 'center', 'east', 'west', 'south', 'north_west', 'south_east', 'south_west', 'north_east'].includes(val as string);
46+
function getGravityValue(gravity: unknown): string {
47+
return `${gravity}`.replace('g_', '');
2048
}
2149

2250
/**
2351
* Creates a compassGravity model
24-
* @param compass
52+
* @param gravity
2553
*/
26-
function createCompassGravityModel(compass: ICompassGravity): ICompassGravityModel{
54+
function createCompassGravityModel(gravity: CompassGravity): ICompassGravityModel {
2755
return {
28-
compass,
56+
compass: getGravityValue(gravity) as ICompassGravity,
2957
gravityType: 'direction'
3058
};
3159
}
3260

3361
/**
34-
* Validate that given string represents an ocr gravity
62+
* Validate that given gravity is an instance of ocr gravity
3563
* @param gravity
3664
*/
37-
function isIOcrGravity(gravity: string): boolean {
38-
return gravity === 'ocr_text';
65+
function isOcrGravity(gravity: unknown): boolean {
66+
return getGravityValue(gravity) === 'ocr_text';
3967
}
4068

4169
/**
@@ -47,18 +75,63 @@ function createOcrGravityModel(): IOcrGravityModel {
4775
};
4876
}
4977

78+
/**
79+
* Validate that given gravity is an instance of AutoGravity
80+
* @param gravity
81+
*/
82+
function isAutoGravity(gravity: unknown): gravity is AutoGravity {
83+
return `${(gravity as AutoGravity).qualifierValue}`.split(':')[0] === 'auto';
84+
}
85+
86+
/**
87+
* Create an instance of IAutoGravityObjectModel
88+
* @param gravity
89+
*/
90+
function createIAutoFocusObject(gravity: AutoFocus): IAutoGravityObjectModel {
91+
const gravityString = gravity.toString();
92+
const values = gravityString.split('_');
93+
const result: IAutoGravityObjectModel = {
94+
object: values[0]
95+
};
96+
97+
if (values.length > 1) {
98+
if (values[1] === 'avoid') {
99+
result.avoid = true;
100+
} else {
101+
result.weight = +values[1];
102+
}
103+
}
104+
105+
return result;
106+
}
107+
108+
/**
109+
* Creates an auto gravity model from given AutoGravity
110+
* @param gravity
111+
*/
112+
function createAutoGravityModel(gravity: AutoGravity): IAutoGravityModel {
113+
const values = gravity.qualifierValue.values.filter((v) => v !== 'auto');
114+
const autoFocus = values.map(createIAutoFocusObject);
115+
116+
return {
117+
autoFocus
118+
};
119+
}
120+
50121
/**
51122
* Create a model of given gravity
52123
* @param gravity
53124
*/
54125
export function createGravityModel(gravity: IGravity): IGravityModel {
55-
const gravityString = `${(typeof gravity === "string" ? gravity : gravity.qualifierValue)}`;
56-
57-
if (isICompassGravity(gravityString)) {
58-
return createCompassGravityModel(gravityString);
126+
if (isCompassGravity(gravity)) {
127+
return createCompassGravityModel(gravity);
59128
}
60129

61-
if (isIOcrGravity(gravityString)) {
130+
if (isOcrGravity(gravity)) {
62131
return createOcrGravityModel();
63132
}
133+
134+
if (isAutoGravity(gravity)) {
135+
return createAutoGravityModel(gravity);
136+
}
64137
}

0 commit comments

Comments
 (0)