@syncfusion/ej2-image-editor 31.1.17 → 31.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/ej2-image-editor.umd.min.js +3 -3
  2. package/dist/ej2-image-editor.umd.min.js.map +1 -1
  3. package/dist/es6/ej2-image-editor.es2015.js +72 -9
  4. package/dist/es6/ej2-image-editor.es2015.js.map +1 -1
  5. package/dist/es6/ej2-image-editor.es5.js +72 -9
  6. package/dist/es6/ej2-image-editor.es5.js.map +1 -1
  7. package/dist/global/ej2-image-editor.min.js +3 -3
  8. package/dist/global/ej2-image-editor.min.js.map +1 -1
  9. package/dist/global/index.d.ts +2 -2
  10. package/package.json +14 -46
  11. package/src/image-editor/action/export.js +6 -2
  12. package/src/image-editor/action/freehand-draw.d.ts +1 -0
  13. package/src/image-editor/action/freehand-draw.js +30 -3
  14. package/src/image-editor/action/selection.js +14 -2
  15. package/src/image-editor/action/undo-redo.js +10 -0
  16. package/src/image-editor/base/image-editor.d.ts +1 -0
  17. package/src/image-editor/base/image-editor.js +9 -2
  18. package/src/image-editor/renderer/toolbar.js +3 -0
  19. package/dist/ts/image-editor/action/crop.d.ts +0 -44
  20. package/dist/ts/image-editor/action/crop.ts +0 -867
  21. package/dist/ts/image-editor/action/draw.d.ts +0 -187
  22. package/dist/ts/image-editor/action/draw.ts +0 -4924
  23. package/dist/ts/image-editor/action/export.d.ts +0 -29
  24. package/dist/ts/image-editor/action/export.ts +0 -509
  25. package/dist/ts/image-editor/action/filter.d.ts +0 -48
  26. package/dist/ts/image-editor/action/filter.ts +0 -872
  27. package/dist/ts/image-editor/action/freehand-draw.d.ts +0 -68
  28. package/dist/ts/image-editor/action/freehand-draw.ts +0 -1135
  29. package/dist/ts/image-editor/action/index.d.ts +0 -9
  30. package/dist/ts/image-editor/action/index.ts +0 -9
  31. package/dist/ts/image-editor/action/selection.d.ts +0 -178
  32. package/dist/ts/image-editor/action/selection.ts +0 -5241
  33. package/dist/ts/image-editor/action/shape.d.ts +0 -130
  34. package/dist/ts/image-editor/action/shape.ts +0 -3917
  35. package/dist/ts/image-editor/action/transform.d.ts +0 -77
  36. package/dist/ts/image-editor/action/transform.ts +0 -2008
  37. package/dist/ts/image-editor/action/undo-redo.d.ts +0 -52
  38. package/dist/ts/image-editor/action/undo-redo.ts +0 -1169
  39. package/dist/ts/image-editor/base/enum.d.ts +0 -277
  40. package/dist/ts/image-editor/base/enum.ts +0 -288
  41. package/dist/ts/image-editor/base/image-editor-model.d.ts +0 -770
  42. package/dist/ts/image-editor/base/image-editor.d.ts +0 -1928
  43. package/dist/ts/image-editor/base/image-editor.ts +0 -5496
  44. package/dist/ts/image-editor/base/index.d.ts +0 -4
  45. package/dist/ts/image-editor/base/index.ts +0 -4
  46. package/dist/ts/image-editor/base/interface.d.ts +0 -1637
  47. package/dist/ts/image-editor/base/interface.ts +0 -1709
  48. package/dist/ts/image-editor/index.d.ts +0 -3
  49. package/dist/ts/image-editor/index.ts +0 -3
  50. package/dist/ts/image-editor/renderer/index.d.ts +0 -1
  51. package/dist/ts/image-editor/renderer/index.ts +0 -1
  52. package/dist/ts/image-editor/renderer/toolbar.d.ts +0 -171
  53. package/dist/ts/image-editor/renderer/toolbar.ts +0 -6356
  54. package/dist/ts/index.d.ts +0 -4
  55. package/dist/ts/index.ts +0 -4
@@ -1,872 +0,0 @@
1
- import { ImageEditor, ImageFinetuneOption, CurrentObject, SelectionPoint, Point, ActivePoint, Adjustment, FinetuneSettingsModel } from '../index';
2
- import { isNullOrUndefined, extend } from '@syncfusion/ej2-base';
3
- import { FrameValue } from '../base';
4
-
5
- export class Filter {
6
- private parent: ImageEditor;
7
- private lowerContext: CanvasRenderingContext2D;
8
- private adjustmentLevel: Adjustment = {brightness: 0, contrast: 0, hue: 0, opacity: 100, saturation: 0, blur: 0,
9
- exposure: 0, transparency: 100, sharpen: false, bw: false}; // for toolbar slider value
10
- private tempAdjustmentLevel: Adjustment = {brightness: 0, contrast: 0, hue: 0, opacity: 100, saturation: 0, blur: 0,
11
- exposure: 0, transparency: 100, sharpen: false, bw: false}; // for temp toolbar slider value
12
- private adjustmentValue: string = ''; // for internal slider value
13
- private isBrightnessAdjusted: boolean = false;
14
- private bevelFilter: string = 'none';
15
- private tempAdjVal: Adjustment = {brightness: 0, contrast: 0, hue: 0, opacity: 100, saturation: 0, blur: 0,
16
- exposure: 0, transparency: 100, sharpen: false, bw: false};
17
- private tempFilVal: string = '';
18
-
19
- constructor(parent: ImageEditor) {
20
- this.parent = parent;
21
- this.addEventListener();
22
- }
23
-
24
- public destroy(): void {
25
- if (this.parent.isDestroyed) { return; }
26
- this.removeEventListener();
27
- }
28
-
29
- private addEventListener(): void {
30
- this.parent.on('filter', this.filter, this);
31
- this.parent.on('destroyed', this.destroy, this);
32
- }
33
-
34
- private removeEventListener(): void {
35
- this.parent.off('filter', this.filter);
36
- this.parent.off('destroyed', this.destroy);
37
- }
38
-
39
- private filter(args?: { onPropertyChange: boolean, prop: string, value?: object }): void {
40
- this.updatePrivateVariables();
41
- switch (args.prop) {
42
- case 'finetuneImage':
43
- this.finetuneImage(args.value['option'] as ImageFinetuneOption, args.value['value'] as number);
44
- break;
45
- case 'applyImageFilter':
46
- this.setFilter(args.value['option'] as string);
47
- break;
48
- case 'update-finetunes':
49
- this.updateFinetunes();
50
- break;
51
- case 'set-adjustment':
52
- this.setAdjustment(args.value['operation'] as string);
53
- break;
54
- case 'initFilter':
55
- this.initFilter();
56
- break;
57
- case 'setCurrAdjValue':
58
- this.setCurrAdjValue(args.value['type'] as string, args.value['value'] as number);
59
- break;
60
- case 'updateAdj':
61
- this.updateAdj(args.value['type'] as string, args.value['value'] as number, args.value['isPreview'],
62
- args.value['ctx']);
63
- break;
64
- case 'getCurrentObj':
65
- this.getCurrentObj(args.value['object']);
66
- break;
67
- case 'getAdjustmentLevel':
68
- if (isNullOrUndefined(this.parent.activeObj.opacity)) {
69
- this.adjustmentLevel.transparency = 100;
70
- } else {
71
- this.adjustmentLevel.transparency = this.parent.activeObj.opacity * 100;
72
- }
73
- args.value['obj']['adjustmentLevel'] = this.adjustmentLevel;
74
- break;
75
- case 'setAdjustmentLevel':
76
- this.adjustmentLevel = args.value['adjustmentLevel'];
77
- break;
78
- case 'getTempAdjustmentLevel':
79
- args.value['obj']['tempAdjustmentLevel'] = this.tempAdjustmentLevel;
80
- break;
81
- case 'setTempAdjustmentLevel':
82
- this.tempAdjustmentLevel = args.value['tempAdjustmentLevel'];
83
- break;
84
- case 'setAdjustmentValue':
85
- this.adjustmentValue = args.value['adjustmentValue'];
86
- break;
87
- case 'setBrightnessAdjusted':
88
- this.isBrightnessAdjusted = args.value['isBrightnessAdjusted'];
89
- if (this.parent.currentFilter.split('_') && this.parent.currentFilter.split('_')[1] === 'cold') {
90
- this.isBrightnessAdjusted = false;
91
- }
92
- break;
93
- case 'getBevelFilter':
94
- args.value['obj']['bevelFilter'] = this.bevelFilter;
95
- break;
96
- case 'setBevelFilter':
97
- this.bevelFilter = args.value['bevelFilter'];
98
- break;
99
- case 'setTempAdjVal':
100
- this.tempAdjVal = extend({}, this.adjustmentLevel, {}, true) as Adjustment;
101
- break;
102
- case 'setTempFilVal':
103
- this.tempFilVal = this.parent.currentFilter;
104
- break;
105
- case 'reset':
106
- this.reset();
107
- break;
108
- case 'apply-filter':
109
- this.applyFilter(args.value['context'] as CanvasRenderingContext2D);
110
- break;
111
- }
112
- }
113
-
114
- private updatePrivateVariables(): void {
115
- const parent: ImageEditor = this.parent;
116
- if (parent.lowerCanvas) {this.lowerContext = parent.lowerCanvas.getContext('2d'); }
117
- }
118
-
119
- public getModuleName(): string {
120
- return 'filter';
121
- }
122
-
123
- private reset(): void {
124
- this.adjustmentLevel = {brightness: 0, contrast: 0, hue: 0, opacity: 100, saturation: 0,
125
- blur: 0, exposure: 0, transparency: 100, sharpen: false, bw: false};
126
- this.tempAdjustmentLevel = {brightness: 0, contrast: 0, hue: 0, opacity: 100, saturation: 0,
127
- blur: 0, exposure: 0, transparency: 100, sharpen: false, bw: false};
128
- this.adjustmentValue = this.parent.getDefaultFilter();
129
- this.isBrightnessAdjusted = false; this.bevelFilter = 'none'; this.tempFilVal = '';
130
- this.tempAdjVal = {brightness: 0, contrast: 0, hue: 0, opacity: 100, saturation: 0,
131
- blur: 0, exposure: 0, transparency: 100, sharpen: false, bw: false};
132
- }
133
-
134
- private updateFinetunes(): void {
135
- const parent: ImageEditor = this.parent;
136
- const fs: FinetuneSettingsModel = parent.finetuneSettings;
137
- if (fs) {
138
- const propertiesToSet: string[] = ['brightness', 'contrast', 'hue', 'saturation', 'exposure', 'opacity', 'blur'];
139
- propertiesToSet.forEach((property: string) => {
140
- if (fs[property as string]) {
141
- this.adjustmentLevel[property as string] = fs[property as string].defaultValue;
142
- this.tempAdjustmentLevel[property as string] = fs[property as string].defaultValue;
143
- }
144
- });
145
- parent.notify('draw', { prop: 'isInitialLoading', onPropertyChange: false, value: { isInitialLoading: true } });
146
- }
147
- }
148
-
149
- private initFilter(): void {
150
- this.setFilterAdj('brightness', this.adjustmentLevel.brightness);
151
- this.setFilterAdj('contrast', this.adjustmentLevel.contrast);
152
- this.setFilterAdj('hue', this.adjustmentLevel.hue);
153
- this.setFilterAdj('saturation', this.adjustmentLevel.saturation);
154
- this.setFilterAdj('exposure', this.adjustmentLevel.exposure);
155
- this.setFilterAdj('opacity', this.adjustmentLevel.opacity);
156
- this.setFilterAdj('blur', this.adjustmentLevel.blur);
157
- }
158
-
159
- private updateAdj(type: string, value: number, isPreview?: boolean, ctx?: CanvasRenderingContext2D): void {
160
- const parent: ImageEditor = this.parent;
161
- this.lowerContext.clearRect(0, 0, parent.lowerCanvas.width, parent.lowerCanvas.height);
162
- let splitWords: string[] = this.lowerContext.filter.split(' ');
163
- let values: string[] = [];
164
- const brightness: number = this.getFilterValue(this.adjustmentLevel.brightness);
165
- let saturate: number; let bright: number; let saturatePercent: number; let contrast: number;
166
- let saturatePercentage: number;
167
- switch (type) {
168
- case 'brightness':
169
- value = this.getFilterValue(this.adjustmentLevel.exposure) + (value * 0.005);
170
- splitWords[0] = 'brightness(' + value + ')';
171
- if (this.adjustmentLevel.brightness !== 0) {
172
- value = (this.adjustmentLevel.opacity / 100) - (this.adjustmentLevel.opacity * 0.3) / 100;
173
- splitWords[4] = 'opacity(' + value + ')';
174
- }
175
- else {
176
- value = this.adjustmentLevel.opacity / 100;
177
- splitWords[4] = 'opacity(' + value + ')';
178
- }
179
- this.adjustmentValue = splitWords.join(' ');
180
- break;
181
- case 'contrast':
182
- splitWords[1] = 'contrast(' + value + '%)';
183
- this.adjustmentValue = splitWords.join(' ');
184
- break;
185
- case 'hue':
186
- splitWords[2] = 'hue-rotate(' + value + 'deg)';
187
- this.adjustmentValue = splitWords.join(' ');
188
- break;
189
- case 'saturation':
190
- splitWords[3] = 'saturate(' + value + '%)';
191
- this.adjustmentValue = splitWords.join(' ');
192
- break;
193
- case 'opacity':
194
- if (parseFloat(splitWords[0].split('(')[1]) !== 1) {
195
- value -= 0.2;
196
- }
197
- if (value < 0) {value = 0; }
198
- splitWords[4] = 'opacity(' + value + ')';
199
- this.adjustmentValue = splitWords.join(' ');
200
- break;
201
- case 'blur':
202
- splitWords[5] = 'blur(' + value + 'px)';
203
- this.adjustmentValue = splitWords.join(' ');
204
- break;
205
- case 'exposure':
206
- if (value > 1) {
207
- value -= 1; value += brightness;
208
- } else if (value < 1) {
209
- value = 1 - value; value = brightness - value;
210
- }
211
- splitWords[0] = 'brightness(' + value + ')';
212
- this.adjustmentValue = splitWords.join(' ');
213
- break;
214
- case 'chrome':
215
- saturate = this.getSaturationFilterValue(this.adjustmentLevel.saturation);
216
- saturate *= 100;
217
- value = saturate + (saturate * 0.4);
218
- splitWords[3] = 'saturate(' + value + '%)';
219
- values = this.adjustmentValue.split(' ');
220
- splitWords[0] = values[0];
221
- splitWords[1] = values[1];
222
- splitWords[2] = values[2];
223
- splitWords[4] = values[4];
224
- splitWords[5] = values[5];
225
- splitWords[6] = 'sepia(0%)';
226
- splitWords[7] = 'grayscale(0%)';
227
- splitWords[8] = 'invert(0%)';
228
- break;
229
- case 'cold':
230
- // Adjusting Brightness
231
- bright = this.getFilterValue(this.adjustmentLevel.brightness);
232
- bright *= 100;
233
- value = bright * 0.9;
234
- value *= 0.01;
235
- splitWords[0] = 'brightness(' + value + ')';
236
- // Adjusting Contrast
237
- contrast = this.getFilterValue(this.adjustmentLevel.contrast);
238
- contrast *= 100;
239
- value = contrast + (contrast * 0.5);
240
- splitWords[1] = 'contrast(' + value + '%)';
241
- // Adjusting Saturation
242
- saturatePercentage = this.getSaturationFilterValue(this.adjustmentLevel.saturation);
243
- saturatePercentage *= 100;
244
- value = saturatePercentage;
245
- splitWords[3] = 'saturate(' + value + '%)';
246
- values = this.adjustmentValue.split(' ');
247
- splitWords[2] = values[2];
248
- splitWords[4] = values[4];
249
- splitWords[5] = values[5];
250
- splitWords[6] = 'sepia(0%)';
251
- splitWords[7] = 'grayscale(0%)';
252
- splitWords[8] = 'invert(0%)';
253
- break;
254
- case 'warm':
255
- saturatePercent = this.getSaturationFilterValue(this.adjustmentLevel.saturation);
256
- saturatePercent *= 100;
257
- value = saturatePercent + (saturatePercent * 0.4);
258
- splitWords[3] = 'saturate(' + value + '%)';
259
- splitWords[6] = 'sepia(25%)';
260
- values = this.adjustmentValue.split(' ');
261
- splitWords[0] = values[0];
262
- splitWords[1] = values[1];
263
- splitWords[2] = values[2];
264
- splitWords[4] = values[4];
265
- splitWords[5] = values[5];
266
- splitWords[7] = 'grayscale(0%)';
267
- splitWords[8] = 'invert(0%)';
268
- break;
269
- case 'grayscale':
270
- splitWords[7] = 'grayscale(100%)';
271
- values = this.adjustmentValue.split(' ');
272
- splitWords[0] = values[0];
273
- splitWords[1] = values[1];
274
- splitWords[2] = values[2];
275
- splitWords[3] = values[3];
276
- splitWords[4] = values[4];
277
- splitWords[5] = values[5];
278
- splitWords[6] = 'sepia(0%)';
279
- splitWords[8] = 'invert(0%)';
280
- break;
281
- case 'sepia':
282
- splitWords[6] = 'sepia(100%)';
283
- values = this.adjustmentValue.split(' ');
284
- splitWords[0] = values[0];
285
- splitWords[1] = values[1];
286
- splitWords[2] = values[2];
287
- splitWords[3] = values[3];
288
- splitWords[4] = values[4];
289
- splitWords[5] = values[5];
290
- splitWords[7] = 'grayscale(0%)';
291
- splitWords[8] = 'invert(0%)';
292
- break;
293
- case 'invert':
294
- splitWords[8] = 'invert(100%)';
295
- values = this.adjustmentValue.split(' ');
296
- splitWords[0] = values[0];
297
- splitWords[1] = values[1];
298
- splitWords[2] = values[2];
299
- splitWords[3] = values[3];
300
- splitWords[4] = values[4];
301
- splitWords[5] = values[5];
302
- splitWords[6] = 'sepia(0%)';
303
- splitWords[7] = 'grayscale(0%)';
304
- break;
305
- }
306
- if (type !== 'sharpen' && type !== 'blackandwhite') {
307
- if (isNullOrUndefined(isPreview)) {
308
- if (type === 'default') {
309
- splitWords = this.getDefaultCurrentFilter(splitWords);
310
- }
311
- this.lowerContext.filter = splitWords.join(' ');
312
- }
313
- splitWords = this.setTempFilterValue(brightness, isPreview, splitWords, type);
314
- parent.notify('draw', { prop: 'setRotateZoom', onPropertyChange: false, value: {isRotateZoom: true }});
315
- parent.notify('draw', { prop: 'updateCurrTransState', onPropertyChange: false,
316
- value: {type: 'initial', isPreventDestination: null, isRotatePan: null} });
317
- let tempFilter: string;
318
- if (parent.frameObj.type === 'bevel') {
319
- tempFilter = this.lowerContext.filter;
320
- this.bevelFilter = tempFilter;
321
- }
322
- if (parent.transform.degree === 0 && parent.rotateFlipColl.length > 0) {
323
- parent.img.destLeft += parent.panPoint.totalPannedPoint.x;
324
- parent.img.destTop += parent.panPoint.totalPannedPoint.y;
325
- }
326
- parent.img.destLeft += parent.panPoint.totalPannedInternalPoint.x;
327
- parent.img.destTop += parent.panPoint.totalPannedInternalPoint.y;
328
- if (parent.transform.degree === 0) {
329
- parent.notify('transform', { prop: 'setDestPointsForFlipState', onPropertyChange: false });
330
- }
331
- parent.notify('draw', { prop: 'drawImage', onPropertyChange: false});
332
- parent.notify('draw', { prop: 'updateCurrTransState', onPropertyChange: false,
333
- value: {type: 'reverse', isPreventDestination: null, isRotatePan: null} });
334
- parent.notify('draw', { prop: 'setRotateZoom', onPropertyChange: false, value: {isRotateZoom: false }});
335
- if (parent.transform.degree === 0 && parent.rotateFlipColl.length > 0) {
336
- parent.img.destLeft += parent.panPoint.totalPannedPoint.x;
337
- parent.img.destTop += parent.panPoint.totalPannedPoint.y;
338
- }
339
- splitWords = this.setTempFilterValue(brightness, isPreview, splitWords, type);
340
- if (isNullOrUndefined(isPreview)) {this.lowerContext.filter = splitWords.join(' '); }
341
- parent.initialAdjustmentValue = splitWords.join(' ');
342
- tempFilter = this.lowerContext.filter;
343
- this.lowerContext.filter = 'brightness(' + 1 + ') ' + 'contrast(' + 100 + '%) ' + 'hue-rotate(' + 0 + 'deg) ' +
344
- 'saturate(' + 100 + '%) ' + 'opacity(' + 1 + ') ' + 'blur(' + 0 + 'px) ' + 'sepia(0%) ' + 'grayscale(0%) ' + 'invert(0%)';
345
- this.bevelFilter = tempFilter;
346
- parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
347
- value: {ctx: this.lowerContext, shape: 'iterate', pen: 'iterate', isPreventApply: null }});
348
- this.lowerContext.filter = tempFilter;
349
- parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.lowerContext}});
350
- if ((parent.currSelectionPoint && parent.currSelectionPoint.shape === 'crop-circle') || parent.isCircleCrop) {
351
- parent.notify('crop', { prop: 'cropCircle', onPropertyChange: false,
352
- value: {context: this.lowerContext, isSave: null, isFlip: null}});
353
- }
354
- this.isBrightnessAdjusted = brightness !== 1;
355
- }
356
- const filter: string = splitWords.join(' ');
357
- if (ctx) {
358
- ctx.filter = filter;
359
- }
360
- }
361
-
362
- private setTempFilterValue(brightness: number, isPreview: boolean, splitWords: string[], type: string): string[] {
363
- if (isPreview) {
364
- if (type === 'default') {
365
- splitWords = this.getDefaultCurrentFilter(splitWords);
366
- } else if (brightness !== 1) {
367
- const tempSplitWords: string[] = this.lowerContext.filter.split(' ');
368
- tempSplitWords[4] = splitWords[4];
369
- this.lowerContext.filter = tempSplitWords.join(' ');
370
- }
371
- }
372
- return splitWords;
373
- }
374
-
375
- private getDefaultCurrentFilter(splitWords: string[]): string[] {
376
- const values: string[] = this.adjustmentValue.split(' ');
377
- splitWords = [ values[0], values[1], values[2], values[3], values[4], values[5], 'sepia(0%)', 'grayscale(0%)', 'invert(0%)' ];
378
- return splitWords;
379
- }
380
-
381
- private getFilterValue(value: number): number {
382
- return (value === 0) ? 1 : 1 + ((value * 0.5) / 100);
383
- }
384
-
385
- private getSaturationFilterValue(value: number): number {
386
- return value === 0 ? 1 : 1 + (value / 100);
387
- }
388
-
389
- private setFilterAdj(type: string, value: number): void {
390
- const parent: ImageEditor = this.parent;
391
- parent.notify('freehand-draw', { prop: 'apply-pen-draw', onPropertyChange: false });
392
- this.adjustmentLevel[`${type}`] = value;
393
- switch (type) {
394
- case 'contrast':
395
- case 'exposure':
396
- value = this.getFilterValue(value);
397
- if (type === 'contrast') {value *= 100; }
398
- break;
399
- case 'hue':
400
- value *= 3;
401
- break;
402
- case 'saturation':
403
- value = this.getSaturationFilterValue(value) * 100;
404
- break;
405
- case 'opacity':
406
- if (value < 10) {
407
- value += 1;
408
- }
409
- value /= 100;
410
- break;
411
- case 'blur':
412
- if (value !== 0) {
413
- value /= 20;
414
- // Since 0.5 is not working in blur we consider from 1
415
- value += 0.5;
416
- }
417
- break;
418
- }
419
- const prevCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
420
- const prevObj: CurrentObject = this.getCurrentObj();
421
- prevObj.objColl = extend([], parent.objColl, [], true) as SelectionPoint[];
422
- prevObj.pointColl = extend([], parent.pointColl, [], true) as Point[];
423
- prevObj.afterCropActions = extend([], parent.afterCropActions, [], true) as string[];
424
- const selPointCollObj: Object = { selPointColl: null };
425
- parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false, value: { obj: selPointCollObj } });
426
- prevObj.selPointColl = extend([], selPointCollObj['selPointColl'], [], true) as Point[];
427
- this.updateAdj(type, value);
428
- parent.notify('undo-redo', { prop: 'updateUndoRedoColl', onPropertyChange: false, value: { operation: type, previousObj: prevObj,
429
- previousObjColl: prevObj.objColl, previousPointColl: prevObj.pointColl, previousSelPointColl: prevObj.selPointColl,
430
- previousCropObj: prevCropObj, previousText: null, currentText: null, previousFilter: null, isCircleCrop: null
431
- }});
432
- }
433
-
434
- private setFilter(type: string): void {
435
- const parent: ImageEditor = this.parent;
436
- type = type.toLowerCase();
437
- parent.notify('freehand-draw', { prop: 'apply-pen-draw', onPropertyChange: false});
438
- const obj: Object = {currentFilter: this.parent.currentFilter };
439
- const prevFilter: string = obj['currentFilter'];
440
- const prevCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
441
- const prevObj: CurrentObject = this.getCurrentObj();
442
- prevObj.objColl = extend([], parent.objColl, [], true) as SelectionPoint[];
443
- prevObj.pointColl = extend([], parent.pointColl, [], true) as Point[];
444
- prevObj.afterCropActions = extend([], parent.afterCropActions, [], true) as string[];
445
- const selPointCollObj: Object = {selPointColl: null };
446
- parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false, value: {obj: selPointCollObj }});
447
- prevObj.selPointColl = extend([], selPointCollObj['selPointColl'], [], true) as Point[];
448
- this.updateAdj(type, null);
449
- parent.notify('draw', { prop: 'setImageEdited', onPropertyChange: false });
450
- parent.notify('undo-redo', { prop: 'updateUndoRedoColl', onPropertyChange: false,
451
- value: {operation: type, previousObj: prevObj, previousObjColl: prevObj.objColl, previousPointColl: prevObj.pointColl,
452
- previousSelPointColl: prevObj.selPointColl, previousCropObj: prevCropObj, previousText: null,
453
- currentText: null, previousFilter: prevFilter, isCircleCrop: null}});
454
- }
455
-
456
- private setAdjustment(type: string): void {
457
- const splitWords: string[] = this.lowerContext.filter.split(' ');
458
- let value: number; let valueArr: string[];
459
- switch (type) {
460
- case 'brightness':
461
- valueArr = splitWords[0].split('(');
462
- value = parseFloat(valueArr[1].split(')')[0]);
463
- this.adjustmentLevel.brightness = this.setFilterValue(value);
464
- break;
465
- case 'contrast':
466
- valueArr = splitWords[1].split('(');
467
- value = parseFloat(valueArr[1].split(')')[0]);
468
- value /= 100;
469
- this.adjustmentLevel.contrast = this.setFilterValue(value);
470
- break;
471
- case 'hue':
472
- valueArr = splitWords[2].split('(');
473
- value = parseFloat(valueArr[1].split(')')[0]);
474
- value /= 3;
475
- this.adjustmentLevel.hue = value;
476
- break;
477
- case 'saturation':
478
- valueArr = splitWords[3].split('(');
479
- value = parseFloat(valueArr[1].split(')')[0]);
480
- value /= 100;
481
- this.adjustmentLevel.saturation = this.setSaturationFilterValue(value);
482
- break;
483
- case 'opacity':
484
- valueArr = splitWords[4].split('(');
485
- value = parseFloat(valueArr[1].split(')')[0]);
486
- if (value === 0.45) {value = 40; }
487
- else if (value === 0.40) {value = 30; }
488
- else if (value === 0.35) {value = 20; }
489
- else if (value === 0.30) {value = 10; }
490
- else if (value === 0.25) { value = 0; }
491
- else {value *= 100; }
492
- this.adjustmentLevel.opacity = value;
493
- break;
494
- case 'blur':
495
- valueArr = splitWords[5].split('(');
496
- value = parseFloat(valueArr[1].split(')')[0]);
497
- value *= 20;
498
- this.adjustmentLevel.blur = value;
499
- break;
500
- case 'exposure':
501
- valueArr = splitWords[0].split('(');
502
- value = parseFloat(valueArr[1].split(')')[0]);
503
- this.adjustmentLevel.exposure = this.setFilterValue(value);
504
- break;
505
- }
506
- }
507
-
508
- private setFilterValue(value: number): number {
509
- return Math.round((value === 1) ? 0 : ((value - 1) * 100) / 0.5);
510
- }
511
-
512
- private setSaturationFilterValue(value: number): number {
513
- return Math.round((value === 1) ? 0 : (value - 1) * 100);
514
- }
515
-
516
- private finetuneImage(finetuneOption: ImageFinetuneOption, value: number): void {
517
- const parent: ImageEditor = this.parent;
518
- if (!parent.disabled && parent.isImageLoaded) {
519
- switch (finetuneOption.toLowerCase()) {
520
- case 'brightness':
521
- this.setFilterAdj('brightness', value);
522
- break;
523
- case 'contrast':
524
- this.setFilterAdj('contrast', value);
525
- break;
526
- case 'hue':
527
- this.setFilterAdj('hue', value);
528
- break;
529
- case 'saturation':
530
- this.setFilterAdj('saturation', value);
531
- break;
532
- case 'opacity':
533
- this.setFilterAdj('opacity', value);
534
- break;
535
- case 'blur':
536
- this.setFilterAdj('blur', value);
537
- break;
538
- case 'exposure':
539
- this.setFilterAdj('exposure', value);
540
- break;
541
- }
542
- this.parent.canvasFilter = this.lowerContext.filter;
543
- parent.notify('undo-redo', {prop: 'updateCurrUrc', value: {type: 'ok' }});
544
- }
545
- }
546
-
547
- private setCurrAdjValue(type: string, value: number): void {
548
- const parent: ImageEditor = this.parent;
549
- this.parent.notify('draw', { prop: 'setImageEdited', onPropertyChange: false });
550
- switch (type) {
551
- case 'brightness':
552
- this.setFilterAdj('brightness', value);
553
- break;
554
- case 'contrast':
555
- this.setFilterAdj('contrast', value);
556
- break;
557
- case 'hue':
558
- this.setFilterAdj('hue', value);
559
- break;
560
- case 'saturation':
561
- this.setFilterAdj('saturation', value);
562
- break;
563
- case 'opacity':
564
- this.setFilterAdj('opacity', value);
565
- break;
566
- case 'blur':
567
- this.setFilterAdj('blur', value);
568
- break;
569
- case 'exposure':
570
- this.setFilterAdj('exposure', value);
571
- break;
572
- }
573
- parent.isFinetuneBtnClick = true;
574
- parent.curFinetuneObjEvent = { finetune: parent.toPascalCase(type) as ImageFinetuneOption, value: value };
575
- }
576
-
577
- private getCurrentObj(dummyObj?: Object): CurrentObject {
578
- const parent: ImageEditor = this.parent;
579
- const tempFlipPanPointObj: Object = {point: null };
580
- parent.notify('crop', {prop: 'getTempFlipPanPoint', value: {obj: tempFlipPanPointObj }});
581
- const zoomObj: Object = {previousZoomValue: null };
582
- parent.notify('transform', {prop: 'getPreviousZoomValue', value: {obj: zoomObj }});
583
- const straightenObj: Object = {zoomFactor: null };
584
- parent.notify('draw', {prop: 'getStraightenInitZoom', value: {obj: straightenObj }});
585
- const bgObj: Object = { color: null };
586
- parent.notify('draw', { prop: 'getImageBackgroundColor', value: {obj: bgObj }});
587
- const obj: CurrentObject = {cropZoom: 0, defaultZoom: 0, totalPannedPoint: {x: 0, y: 0}, totalPannedClientPoint: {x: 0, y: 0},
588
- totalPannedInternalPoint: {x: 0, y: 0}, tempFlipPanPoint: {x: 0, y: 0}, activeObj: {} as SelectionPoint,
589
- rotateFlipColl: [], degree: 0, currFlipState: '', zoomFactor: 0, previousZoomValue : 0, straighten: 0,
590
- destPoints: {startX: 0, startY: 0, width: 0, height: 0} as ActivePoint, frame: 'none',
591
- srcPoints: {startX: 0, startY: 0, width: 0, height: 0} as ActivePoint, filter : '', isBrightAdjust: this.isBrightnessAdjusted,
592
- aspectWidth: null, aspectHeight: null, straightenZoom: 0, adjustmentLevel: extend({}, this.tempAdjVal, {}, true) as Adjustment,
593
- currentFilter: this.tempFilVal, imageSource: '', bgColor: '' };
594
- obj.cropZoom = parent.transform.cropZoomFactor; obj.defaultZoom = parent.transform.defaultZoomFactor;
595
- obj.zoomFactor = parent.zoomSettings.zoomFactor; obj.previousZoomValue = zoomObj['previousZoomValue'];
596
- obj.straightenZoom = straightenObj['zoomFactor'];
597
- obj.totalPannedPoint = extend({}, parent.panPoint.totalPannedPoint, {}, true) as Point;
598
- obj.totalPannedClientPoint = extend({}, parent.panPoint.totalPannedClientPoint, {}, true) as Point;
599
- obj.totalPannedInternalPoint = extend({}, parent.panPoint.totalPannedInternalPoint, {}, true) as Point;
600
- obj.tempFlipPanPoint = extend({}, tempFlipPanPointObj['point'], {}, true) as Point;
601
- obj.activeObj = extend({}, parent.activeObj, {}, true) as SelectionPoint;
602
- obj.rotateFlipColl = extend([], parent.rotateFlipColl, [], true) as string[] | number[];
603
- obj.degree = parent.transform.degree; obj.straighten = parent.cropObj.straighten;
604
- obj.currFlipState = parent.transform.currFlipState;
605
- obj.destPoints = {startX: parent.img.destLeft, startY: parent.img.destTop, endX: 0, endY: 0,
606
- width: parent.img.destWidth, height: parent.img.destHeight};
607
- obj.srcPoints = {startX: parent.img.srcLeft, startY: parent.img.srcTop, endX: 0, endY: 0,
608
- width: parent.img.srcWidth, height: parent.img.srcHeight};
609
- obj.filter = this.lowerContext.filter; obj.aspectWidth = parent.aspectWidth; obj.aspectHeight = parent.aspectHeight;
610
- obj.frame = parent.frameObj.type;
611
- obj.frameObj = extend({}, parent.frameObj) as FrameValue;
612
- obj.imageSource = parent.baseImg.src;
613
- obj.bgColor = bgObj['color'];
614
- if (dummyObj) {dummyObj['currObj'] = obj; }
615
- return obj;
616
- }
617
-
618
- /* Filter safari related codes */
619
- private getValFromPercentage(percentage: string): number {
620
- let val: number = parseFloat(percentage);
621
- // check for percentages and divide by a hundred
622
- if (/%\s*?$/i.test(percentage)) {
623
- val /= 100;
624
- }
625
- return val;
626
- }
627
-
628
- private getValFromLength(length: string): number {
629
- return parseFloat(length);
630
- }
631
-
632
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
633
- private parseFilterString(filterString: string): any[] {
634
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
635
- let filterArray: any[] = [];
636
- if (filterString && filterString !== 'none') {
637
- filterArray = filterString.split(' ').map((filter: string) => {
638
- const [name, value] = filter.match(/([a-z-]+)\(([^)]+)\)/).slice(1, 3);
639
- return { filter: name, value: value };
640
- });
641
- }
642
- return filterArray;
643
- }
644
-
645
- private applyFilter(context: CanvasRenderingContext2D): void {
646
- const { height, width } = context.canvas;
647
- let imageData: ImageData = context.getImageData(0, 0, width, height);
648
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
649
- const filterArray: any[] = this.parseFilterString(context.filter);
650
- for (let i: number = 0, len: number = filterArray.length; i < len; i++) {
651
- switch (filterArray[i as number].filter) {
652
- case 'blur':
653
- imageData = this.blur(context, imageData, filterArray[i as number].value);
654
- break;
655
- case 'brightness':
656
- imageData = this.brightness(imageData, filterArray[i as number].value);
657
- break;
658
- case 'contrast':
659
- imageData = this.contrast(imageData, filterArray[i as number].value);
660
- break;
661
- case 'grayscale':
662
- imageData = this.grayscale(imageData, filterArray[i as number].value);
663
- break;
664
- case 'hue-rotate':
665
- imageData = this.hueRotate(imageData, filterArray[i as number].value);
666
- break;
667
- case 'invert':
668
- imageData = this.invert(imageData, filterArray[i as number].value);
669
- break;
670
- case 'opacity':
671
- imageData = this.opacity(imageData, filterArray[i as number].value);
672
- break;
673
- case 'saturate':
674
- imageData = this.saturate(context, imageData, filterArray[i as number].value);
675
- break;
676
- case 'sepia':
677
- imageData = this.sepia(imageData, filterArray[i as number].value);
678
- break;
679
- }
680
- }
681
- context.putImageData(imageData, 0, 0);
682
- }
683
-
684
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
685
- private blur(context: CanvasRenderingContext2D, imageData: ImageData, radius: any = '0'): ImageData {
686
- let blurRadius: number = this.getValFromLength(radius); blurRadius = Math.floor(blurRadius);
687
- if (blurRadius <= 0) {
688
- return imageData;
689
- }
690
- const { height, width } = context.canvas;
691
- const { data } = imageData;
692
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
693
- const blurredData: any = new Uint8ClampedArray(data.length);
694
- for (let y: number = 0; y < height; y++) {
695
- for (let x: number = 0; x < width; x++) {
696
- let r: number = 0; let g: number = 0; let b: number = 0; let a: number = 0; let count: number = 0;
697
- for (let dy: number = -blurRadius; dy <= blurRadius; dy++) {
698
- for (let dx: number = -blurRadius; dx <= blurRadius; dx++) {
699
- const nx: number = x + dx;
700
- const ny: number = y + dy;
701
- if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
702
- const offset: number = (ny * width + nx) * 4;
703
- r += data[offset as number];
704
- g += data[offset + 1];
705
- b += data[offset + 2];
706
- a += data[offset + 3];
707
- count++;
708
- }
709
- }
710
- }
711
- const i: number = (y * width + x) * 4;
712
- blurredData[i as number] = r / count;
713
- blurredData[i + 1] = g / count;
714
- blurredData[i + 2] = b / count;
715
- blurredData[i + 3] = a / count;
716
- }
717
- }
718
- for (let i: number = 0; i < data.length; i++) {
719
- data[i as number] = blurredData[i as number];
720
- }
721
- return imageData;
722
- }
723
-
724
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
725
- private brightness(imageData: ImageData, percentage: any = '1'): ImageData {
726
- const factor: number = this.getValFromPercentage(percentage);
727
- if (factor !== 1) {
728
- const { data } = imageData;
729
- const { length } = data;
730
- for (let i: number = 0; i < length; i += 4) {
731
- data[i + 0] *= factor; data[i + 1] *= factor; data[i + 2] *= factor;
732
- }
733
- }
734
- return imageData;
735
- }
736
-
737
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
738
- private contrast(imageData: ImageData, percentage: any = '1'): ImageData {
739
- const factor: number = this.getValFromPercentage(percentage);
740
- if (factor !== 1) {
741
- const { data } = imageData;
742
- const { length } = data;
743
- for (let i: number = 0; i < length; i += 4) {
744
- data[i + 0] = ((data[i + 0] / 255 - 0.5) * factor + 0.5) * 255;
745
- data[i + 1] = ((data[i + 1] / 255 - 0.5) * factor + 0.5) * 255;
746
- data[i + 2] = ((data[i + 2] / 255 - 0.5) * factor + 0.5) * 255;
747
- }
748
- }
749
- return imageData;
750
- }
751
-
752
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
753
- private grayscale(imageData: ImageData, percentage: any = '0'): ImageData {
754
- const factor: number = this.getValFromPercentage(percentage);
755
- if (factor > 0) {
756
- const { data } = imageData;
757
- const { length } = data;
758
- for (let i: number = 0; i < length; i += 4) {
759
- const r: number = data[i as number]; const g: number = data[i + 1]; const b: number = data[i + 2];
760
- // Calculate the grayscale value using the luminosity method
761
- const gray: number = 0.299 * r + 0.587 * g + 0.114 * b;
762
- // Blend the original color with the grayscale value based on the percentage
763
- data[i as number] = r * (1 - factor) + gray * factor;
764
- data[i + 1] = g * (1 - factor) + gray * factor;
765
- data[i + 2] = b * (1 - factor) + gray * factor;
766
- }
767
- }
768
- return imageData;
769
- }
770
-
771
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
772
- private hueRotate(imageData: ImageData, rotation: any = '0deg'): ImageData {
773
- const { data } = imageData;
774
- const angle: number = parseFloat(rotation) * (Math.PI / 180);
775
- if (angle > 0) {
776
- const cosA: number = Math.cos(angle);
777
- const sinA: number = Math.sin(angle);
778
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
779
- const matrix: any = [
780
- 0.213 + cosA * 0.787 - sinA * 0.213, 0.715 - cosA * 0.715 - sinA * 0.715, 0.072 - cosA * 0.072 + sinA * 0.928,
781
- 0.213 - cosA * 0.213 + sinA * 0.143, 0.715 + cosA * 0.285 + sinA * 0.140, 0.072 - cosA * 0.072 - sinA * 0.283,
782
- 0.213 - cosA * 0.213 - sinA * 0.787, 0.715 - cosA * 0.715 + sinA * 0.715, 0.072 + cosA * 0.928 + sinA * 0.072
783
- ];
784
- for (let i: number = 0; i < data.length; i += 4) {
785
- const r: number = data[i as number];
786
- const g: number = data[i + 1];
787
- const b: number = data[i + 2];
788
-
789
- // Apply the hue rotation matrix
790
- data[i as number] = matrix[0] * r + matrix[1] * g + matrix[2] * b;
791
- data[i + 1] = matrix[3] * r + matrix[4] * g + matrix[5] * b;
792
- data[i + 2] = matrix[6] * r + matrix[7] * g + matrix[8] * b;
793
- }
794
- }
795
- return imageData;
796
- }
797
-
798
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
799
- private invert(imageData: ImageData, percentage: any = '0'): ImageData {
800
- const factor: number = this.getValFromPercentage(percentage);
801
- if (factor > 0) {
802
- const { data } = imageData;
803
- const { length } = data;
804
- for (let i: number = 0; i < length; i += 4) {
805
- data[i + 0] = Math.abs(data[i + 0] - 255 * factor);
806
- data[i + 1] = Math.abs(data[i + 1] - 255 * factor);
807
- data[i + 2] = Math.abs(data[i + 2] - 255 * factor);
808
- }
809
- }
810
- return imageData;
811
- }
812
-
813
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
814
- private opacity(imageData: ImageData, percentage: any = '0'): ImageData {
815
- const factor: number = this.getValFromPercentage(percentage);
816
- if (factor >= 0) {
817
- const { data } = imageData;
818
- const { length } = data;
819
- for (let i: number = 3; i < length; i += 4) {
820
- data[i as number] *= factor;
821
- }
822
- }
823
- return imageData;
824
- }
825
-
826
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
827
- private saturate(context: CanvasRenderingContext2D, imageData: ImageData, percentage: any = '0'): ImageData {
828
- const factor: number = this.getValFromPercentage(percentage);
829
- if (factor !== 1) {
830
- const {width, height} = context.canvas;
831
- const { data } = imageData;
832
- const lumR: number = (1 - factor) * 0.3086; const lumG: number = (1 - factor) * 0.6094;
833
- const lumB: number = (1 - factor) * 0.082;
834
- // tslint:disable-next-line no-bitwise
835
- const shiftW: number = width << 2;
836
- for (let j: number = 0; j < height; j++) {
837
- const offset: number = j * shiftW;
838
- for (let i: number = 0; i < width; i++) {
839
- // tslint:disable-next-line no-bitwise
840
- const pos: number = offset + (i << 2);
841
- const r: number = data[pos + 0]; const g: number = data[pos + 1]; const b: number = data[pos + 2];
842
- data[pos + 0] = (lumR + factor) * r + lumG * g + lumB * b;
843
- data[pos + 1] = lumR * r + (lumG + factor) * g + lumB * b;
844
- data[pos + 2] = lumR * r + lumG * g + (lumB + factor) * b;
845
- }
846
- }
847
- }
848
- return imageData;
849
- }
850
-
851
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
852
- private sepia(imageData: ImageData, percentage: any = '0'): ImageData {
853
- let factor: number = this.getValFromPercentage(percentage);
854
- if (factor > 1) {
855
- factor = 1;
856
- }
857
- if (factor > 0) {
858
- const { data } = imageData;
859
- const { length } = data;
860
- for (let i: number = 0; i < length; i += 4) {
861
- const r: number = data[i + 0]; const g: number = data[i + 1]; const b: number = data[i + 2];
862
- data[i + 0] =
863
- (0.393 * r + 0.769 * g + 0.189 * b) * factor + r * (1 - factor);
864
- data[i + 1] =
865
- (0.349 * r + 0.686 * g + 0.168 * b) * factor + g * (1 - factor);
866
- data[i + 2] =
867
- (0.272 * r + 0.534 * g + 0.131 * b) * factor + b * (1 - factor);
868
- }
869
- }
870
- return imageData;
871
- }
872
- }