@syncfusion/ej2-image-editor 30.2.4 → 31.1.17
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.
- package/dist/ej2-image-editor.umd.min.js +2 -2
- package/dist/ej2-image-editor.umd.min.js.map +1 -1
- package/dist/es6/ej2-image-editor.es2015.js +3 -3
- package/dist/es6/ej2-image-editor.es2015.js.map +1 -1
- package/dist/es6/ej2-image-editor.es5.js +3 -3
- package/dist/es6/ej2-image-editor.es5.js.map +1 -1
- package/dist/global/ej2-image-editor.min.js +2 -2
- package/dist/global/ej2-image-editor.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/dist/ts/image-editor/action/crop.d.ts +44 -0
- package/dist/ts/image-editor/action/crop.ts +867 -0
- package/dist/ts/image-editor/action/draw.d.ts +187 -0
- package/dist/ts/image-editor/action/draw.ts +4924 -0
- package/dist/ts/image-editor/action/export.d.ts +29 -0
- package/dist/ts/image-editor/action/export.ts +509 -0
- package/dist/ts/image-editor/action/filter.d.ts +48 -0
- package/dist/ts/image-editor/action/filter.ts +872 -0
- package/dist/ts/image-editor/action/freehand-draw.d.ts +68 -0
- package/dist/ts/image-editor/action/freehand-draw.ts +1135 -0
- package/dist/ts/image-editor/action/index.d.ts +9 -0
- package/dist/ts/image-editor/action/index.ts +9 -0
- package/dist/ts/image-editor/action/selection.d.ts +178 -0
- package/dist/ts/image-editor/action/selection.ts +5241 -0
- package/dist/ts/image-editor/action/shape.d.ts +130 -0
- package/dist/ts/image-editor/action/shape.ts +3917 -0
- package/dist/ts/image-editor/action/transform.d.ts +77 -0
- package/dist/ts/image-editor/action/transform.ts +2008 -0
- package/dist/ts/image-editor/action/undo-redo.d.ts +52 -0
- package/dist/ts/image-editor/action/undo-redo.ts +1169 -0
- package/dist/ts/image-editor/base/enum.d.ts +277 -0
- package/dist/ts/image-editor/base/enum.ts +288 -0
- package/dist/ts/image-editor/base/image-editor-model.d.ts +770 -0
- package/dist/ts/image-editor/base/image-editor.d.ts +1928 -0
- package/dist/ts/image-editor/base/image-editor.ts +5496 -0
- package/dist/ts/image-editor/base/index.d.ts +4 -0
- package/dist/ts/image-editor/base/index.ts +4 -0
- package/dist/ts/image-editor/base/interface.d.ts +1637 -0
- package/dist/ts/image-editor/base/interface.ts +1709 -0
- package/dist/ts/image-editor/index.d.ts +3 -0
- package/dist/ts/image-editor/index.ts +3 -0
- package/dist/ts/image-editor/renderer/index.d.ts +1 -0
- package/dist/ts/image-editor/renderer/index.ts +1 -0
- package/dist/ts/image-editor/renderer/toolbar.d.ts +171 -0
- package/dist/ts/image-editor/renderer/toolbar.ts +6356 -0
- package/dist/ts/index.d.ts +4 -0
- package/dist/ts/index.ts +4 -0
- package/package.json +47 -15
- package/src/image-editor/action/undo-redo.js +3 -3
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ImageEditor } from '../index';
|
|
2
|
+
export declare class Export {
|
|
3
|
+
private parent;
|
|
4
|
+
private lowerContext;
|
|
5
|
+
private imageQuality;
|
|
6
|
+
constructor(parent: ImageEditor);
|
|
7
|
+
destroy(): void;
|
|
8
|
+
private addEventListener;
|
|
9
|
+
private removeEventListener;
|
|
10
|
+
private export;
|
|
11
|
+
getModuleName(): string;
|
|
12
|
+
private updatePvtVar;
|
|
13
|
+
private exportImg;
|
|
14
|
+
private beforeSaveEvent;
|
|
15
|
+
private toSVGImg;
|
|
16
|
+
private toBlobFn;
|
|
17
|
+
private exportToCanvas;
|
|
18
|
+
private drawAnnotation;
|
|
19
|
+
private drawShape;
|
|
20
|
+
private drawPen;
|
|
21
|
+
private downScaleImgCanvas;
|
|
22
|
+
private updateFrame;
|
|
23
|
+
private downloadImg;
|
|
24
|
+
private exportTransformedImage;
|
|
25
|
+
private exportRotate;
|
|
26
|
+
private exportFlip;
|
|
27
|
+
private updateSaveContext;
|
|
28
|
+
private setMaxDim;
|
|
29
|
+
}
|
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
2
|
+
import { extend, isNullOrUndefined } from '@syncfusion/ej2-base';
|
|
3
|
+
import { Dimension } from '@syncfusion/ej2-inputs';
|
|
4
|
+
import { hideSpinner, showSpinner } from '@syncfusion/ej2-popups';
|
|
5
|
+
import { BeforeSaveEventArgs, FileType, ImageEditor, Point, SaveEventArgs, SelectionPoint, ActivePoint, CurrentObject, EditCompleteEventArgs } from '../index';
|
|
6
|
+
|
|
7
|
+
export class Export {
|
|
8
|
+
private parent: ImageEditor;
|
|
9
|
+
private lowerContext: CanvasRenderingContext2D;
|
|
10
|
+
private imageQuality: number;
|
|
11
|
+
|
|
12
|
+
constructor(parent: ImageEditor) {
|
|
13
|
+
this.parent = parent;
|
|
14
|
+
this.addEventListener();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public destroy(): void {
|
|
18
|
+
if (this.parent.isDestroyed) { return; }
|
|
19
|
+
this.removeEventListener();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private addEventListener(): void {
|
|
23
|
+
this.parent.on('export', this.export, this);
|
|
24
|
+
this.parent.on('destroyed', this.destroy, this);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private removeEventListener(): void {
|
|
28
|
+
this.parent.off('export', this.export);
|
|
29
|
+
this.parent.off('destroyed', this.destroy);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private export(args?: { onPropertyChange: boolean, prop: string, value?: object }): void {
|
|
33
|
+
this.parent.notify('toolbar', { prop: 'refreshShapeDrawing', onPropertyChange: false });
|
|
34
|
+
this.updatePvtVar();
|
|
35
|
+
switch (args.prop) {
|
|
36
|
+
case 'export':
|
|
37
|
+
this.exportImg(args.value['type'], args.value['fileName'], args.value['imgQuality']);
|
|
38
|
+
break;
|
|
39
|
+
case 'exportToCanvas':
|
|
40
|
+
this.exportToCanvas(args.value['object']);
|
|
41
|
+
break;
|
|
42
|
+
case 'updateSaveContext':
|
|
43
|
+
this.updateSaveContext(args.value['context']);
|
|
44
|
+
break;
|
|
45
|
+
case 'setImageQuality':
|
|
46
|
+
this.imageQuality = args.value['value'];
|
|
47
|
+
break;
|
|
48
|
+
case 'drawAnnotation':
|
|
49
|
+
this.drawAnnotation(args.value['context'], args.value['ratio']);
|
|
50
|
+
break;
|
|
51
|
+
case 'downScaleImgCanvas':
|
|
52
|
+
this.downScaleImgCanvas(args.value['canvas'], args.value['width'], args.value['height']);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public getModuleName(): string {
|
|
58
|
+
return 'export';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private updatePvtVar(): void {
|
|
62
|
+
const parent: ImageEditor = this.parent;
|
|
63
|
+
if (parent.lowerCanvas) {
|
|
64
|
+
this.lowerContext = parent.lowerCanvas.getContext('2d');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private exportImg(type?: string, fileName?: string, imgQuality?: number): void {
|
|
69
|
+
const parent: ImageEditor = this.parent;
|
|
70
|
+
const obj: Object = { fileName: '' };
|
|
71
|
+
parent.notify('draw', { prop: 'getFileName', onPropertyChange: false, value: {obj: obj }});
|
|
72
|
+
const imageName: string = obj['fileName'];
|
|
73
|
+
if (!parent.disabled && parent.isImageLoaded) {
|
|
74
|
+
parent.notify('shape', { prop: 'applyActObj', onPropertyChange: false, value: {isMouseDown: null}});
|
|
75
|
+
const obj: Object = {canvasFilter: this.parent.canvasFilter };
|
|
76
|
+
this.lowerContext.filter = obj['canvasFilter'];
|
|
77
|
+
type = type ? type : 'Png';
|
|
78
|
+
parent.notify('shape', { prop: 'redrawActObj', onPropertyChange: false,
|
|
79
|
+
value: {x: null, y: null, isMouseDown: null}});
|
|
80
|
+
const beforeSave: BeforeSaveEventArgs = { cancel: false, fileName: fileName ? fileName : imageName,
|
|
81
|
+
fileType: type as FileType, imageQuality: imgQuality};
|
|
82
|
+
parent.trigger('beforeSave', beforeSave);
|
|
83
|
+
this.beforeSaveEvent(beforeSave, type, fileName, imageName, imgQuality);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private beforeSaveEvent(observableSaveArgs: BeforeSaveEventArgs, type: string, fileName: string, imageName: string, imgQuality?: number): void {
|
|
88
|
+
const parent: ImageEditor = this.parent;
|
|
89
|
+
if (!observableSaveArgs.cancel) {
|
|
90
|
+
parent.currObjType.isSave = true;
|
|
91
|
+
fileName = observableSaveArgs.fileName ? observableSaveArgs.fileName : fileName;
|
|
92
|
+
const lowerCaseType: string = type.toLowerCase();
|
|
93
|
+
fileName = fileName || imageName;
|
|
94
|
+
if (lowerCaseType === 'svg') {
|
|
95
|
+
this.toSVGImg(fileName);
|
|
96
|
+
} else {
|
|
97
|
+
this.toBlobFn(fileName, lowerCaseType, imgQuality);
|
|
98
|
+
}
|
|
99
|
+
const saved: SaveEventArgs = { fileName: fileName ? fileName : imageName, fileType: type as FileType};
|
|
100
|
+
parent.trigger('saved', saved);
|
|
101
|
+
const actionArgs: EditCompleteEventArgs = { action: 'save', actionEventArgs: saved };
|
|
102
|
+
parent.triggerEditCompleteEvent(actionArgs);
|
|
103
|
+
parent.notify('toolbar', { prop: 'refresh-main-toolbar', onPropertyChange: false});
|
|
104
|
+
parent.lowerCanvas.style.left = parent.upperCanvas.style.left = '';
|
|
105
|
+
parent.lowerCanvas.style.top = parent.upperCanvas.style.top = '';
|
|
106
|
+
parent.lowerCanvas.style.maxWidth = parent.upperCanvas.style.maxWidth = '';
|
|
107
|
+
parent.lowerCanvas.style.maxHeight = parent.upperCanvas.style.maxHeight = '';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private toSVGImg(fileName?: string): string {
|
|
112
|
+
const parent: ImageEditor = this.parent;
|
|
113
|
+
showSpinner(parent.element);
|
|
114
|
+
parent.element.style.opacity = '0.5';
|
|
115
|
+
const tempCanvas: HTMLCanvasElement = this.exportToCanvas();
|
|
116
|
+
const dataUrl: string = tempCanvas.toDataURL();
|
|
117
|
+
hideSpinner(parent.element);
|
|
118
|
+
parent.element.style.opacity = '1';
|
|
119
|
+
const svg: SVGSVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
120
|
+
svg.setAttribute('width', tempCanvas.style.maxWidth); svg.setAttribute('height', tempCanvas.style.maxHeight);
|
|
121
|
+
const XLinkNS: string = 'http://www.w3.org/1999/xlink';
|
|
122
|
+
const img: SVGImageElement = document.createElementNS('http://www.w3.org/2000/svg', 'image');
|
|
123
|
+
img.setAttributeNS(null, 'height', tempCanvas.height.toString());
|
|
124
|
+
img.setAttributeNS(null, 'width', tempCanvas.width.toString());
|
|
125
|
+
img.setAttributeNS(XLinkNS, 'xlink:href', dataUrl); svg.appendChild(img);
|
|
126
|
+
const prefix: string = 'data:image/svg+xml;base64,';
|
|
127
|
+
const header: string = '<svg' + ' xmlns="http://www.w3.org/2000/svg"' + ' xmlns:xlink="http://www.w3.org/1999/xlink"'
|
|
128
|
+
+ ` width="${tempCanvas.width}"` + ` height="${tempCanvas.height}"` + '>';
|
|
129
|
+
const footer: string = '</svg>'; const body: string = svg.innerHTML;
|
|
130
|
+
const data: string = header + body + footer; const svgDataUrl: string = prefix + btoa(data);
|
|
131
|
+
if (fileName === null) {return svgDataUrl; }
|
|
132
|
+
else {
|
|
133
|
+
this.downloadImg(svgDataUrl, fileName + '.' + 'svg');
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private toBlobFn(fileName: string, type: string, imgQuality?: number): void {
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
140
|
+
const proxy: this = this;
|
|
141
|
+
const parent: ImageEditor = this.parent;
|
|
142
|
+
showSpinner(parent.element);
|
|
143
|
+
parent.element.style.opacity = '0.5';
|
|
144
|
+
if (!isNullOrUndefined(imgQuality)) {
|
|
145
|
+
imgQuality = imgQuality > 1 ? 1 : (imgQuality <= 0 ? 0.01 : imgQuality);
|
|
146
|
+
this.imageQuality = imgQuality ? imgQuality : null;
|
|
147
|
+
}
|
|
148
|
+
const tempCanvas: HTMLCanvasElement = this.exportToCanvas();
|
|
149
|
+
const imagetype: string = (type === 'jpeg' ? 'image/jpeg' : (type === 'webp' ? 'image/webp' : 'image/png'));
|
|
150
|
+
// eslint-disable-next-line @typescript-eslint/tslint/config
|
|
151
|
+
tempCanvas.toBlob(function(blob){
|
|
152
|
+
const blobUrl: string = URL.createObjectURL(blob);
|
|
153
|
+
proxy.downloadImg(blobUrl, fileName + '.' + type);
|
|
154
|
+
hideSpinner(parent.element);
|
|
155
|
+
parent.element.style.opacity = '1';
|
|
156
|
+
}, imagetype, this.imageQuality ? this.imageQuality : null);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private exportToCanvas(object?: Object): HTMLCanvasElement {
|
|
160
|
+
const parent: ImageEditor = this.parent;
|
|
161
|
+
let width: number; let height: number;
|
|
162
|
+
const tempCropObj: CurrentObject = extend({}, parent.cropObj, {}, true) as CurrentObject;
|
|
163
|
+
const tempObj: Object = {currObj: {} as CurrentObject };
|
|
164
|
+
parent.notify('filter', { prop: 'getCurrentObj', onPropertyChange: false, value: {object: tempObj }});
|
|
165
|
+
const prevObj: CurrentObject = tempObj['currObj'];
|
|
166
|
+
prevObj.objColl = extend([], parent.objColl, [], true) as SelectionPoint[];
|
|
167
|
+
prevObj.pointColl = extend([], parent.pointColl, [], true) as Point[];
|
|
168
|
+
prevObj.afterCropActions = extend([], parent.afterCropActions, [], true) as string[];
|
|
169
|
+
const selPointCollObj: Object = {selPointColl: null };
|
|
170
|
+
parent.notify('freehand-draw', { prop: 'getSelPointColl', onPropertyChange: false,
|
|
171
|
+
value: {obj: selPointCollObj }});
|
|
172
|
+
if (this.parent.aspectWidth) {
|
|
173
|
+
parent.notify('undo-redo', { prop: 'setPreventUR', value: { bool: true } });
|
|
174
|
+
parent.notify('toolbar', { prop: 'resizeClick', value: {bool: false }});
|
|
175
|
+
parent.okBtn();
|
|
176
|
+
if (parent.transform.degree % 90 === 0 && parent.transform.degree % 180 !== 0) {
|
|
177
|
+
width = this.parent.aspectHeight; height = this.parent.aspectWidth;
|
|
178
|
+
} else {
|
|
179
|
+
width = this.parent.aspectWidth; height = this.parent.aspectHeight;
|
|
180
|
+
}
|
|
181
|
+
parent.notify('undo-redo', { prop: 'setPreventUR', value: { bool: false } });
|
|
182
|
+
}
|
|
183
|
+
else if (parent.currSelectionPoint) { width = parent.img.srcWidth; height = parent.img.srcHeight; }
|
|
184
|
+
else {width = parent.baseImgCanvas.width; height = parent.baseImgCanvas.height; }
|
|
185
|
+
const obj: Object = {width: 0, height: 0 };
|
|
186
|
+
parent.notify('crop', { prop: 'calcRatio', onPropertyChange: false,
|
|
187
|
+
value: {obj: obj, dimension: {width: width, height: height }}});
|
|
188
|
+
const ratio: Dimension = obj as Dimension;
|
|
189
|
+
const tempContextFilter: string = this.lowerContext.filter;
|
|
190
|
+
// Manipulating blur value
|
|
191
|
+
if (this.lowerContext.filter !== 'none') {
|
|
192
|
+
const splitWords: string[] = this.lowerContext.filter.split(' ');
|
|
193
|
+
let value: number = parseFloat(splitWords[5].split('(')[1]);
|
|
194
|
+
value *= ((ratio.width + ratio.height) / 2);
|
|
195
|
+
splitWords[5] = 'blur(' + value + 'px)';
|
|
196
|
+
this.lowerContext.filter = splitWords.join(' ');
|
|
197
|
+
}
|
|
198
|
+
const tempCanvas: HTMLCanvasElement = parent.createElement('canvas', {
|
|
199
|
+
id: parent.element.id + '_tempCanvas', attrs: { name: 'canvasImage' }
|
|
200
|
+
});
|
|
201
|
+
const tempContext: CanvasRenderingContext2D = tempCanvas.getContext('2d');
|
|
202
|
+
tempCanvas.width = width; tempCanvas.height = height;
|
|
203
|
+
const dimObj: Object = {width: 0, height: 0 };
|
|
204
|
+
parent.notify('transform', { prop: 'calcMaxDimension', onPropertyChange: false,
|
|
205
|
+
value: {width: width, height: height, obj: dimObj}});
|
|
206
|
+
const maxDimension: Dimension = dimObj as Dimension;
|
|
207
|
+
tempCanvas.style.maxWidth = maxDimension.width + 'px'; tempCanvas.style.maxHeight = maxDimension.height + 'px';
|
|
208
|
+
const temp: string = this.lowerContext.filter;
|
|
209
|
+
tempContext.filter = this.lowerContext.filter;
|
|
210
|
+
this.downScaleImgCanvas(tempContext, width, height);
|
|
211
|
+
this.lowerContext.filter = temp;
|
|
212
|
+
if (parent.transform.degree !== 0 || parent.transform.currFlipState !== '' || parent.transform.straighten !== 0) {
|
|
213
|
+
this.updateSaveContext(tempContext);
|
|
214
|
+
this.exportTransformedImage(tempContext);
|
|
215
|
+
}
|
|
216
|
+
if (parent.isSafari) {
|
|
217
|
+
parent.notify('filter', { prop: 'apply-filter', onPropertyChange: false, value: {context: tempContext}});
|
|
218
|
+
}
|
|
219
|
+
this.drawAnnotation(tempContext, ratio);
|
|
220
|
+
if (parent.isCircleCrop) {
|
|
221
|
+
parent.notify('crop', { prop: 'cropCircle', onPropertyChange: false,
|
|
222
|
+
value: {context: tempContext, isSave: true, isFlip: null}});
|
|
223
|
+
}
|
|
224
|
+
this.updateFrame(tempContext, true);
|
|
225
|
+
this.lowerContext.filter = tempContextFilter; parent.canvasFilter = tempContextFilter;
|
|
226
|
+
if (object) { object['canvas'] = tempCanvas; }
|
|
227
|
+
if (parent.aspectWidth) {
|
|
228
|
+
parent.objColl = []; parent.pointColl = []; parent.freehandCounter = 0;
|
|
229
|
+
parent.notify('freehand-draw', { prop: 'setSelPointColl', onPropertyChange: false,
|
|
230
|
+
value: {obj: {selPointColl: [] }}});
|
|
231
|
+
parent.notify('draw', { prop: 'setCurrentObj', onPropertyChange: false, value: {obj: prevObj }});
|
|
232
|
+
prevObj.selPointColl = extend([], selPointCollObj['selPointColl'], [], true) as Point[];
|
|
233
|
+
parent.notify('freehand-draw', { prop: 'setSelPointColl', onPropertyChange: false,
|
|
234
|
+
value: {obj: {selPointColl: prevObj.selPointColl }}});
|
|
235
|
+
parent.cropObj = tempCropObj;
|
|
236
|
+
parent.objColl = extend([], prevObj.objColl, [], true) as SelectionPoint[];
|
|
237
|
+
parent.pointColl = extend([], prevObj.pointColl, [], true) as Point[];
|
|
238
|
+
parent.freehandCounter = parent.pointColl.length;
|
|
239
|
+
parent.transform.straighten = 0;
|
|
240
|
+
this.lowerContext.filter = 'none';
|
|
241
|
+
parent.notify('shape', { prop: 'drawAnnotations', onPropertyChange: false,
|
|
242
|
+
value: {ctx: this.lowerContext, shape: 'zoom', pen: 'zoom', isPreventApply: null }});
|
|
243
|
+
this.lowerContext.filter = prevObj.filter;
|
|
244
|
+
parent.notify('draw', { prop: 'clearOuterCanvas', onPropertyChange: false, value: {context: this.lowerContext}});
|
|
245
|
+
if (parent.isCircleCrop || (parent.currSelectionPoint && parent.currSelectionPoint.shape === 'crop-circle')) {
|
|
246
|
+
parent.notify('crop', { prop: 'cropCircle', onPropertyChange: false,
|
|
247
|
+
value: {context: this.lowerContext, isSave: null, isFlip: null}});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return tempCanvas;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private drawAnnotation(tempContext: CanvasRenderingContext2D, ratio: Dimension): void {
|
|
254
|
+
const parent: ImageEditor = this.parent;
|
|
255
|
+
const tempObjColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
|
|
256
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
257
|
+
const tempPointColl: any = extend([], parent.pointColl, [], true);
|
|
258
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
259
|
+
const nonRedact: any = parent.shapeColl.filter((item: SelectionPoint) => item.shape !== 'redact');
|
|
260
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
261
|
+
const redact: any = parent.shapeColl.filter((item: SelectionPoint) => item.shape === 'redact');
|
|
262
|
+
parent.shapeColl = redact.concat(nonRedact);
|
|
263
|
+
for (let i: number = 0; i < parent.shapeColl.length; i++) {
|
|
264
|
+
if (parent.shapeColl[i as number].order) {
|
|
265
|
+
if (parent.shapeColl[i as number].currIndex && parent.shapeColl[i as number].currIndex.indexOf('shape') > -1) {
|
|
266
|
+
parent.objColl = [];
|
|
267
|
+
parent.objColl.push(extend({}, parent.shapeColl[i as number], {}, true) as SelectionPoint);
|
|
268
|
+
this.drawShape(tempContext, ratio);
|
|
269
|
+
} else if (parent.shapeColl[i as number].id && parent.shapeColl[i as number].id.indexOf('pen') > -1) {
|
|
270
|
+
parent.pointColl = []; parent.freehandCounter = 0;
|
|
271
|
+
parent.pointColl.push(extend({}, parent.shapeColl[i as number], {}, true));
|
|
272
|
+
parent.freehandCounter = parent.pointColl.length;
|
|
273
|
+
this.drawPen(tempContext, ratio);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
parent.objColl = tempObjColl; parent.pointColl = tempPointColl; parent.freehandCounter = parent.pointColl.length;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private drawShape(tempContext: CanvasRenderingContext2D, ratio: Dimension): void {
|
|
281
|
+
const parent: ImageEditor = this.parent;
|
|
282
|
+
if (parent.objColl.length > 0) {
|
|
283
|
+
const temp: string = tempContext.filter;
|
|
284
|
+
tempContext.filter = 'none';
|
|
285
|
+
const indexObj: Object = {index: null };
|
|
286
|
+
parent.notify('shape', { prop: 'getSmallestIndex', onPropertyChange: false, value: {obj: indexObj }});
|
|
287
|
+
let index: number = indexObj['index'];
|
|
288
|
+
const objColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
|
|
289
|
+
const tempObjColl: SelectionPoint[] = extend([], parent.objColl, [], true) as SelectionPoint[];
|
|
290
|
+
while (objColl.length > 0) {
|
|
291
|
+
let found: boolean = false;
|
|
292
|
+
for (let i: number = 0; i < objColl.length; i++) {
|
|
293
|
+
const currentObj: SelectionPoint = objColl[i as number];
|
|
294
|
+
if (isNullOrUndefined(currentObj.order)) {
|
|
295
|
+
objColl.splice(i, 1);
|
|
296
|
+
i--;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (currentObj.order === index) {
|
|
300
|
+
const temp: string = tempContext.filter;
|
|
301
|
+
tempContext.filter = 'none';
|
|
302
|
+
const currObj: SelectionPoint = objColl[i as number];
|
|
303
|
+
const activePoint: ActivePoint = currObj.activePoint;
|
|
304
|
+
// Subtracting destination left and top points
|
|
305
|
+
activePoint.startX -= parent.img.destLeft;
|
|
306
|
+
activePoint.startY -= parent.img.destTop;
|
|
307
|
+
activePoint.endX -= parent.img.destLeft;
|
|
308
|
+
activePoint.endY -= parent.img.destTop;
|
|
309
|
+
activePoint.width = activePoint.endX - activePoint.startX;
|
|
310
|
+
activePoint.height = activePoint.endY - activePoint.startY;
|
|
311
|
+
// Manipulating points
|
|
312
|
+
activePoint.startX *= ratio.width;
|
|
313
|
+
activePoint.startY *= ratio.height;
|
|
314
|
+
activePoint.endX *= ratio.width;
|
|
315
|
+
activePoint.endY *= ratio.height;
|
|
316
|
+
activePoint.width = activePoint.endX - activePoint.startX;
|
|
317
|
+
activePoint.height = activePoint.endY - activePoint.startY;
|
|
318
|
+
currObj.strokeSettings.strokeWidth *= ((ratio.width + ratio.height) / 2);
|
|
319
|
+
if (currObj.shape === 'text') {
|
|
320
|
+
currObj.textSettings.fontSize *= ((ratio.width + ratio.height) / 2);
|
|
321
|
+
} else if (currObj.shape === 'path') {
|
|
322
|
+
for (let l: number = 0; l < currObj.pointColl.length; l++) {
|
|
323
|
+
currObj.pointColl[l as number].x =
|
|
324
|
+
(currObj.pointColl[l as number].x - parent.img.destLeft) * ratio.width;
|
|
325
|
+
currObj.pointColl[l as number].y =
|
|
326
|
+
(currObj.pointColl[l as number].y - parent.img.destTop) * ratio.height;
|
|
327
|
+
}
|
|
328
|
+
} else if (currObj.shape === 'image') {
|
|
329
|
+
parent.activeObj = extend({}, objColl[i as number], {}, true) as SelectionPoint;
|
|
330
|
+
parent.notify('selection', { prop: 'upgradeImageQuality', onPropertyChange: false});
|
|
331
|
+
objColl[i as number] = extend({}, parent.activeObj, {}, true) as SelectionPoint;
|
|
332
|
+
}
|
|
333
|
+
parent.notify('draw', { prop: 'drawObject', onPropertyChange: false, value: {canvas: 'saveContext', obj: objColl[i as number], isCropRatio: null,
|
|
334
|
+
points: null, isPreventDrag: true, saveContext: tempContext, isPreventSelection: null} });
|
|
335
|
+
tempContext.filter = temp;
|
|
336
|
+
parent.notify('shape', { prop: 'refreshActiveObj', onPropertyChange: false});
|
|
337
|
+
index++;
|
|
338
|
+
const indexBool: Object = {bool: false };
|
|
339
|
+
parent.notify('shape', { prop: 'isIndexInObjColl', onPropertyChange: false, value: {obj: indexBool, index: index }});
|
|
340
|
+
if (!indexBool['bool']) {index++; }
|
|
341
|
+
objColl.splice(i, 1);
|
|
342
|
+
found = true;
|
|
343
|
+
break; // Exit the loop to start from the beginning
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (!found) {
|
|
347
|
+
break; // If no matching order was found, exit the loop
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
tempContext.filter = temp;
|
|
351
|
+
parent.notify('shape', { prop: 'refreshActiveObj', onPropertyChange: false});
|
|
352
|
+
parent.objColl = tempObjColl;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
private drawPen(tempContext: CanvasRenderingContext2D, ratio: Dimension): void {
|
|
357
|
+
const parent: ImageEditor = this.parent;
|
|
358
|
+
if (parent.freehandCounter > 0) {
|
|
359
|
+
const widthObj: Object = {penStrokeWidth: null };
|
|
360
|
+
parent.notify('freehand-draw', {prop: 'getPenStrokeWidth', onPropertyChange: false, value: {obj: widthObj }});
|
|
361
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
362
|
+
const tempPointColl: any = extend({}, parent.pointColl, {}, true);
|
|
363
|
+
for (let n: number = 0; n < parent.freehandCounter; n++) {
|
|
364
|
+
parent.points = extend([], parent.pointColl[n as number].points, []) as Point[];
|
|
365
|
+
parent.notify('freehand-draw', { prop: 'setPointCounter', onPropertyChange: false, value: {value: 0 }});
|
|
366
|
+
const len: number = parent.points.length;
|
|
367
|
+
parent.pointColl[n as number].strokeWidth *= ((ratio.width + ratio.height) / 2);
|
|
368
|
+
for (let l: number = 0; l < len; l++) {
|
|
369
|
+
parent.points[l as number].x = (parent.points[l as number].x - parent.img.destLeft) * ratio.width;
|
|
370
|
+
parent.points[l as number].y = (parent.points[l as number].y - parent.img.destTop) * ratio.height;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
parent.notify('freehand-draw', { prop: 'freehandRedraw', onPropertyChange: false,
|
|
374
|
+
value: {context: tempContext, points: null} });
|
|
375
|
+
parent.pointColl = tempPointColl;
|
|
376
|
+
parent.notify('freehand-draw', {prop: 'setPenStrokeWidth', onPropertyChange: false, value: {value: widthObj['penStrokeWidth'] }});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private downScaleImgCanvas(ctx: CanvasRenderingContext2D, width: number, height: number): void {
|
|
381
|
+
const parent: ImageEditor = this.parent;
|
|
382
|
+
const canvas: HTMLCanvasElement = parent.baseImgCanvas;
|
|
383
|
+
const img: HTMLImageElement = parent.baseImg;
|
|
384
|
+
const obj: Object = {width: 0, height: 0 };
|
|
385
|
+
parent.notify('transform', { prop: 'calcMaxDimension', onPropertyChange: false,
|
|
386
|
+
value: {width: img.width, height: img.height, obj: obj, isImgShape: null }});
|
|
387
|
+
const bgObj: Object = { color: null };
|
|
388
|
+
parent.notify('draw', { prop: 'getImageBackgroundColor', value: {obj: bgObj }});
|
|
389
|
+
if (bgObj['color'] !== '') {
|
|
390
|
+
ctx.fillStyle = bgObj['color'];
|
|
391
|
+
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
392
|
+
}
|
|
393
|
+
if (obj['width'] > width && obj['height'] > height) {
|
|
394
|
+
const tempCanvas: HTMLCanvasElement = parent.createElement('canvas', {
|
|
395
|
+
id: parent.element.id + '_downScaleCanvas', attrs: { name: 'canvasImage' }
|
|
396
|
+
});
|
|
397
|
+
tempCanvas.width = this.parent.img.srcWidth; tempCanvas.height = this.parent.img.srcHeight;
|
|
398
|
+
tempCanvas.getContext('2d').drawImage(canvas, parent.img.srcLeft, parent.img.srcTop, parent.img.srcWidth,
|
|
399
|
+
parent.img.srcHeight, 0, 0, tempCanvas.width, tempCanvas.height);
|
|
400
|
+
parent.notify('draw', {prop: 'downScale', value: {canvas: tempCanvas, width: width, height: height }});
|
|
401
|
+
ctx.drawImage(tempCanvas, 0, 0);
|
|
402
|
+
} else {
|
|
403
|
+
ctx.drawImage(parent.baseImgCanvas, parent.img.srcLeft, parent.img.srcTop, parent.img.srcWidth,
|
|
404
|
+
parent.img.srcHeight, 0, 0, width, height);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
private updateFrame(tempContext: CanvasRenderingContext2D, isAnnotation?: boolean): void {
|
|
409
|
+
if (this.parent.frameObj.type !== 'none') {
|
|
410
|
+
const temp: string = tempContext.filter;
|
|
411
|
+
tempContext.filter = 'none';
|
|
412
|
+
this.parent.notify('draw', {prop: 'applyFrame', value: {ctx: tempContext, frame: this.parent.frameObj.type, preventImg: isAnnotation }});
|
|
413
|
+
tempContext.filter = temp;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
private downloadImg(blob: string, fileName: string): void {
|
|
418
|
+
const a: HTMLAnchorElement = document.createElement('a');
|
|
419
|
+
a.href = blob; a.target = '_parent';
|
|
420
|
+
a.download = fileName;
|
|
421
|
+
(document.body || document.documentElement).appendChild(a);
|
|
422
|
+
a.click(); a.parentNode.removeChild(a);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
private exportTransformedImage(tempContext: CanvasRenderingContext2D): void {
|
|
426
|
+
const parent: ImageEditor = this.parent;
|
|
427
|
+
const degree: number = parent.transform.degree;
|
|
428
|
+
if (parent.rotateFlipColl.length > 0) {
|
|
429
|
+
for (let i: number = 0, len: number = parent.rotateFlipColl.length; i < len; i++) {
|
|
430
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
431
|
+
const flip: any = parent.rotateFlipColl[i as number];
|
|
432
|
+
if (typeof flip === 'number') {
|
|
433
|
+
this.exportRotate(tempContext, flip as number);
|
|
434
|
+
} else if (flip === 'horizontal') {
|
|
435
|
+
this.exportFlip(tempContext, true, false);
|
|
436
|
+
} else if (flip === 'vertical') {
|
|
437
|
+
this.exportFlip(tempContext, false, true);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
parent.transform.degree = degree;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
private exportRotate(tempContext: CanvasRenderingContext2D, degree: number): void {
|
|
445
|
+
const parent: ImageEditor = this.parent;
|
|
446
|
+
tempContext.clearRect(0, 0, tempContext.canvas.width, tempContext.canvas.height);
|
|
447
|
+
this.setMaxDim(parent.transform.degree, tempContext.canvas);
|
|
448
|
+
tempContext.translate(tempContext.canvas.width / 2, tempContext.canvas.height / 2);
|
|
449
|
+
tempContext.rotate(Math.PI / 180 * degree);
|
|
450
|
+
tempContext.drawImage(parent.inMemoryCanvas, -tempContext.canvas.height / 2, -tempContext.canvas.width / 2,
|
|
451
|
+
tempContext.canvas.height, tempContext.canvas.width);
|
|
452
|
+
this.updateSaveContext(tempContext);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private exportFlip(tempContext: CanvasRenderingContext2D, flipHorizontal: boolean, flipVertical: boolean): void {
|
|
456
|
+
tempContext.clearRect(0, 0, tempContext.canvas.width, tempContext.canvas.height);
|
|
457
|
+
if (flipHorizontal) {
|
|
458
|
+
tempContext.translate(tempContext.canvas.width, 0);
|
|
459
|
+
tempContext.scale(-1, 1);
|
|
460
|
+
}
|
|
461
|
+
if (flipVertical) {
|
|
462
|
+
tempContext.translate(0, tempContext.canvas.height);
|
|
463
|
+
tempContext.scale(1, -1);
|
|
464
|
+
}
|
|
465
|
+
tempContext.drawImage(this.parent.inMemoryCanvas, 0, 0);
|
|
466
|
+
this.updateSaveContext(tempContext);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
private updateSaveContext(tempContext: CanvasRenderingContext2D): void {
|
|
470
|
+
const inMemoryContext: CanvasRenderingContext2D = this.parent.inMemoryCanvas.getContext('2d');
|
|
471
|
+
tempContext.setTransform(1, 0, 0, 1, 0, 0);
|
|
472
|
+
const imageData: ImageData = tempContext.getImageData(0, 0, tempContext.canvas.width, tempContext.canvas.height);
|
|
473
|
+
this.parent.inMemoryCanvas.width = imageData.width; this.parent.inMemoryCanvas.height = imageData.height;
|
|
474
|
+
inMemoryContext.putImageData(imageData, 0, 0);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private setMaxDim(degree: number, tempCanvas: HTMLCanvasElement): void {
|
|
478
|
+
let newWidth: number; let newHeight: number;
|
|
479
|
+
|
|
480
|
+
if (degree % 90 === 0 && degree % 180 !== 0) {
|
|
481
|
+
if (isNullOrUndefined(this.parent.currSelectionPoint)) {
|
|
482
|
+
newWidth = this.parent.baseImgCanvas.height;
|
|
483
|
+
newHeight = this.parent.baseImgCanvas.width;
|
|
484
|
+
} else {
|
|
485
|
+
newWidth = this.parent.img.srcHeight;
|
|
486
|
+
newHeight = this.parent.img.srcWidth;
|
|
487
|
+
}
|
|
488
|
+
} else if (degree % 180 === 0 || degree === 0) {
|
|
489
|
+
if (isNullOrUndefined(this.parent.currSelectionPoint)) {
|
|
490
|
+
newWidth = this.parent.baseImgCanvas.width;
|
|
491
|
+
newHeight = this.parent.baseImgCanvas.height;
|
|
492
|
+
} else {
|
|
493
|
+
newWidth = this.parent.img.srcWidth;
|
|
494
|
+
newHeight = this.parent.img.srcHeight;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (!isNullOrUndefined(this.parent.aspectWidth)) {
|
|
498
|
+
newWidth = this.parent.aspectWidth;
|
|
499
|
+
newHeight = this.parent.aspectHeight;
|
|
500
|
+
}
|
|
501
|
+
tempCanvas.width = newWidth; tempCanvas.height = newHeight;
|
|
502
|
+
const obj: Object = {width: 0, height: 0 };
|
|
503
|
+
this.parent.notify('transform', { prop: 'calcMaxDimension', onPropertyChange: false,
|
|
504
|
+
value: {width: newWidth, height: newHeight, obj: obj, isImgShape: null}});
|
|
505
|
+
const maxDimension: Dimension = obj as Dimension;
|
|
506
|
+
tempCanvas.style.maxWidth = maxDimension.width + 'px';
|
|
507
|
+
tempCanvas.style.maxHeight = maxDimension.height + 'px';
|
|
508
|
+
}
|
|
509
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ImageEditor } from '../index';
|
|
2
|
+
export declare class Filter {
|
|
3
|
+
private parent;
|
|
4
|
+
private lowerContext;
|
|
5
|
+
private adjustmentLevel;
|
|
6
|
+
private tempAdjustmentLevel;
|
|
7
|
+
private adjustmentValue;
|
|
8
|
+
private isBrightnessAdjusted;
|
|
9
|
+
private bevelFilter;
|
|
10
|
+
private tempAdjVal;
|
|
11
|
+
private tempFilVal;
|
|
12
|
+
constructor(parent: ImageEditor);
|
|
13
|
+
destroy(): void;
|
|
14
|
+
private addEventListener;
|
|
15
|
+
private removeEventListener;
|
|
16
|
+
private filter;
|
|
17
|
+
private updatePrivateVariables;
|
|
18
|
+
getModuleName(): string;
|
|
19
|
+
private reset;
|
|
20
|
+
private updateFinetunes;
|
|
21
|
+
private initFilter;
|
|
22
|
+
private updateAdj;
|
|
23
|
+
private setTempFilterValue;
|
|
24
|
+
private getDefaultCurrentFilter;
|
|
25
|
+
private getFilterValue;
|
|
26
|
+
private getSaturationFilterValue;
|
|
27
|
+
private setFilterAdj;
|
|
28
|
+
private setFilter;
|
|
29
|
+
private setAdjustment;
|
|
30
|
+
private setFilterValue;
|
|
31
|
+
private setSaturationFilterValue;
|
|
32
|
+
private finetuneImage;
|
|
33
|
+
private setCurrAdjValue;
|
|
34
|
+
private getCurrentObj;
|
|
35
|
+
private getValFromPercentage;
|
|
36
|
+
private getValFromLength;
|
|
37
|
+
private parseFilterString;
|
|
38
|
+
private applyFilter;
|
|
39
|
+
private blur;
|
|
40
|
+
private brightness;
|
|
41
|
+
private contrast;
|
|
42
|
+
private grayscale;
|
|
43
|
+
private hueRotate;
|
|
44
|
+
private invert;
|
|
45
|
+
private opacity;
|
|
46
|
+
private saturate;
|
|
47
|
+
private sepia;
|
|
48
|
+
}
|