ngx-image-cropper 8.0.0 → 8.1.1

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 (31) hide show
  1. package/README.md +56 -43
  2. package/esm2022/lib/component/cropper.state.mjs +188 -0
  3. package/esm2022/lib/component/image-cropper.component.mjs +211 -320
  4. package/esm2022/lib/interfaces/cropper-options.interface.mjs +1 -1
  5. package/esm2022/lib/interfaces/index.mjs +2 -2
  6. package/esm2022/lib/interfaces/move-start.interface.mjs +1 -1
  7. package/esm2022/lib/services/crop.service.mjs +60 -68
  8. package/esm2022/lib/services/load-image.service.mjs +20 -25
  9. package/esm2022/lib/utils/blob.utils.mjs +1 -1
  10. package/esm2022/lib/utils/cropper-position.utils.mjs +239 -0
  11. package/esm2022/lib/utils/exif.utils.mjs +1 -1
  12. package/esm2022/lib/utils/keyboard.utils.mjs +1 -1
  13. package/esm2022/lib/utils/resize.utils.mjs +1 -1
  14. package/fesm2022/ngx-image-cropper.mjs +734 -688
  15. package/fesm2022/ngx-image-cropper.mjs.map +1 -1
  16. package/lib/component/cropper.state.d.ts +29 -0
  17. package/lib/component/image-cropper.component.d.ts +57 -64
  18. package/lib/interfaces/cropper-options.interface.d.ts +5 -5
  19. package/lib/interfaces/index.d.ts +0 -1
  20. package/lib/interfaces/move-start.interface.d.ts +4 -6
  21. package/lib/services/crop.service.d.ts +6 -9
  22. package/lib/services/load-image.service.d.ts +5 -8
  23. package/lib/utils/cropper-position.utils.d.ts +11 -0
  24. package/lib/utils/keyboard.utils.d.ts +3 -2
  25. package/package.json +2 -1
  26. package/esm2022/lib/interfaces/cropper.settings.mjs +0 -54
  27. package/esm2022/lib/services/cropper-position.service.mjs +0 -210
  28. package/esm2022/lib/utils/hammer.utils.mjs +0 -2
  29. package/lib/interfaces/cropper.settings.d.ts +0 -38
  30. package/lib/services/cropper-position.service.d.ts +0 -15
  31. package/lib/utils/hammer.utils.d.ts +0 -7
@@ -1,63 +1,434 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, isDevMode, Component, ChangeDetectionStrategy, Optional, Inject, ViewChild, Input, HostBinding, Output, HostListener } from '@angular/core';
3
- import * as i4 from '@angular/platform-browser';
4
- import { HAMMER_LOADER } from '@angular/platform-browser';
2
+ import { signal, EventEmitter, Component, ChangeDetectionStrategy, ViewChild, Input, HostBinding, Output, HostListener } from '@angular/core';
5
3
  import { takeUntil, first } from 'rxjs/operators';
6
- import { merge, fromEvent } from 'rxjs';
4
+ import { Subject, merge, fromEvent } from 'rxjs';
7
5
  import { NgIf } from '@angular/common';
6
+ import * as i1 from '@angular/platform-browser';
8
7
 
9
- class CropperSettings {
8
+ function checkCropperPosition(cropperPosition, cropperState, maintainSize) {
9
+ cropperPosition = checkCropperSizeRestriction(cropperPosition, cropperState);
10
+ return checkCropperWithinMaxSizeBounds(cropperPosition, cropperState, maintainSize);
11
+ }
12
+ function checkCropperSizeRestriction(cropperPosition, cropperState) {
13
+ let cropperWidth = cropperPosition.x2 - cropperPosition.x1;
14
+ let cropperHeight = cropperPosition.y2 - cropperPosition.y1;
15
+ const centerX = cropperPosition.x1 + cropperWidth / 2;
16
+ const centerY = cropperPosition.y1 + cropperHeight / 2;
17
+ if (cropperState.options.cropperStaticHeight && cropperState.options.cropperStaticWidth) {
18
+ cropperWidth = cropperState.maxSize.width > cropperState.options.cropperStaticWidth
19
+ ? cropperState.options.cropperStaticWidth
20
+ : cropperState.maxSize.width;
21
+ cropperHeight = cropperState.maxSize.height > cropperState.options.cropperStaticHeight
22
+ ? cropperState.options.cropperStaticHeight
23
+ : cropperState.maxSize.height;
24
+ }
25
+ else {
26
+ cropperWidth = Math.max(cropperState.cropperScaledMinWidth, Math.min(cropperWidth, cropperState.cropperScaledMaxWidth, cropperState.maxSize.width));
27
+ cropperHeight = Math.max(cropperState.cropperScaledMinHeight, Math.min(cropperHeight, cropperState.cropperScaledMaxHeight, cropperState.maxSize.height));
28
+ if (cropperState.options.maintainAspectRatio) {
29
+ if (cropperState.maxSize.width / cropperState.options.aspectRatio < cropperState.maxSize.height) {
30
+ cropperHeight = cropperWidth / cropperState.options.aspectRatio;
31
+ }
32
+ else {
33
+ cropperWidth = cropperHeight * cropperState.options.aspectRatio;
34
+ }
35
+ }
36
+ }
37
+ const x1 = centerX - cropperWidth / 2;
38
+ const x2 = x1 + cropperWidth;
39
+ const y1 = centerY - cropperHeight / 2;
40
+ const y2 = y1 + cropperHeight;
41
+ return { x1, x2, y1, y2 };
42
+ }
43
+ function checkCropperWithinMaxSizeBounds(position, cropperState, maintainSize = false) {
44
+ if (position.x1 < 0) {
45
+ position = {
46
+ ...position,
47
+ x1: 0,
48
+ x2: position.x2 - (maintainSize ? position.x1 : 0)
49
+ };
50
+ }
51
+ if (position.y1 < 0) {
52
+ position = {
53
+ ...position,
54
+ y2: position.y2 - (maintainSize ? position.y1 : 0),
55
+ y1: 0
56
+ };
57
+ }
58
+ if (position.x2 > cropperState.maxSize.width) {
59
+ position = {
60
+ ...position,
61
+ x1: position.x1 - (maintainSize ? (position.x2 - cropperState.maxSize.width) : 0),
62
+ x2: cropperState.maxSize.width
63
+ };
64
+ }
65
+ if (position.y2 > cropperState.maxSize.height) {
66
+ position = {
67
+ ...position,
68
+ y1: position.y1 - (maintainSize ? (position.y2 - cropperState.maxSize.height) : 0),
69
+ y2: cropperState.maxSize.height
70
+ };
71
+ }
72
+ return position;
73
+ }
74
+ function moveCropper(event, moveStart) {
75
+ const diffX = getClientX(event) - moveStart.clientX;
76
+ const diffY = getClientY(event) - moveStart.clientY;
77
+ return {
78
+ x1: moveStart.cropper.x1 + diffX,
79
+ y1: moveStart.cropper.y1 + diffY,
80
+ x2: moveStart.cropper.x2 + diffX,
81
+ y2: moveStart.cropper.y2 + diffY
82
+ };
83
+ }
84
+ function resizeCropper(event, moveStart, cropperState) {
85
+ const cropperPosition = { ...cropperState.cropper };
86
+ const moveX = getClientX(event) - moveStart.clientX;
87
+ const moveY = getClientY(event) - moveStart.clientY;
88
+ switch (moveStart.position) {
89
+ case 'left':
90
+ cropperPosition.x1 = Math.min(Math.max(moveStart.cropper.x1 + moveX, cropperPosition.x2 - cropperState.cropperScaledMaxWidth), cropperPosition.x2 - cropperState.cropperScaledMinWidth);
91
+ break;
92
+ case 'topleft':
93
+ cropperPosition.x1 = Math.min(Math.max(moveStart.cropper.x1 + moveX, cropperPosition.x2 - cropperState.cropperScaledMaxWidth), cropperPosition.x2 - cropperState.cropperScaledMinWidth);
94
+ cropperPosition.y1 = Math.min(Math.max(moveStart.cropper.y1 + moveY, cropperPosition.y2 - cropperState.cropperScaledMaxHeight), cropperPosition.y2 - cropperState.cropperScaledMinHeight);
95
+ break;
96
+ case 'top':
97
+ cropperPosition.y1 = Math.min(Math.max(moveStart.cropper.y1 + moveY, cropperPosition.y2 - cropperState.cropperScaledMaxHeight), cropperPosition.y2 - cropperState.cropperScaledMinHeight);
98
+ break;
99
+ case 'topright':
100
+ cropperPosition.x2 = Math.max(Math.min(moveStart.cropper.x2 + moveX, cropperPosition.x1 + cropperState.cropperScaledMaxWidth), cropperPosition.x1 + cropperState.cropperScaledMinWidth);
101
+ cropperPosition.y1 = Math.min(Math.max(moveStart.cropper.y1 + moveY, cropperPosition.y2 - cropperState.cropperScaledMaxHeight), cropperPosition.y2 - cropperState.cropperScaledMinHeight);
102
+ break;
103
+ case 'right':
104
+ cropperPosition.x2 = Math.max(Math.min(moveStart.cropper.x2 + moveX, cropperPosition.x1 + cropperState.cropperScaledMaxWidth), cropperPosition.x1 + cropperState.cropperScaledMinWidth);
105
+ break;
106
+ case 'bottomright':
107
+ cropperPosition.x2 = Math.max(Math.min(moveStart.cropper.x2 + moveX, cropperPosition.x1 + cropperState.cropperScaledMaxWidth), cropperPosition.x1 + cropperState.cropperScaledMinWidth);
108
+ cropperPosition.y2 = Math.max(Math.min(moveStart.cropper.y2 + moveY, cropperPosition.y1 + cropperState.cropperScaledMaxHeight), cropperPosition.y1 + cropperState.cropperScaledMinHeight);
109
+ break;
110
+ case 'bottom':
111
+ cropperPosition.y2 = Math.max(Math.min(moveStart.cropper.y2 + moveY, cropperPosition.y1 + cropperState.cropperScaledMaxHeight), cropperPosition.y1 + cropperState.cropperScaledMinHeight);
112
+ break;
113
+ case 'bottomleft':
114
+ cropperPosition.x1 = Math.min(Math.max(moveStart.cropper.x1 + moveX, cropperPosition.x2 - cropperState.cropperScaledMaxWidth), cropperPosition.x2 - cropperState.cropperScaledMinWidth);
115
+ cropperPosition.y2 = Math.max(Math.min(moveStart.cropper.y2 + moveY, cropperPosition.y1 + cropperState.cropperScaledMaxHeight), cropperPosition.y1 + cropperState.cropperScaledMinHeight);
116
+ break;
117
+ case 'center':
118
+ const scale = 'scale' in event ? event.scale : 1;
119
+ const newWidth = Math.min(Math.max(cropperState.cropperScaledMinWidth, (Math.abs(moveStart.cropper.x2 - moveStart.cropper.x1)) * scale), cropperState.cropperScaledMaxWidth);
120
+ const newHeight = Math.min(Math.max(cropperState.cropperScaledMinHeight, (Math.abs(moveStart.cropper.y2 - moveStart.cropper.y1)) * scale), cropperState.cropperScaledMaxHeight);
121
+ cropperPosition.x1 = moveStart.clientX - newWidth / 2;
122
+ cropperPosition.x2 = moveStart.clientX + newWidth / 2;
123
+ cropperPosition.y1 = moveStart.clientY - newHeight / 2;
124
+ cropperPosition.y2 = moveStart.clientY + newHeight / 2;
125
+ if (cropperPosition.x1 < 0) {
126
+ cropperPosition.x2 -= cropperPosition.x1;
127
+ cropperPosition.x1 = 0;
128
+ }
129
+ else if (cropperPosition.x2 > cropperState.maxSize.width) {
130
+ cropperPosition.x1 -= (cropperPosition.x2 - cropperState.maxSize.width);
131
+ cropperPosition.x2 = cropperState.maxSize.width;
132
+ }
133
+ if (cropperPosition.y1 < 0) {
134
+ cropperPosition.y2 -= cropperPosition.y1;
135
+ cropperPosition.y1 = 0;
136
+ }
137
+ else if (cropperPosition.y2 > cropperState.maxSize.height) {
138
+ cropperPosition.y1 -= (cropperPosition.y2 - cropperState.maxSize.height);
139
+ cropperPosition.y2 = cropperState.maxSize.height;
140
+ }
141
+ break;
142
+ }
143
+ if (cropperState.options.maintainAspectRatio) {
144
+ return checkAspectRatio(moveStart.position, cropperPosition, cropperState);
145
+ }
146
+ else {
147
+ return cropperPosition;
148
+ }
149
+ }
150
+ function checkAspectRatio(position, cropperPosition, cropperState) {
151
+ cropperPosition = { ...cropperPosition };
152
+ let overflowX = 0;
153
+ let overflowY = 0;
154
+ switch (position) {
155
+ case 'top':
156
+ cropperPosition.x2 = cropperPosition.x1 + (cropperPosition.y2 - cropperPosition.y1) * cropperState.options.aspectRatio;
157
+ overflowX = Math.max(cropperPosition.x2 - cropperState.maxSize.width, 0);
158
+ overflowY = Math.max(0 - cropperPosition.y1, 0);
159
+ if (overflowX > 0 || overflowY > 0) {
160
+ cropperPosition.x2 -= (overflowY * cropperState.options.aspectRatio) > overflowX ? (overflowY * cropperState.options.aspectRatio) : overflowX;
161
+ cropperPosition.y1 += (overflowY * cropperState.options.aspectRatio) > overflowX ? overflowY : overflowX / cropperState.options.aspectRatio;
162
+ }
163
+ break;
164
+ case 'bottom':
165
+ cropperPosition.x2 = cropperPosition.x1 + (cropperPosition.y2 - cropperPosition.y1) * cropperState.options.aspectRatio;
166
+ overflowX = Math.max(cropperPosition.x2 - cropperState.maxSize.width, 0);
167
+ overflowY = Math.max(cropperPosition.y2 - cropperState.maxSize.height, 0);
168
+ if (overflowX > 0 || overflowY > 0) {
169
+ cropperPosition.x2 -= (overflowY * cropperState.options.aspectRatio) > overflowX ? (overflowY * cropperState.options.aspectRatio) : overflowX;
170
+ cropperPosition.y2 -= (overflowY * cropperState.options.aspectRatio) > overflowX ? overflowY : (overflowX / cropperState.options.aspectRatio);
171
+ }
172
+ break;
173
+ case 'topleft':
174
+ cropperPosition.y1 = cropperPosition.y2 - (cropperPosition.x2 - cropperPosition.x1) / cropperState.options.aspectRatio;
175
+ overflowX = Math.max(0 - cropperPosition.x1, 0);
176
+ overflowY = Math.max(0 - cropperPosition.y1, 0);
177
+ if (overflowX > 0 || overflowY > 0) {
178
+ cropperPosition.x1 += (overflowY * cropperState.options.aspectRatio) > overflowX ? (overflowY * cropperState.options.aspectRatio) : overflowX;
179
+ cropperPosition.y1 += (overflowY * cropperState.options.aspectRatio) > overflowX ? overflowY : overflowX / cropperState.options.aspectRatio;
180
+ }
181
+ break;
182
+ case 'topright':
183
+ cropperPosition.y1 = cropperPosition.y2 - (cropperPosition.x2 - cropperPosition.x1) / cropperState.options.aspectRatio;
184
+ overflowX = Math.max(cropperPosition.x2 - cropperState.maxSize.width, 0);
185
+ overflowY = Math.max(0 - cropperPosition.y1, 0);
186
+ if (overflowX > 0 || overflowY > 0) {
187
+ cropperPosition.x2 -= (overflowY * cropperState.options.aspectRatio) > overflowX ? (overflowY * cropperState.options.aspectRatio) : overflowX;
188
+ cropperPosition.y1 += (overflowY * cropperState.options.aspectRatio) > overflowX ? overflowY : overflowX / cropperState.options.aspectRatio;
189
+ }
190
+ break;
191
+ case 'right':
192
+ case 'bottomright':
193
+ cropperPosition.y2 = cropperPosition.y1 + (cropperPosition.x2 - cropperPosition.x1) / cropperState.options.aspectRatio;
194
+ overflowX = Math.max(cropperPosition.x2 - cropperState.maxSize.width, 0);
195
+ overflowY = Math.max(cropperPosition.y2 - cropperState.maxSize.height, 0);
196
+ if (overflowX > 0 || overflowY > 0) {
197
+ cropperPosition.x2 -= (overflowY * cropperState.options.aspectRatio) > overflowX ? (overflowY * cropperState.options.aspectRatio) : overflowX;
198
+ cropperPosition.y2 -= (overflowY * cropperState.options.aspectRatio) > overflowX ? overflowY : overflowX / cropperState.options.aspectRatio;
199
+ }
200
+ break;
201
+ case 'left':
202
+ case 'bottomleft':
203
+ cropperPosition.y2 = cropperPosition.y1 + (cropperPosition.x2 - cropperPosition.x1) / cropperState.options.aspectRatio;
204
+ overflowX = Math.max(0 - cropperPosition.x1, 0);
205
+ overflowY = Math.max(cropperPosition.y2 - cropperState.maxSize.height, 0);
206
+ if (overflowX > 0 || overflowY > 0) {
207
+ cropperPosition.x1 += (overflowY * cropperState.options.aspectRatio) > overflowX ? (overflowY * cropperState.options.aspectRatio) : overflowX;
208
+ cropperPosition.y2 -= (overflowY * cropperState.options.aspectRatio) > overflowX ? overflowY : overflowX / cropperState.options.aspectRatio;
209
+ }
210
+ break;
211
+ case 'center':
212
+ cropperPosition.x2 = cropperPosition.x1 + (cropperPosition.y2 - cropperPosition.y1) * cropperState.options.aspectRatio;
213
+ cropperPosition.y2 = cropperPosition.y1 + (cropperPosition.x2 - cropperPosition.x1) / cropperState.options.aspectRatio;
214
+ const overflowX1 = Math.max(0 - cropperPosition.x1, 0);
215
+ const overflowX2 = Math.max(cropperPosition.x2 - cropperState.maxSize.width, 0);
216
+ const overflowY1 = Math.max(cropperPosition.y2 - cropperState.maxSize.height, 0);
217
+ const overflowY2 = Math.max(0 - cropperPosition.y1, 0);
218
+ if (overflowX1 > 0 || overflowX2 > 0 || overflowY1 > 0 || overflowY2 > 0) {
219
+ cropperPosition.x1 += (overflowY1 * cropperState.options.aspectRatio) > overflowX1 ? (overflowY1 * cropperState.options.aspectRatio) : overflowX1;
220
+ cropperPosition.x2 -= (overflowY2 * cropperState.options.aspectRatio) > overflowX2 ? (overflowY2 * cropperState.options.aspectRatio) : overflowX2;
221
+ cropperPosition.y1 += (overflowY2 * cropperState.options.aspectRatio) > overflowX2 ? overflowY2 : overflowX2 / cropperState.options.aspectRatio;
222
+ cropperPosition.y2 -= (overflowY1 * cropperState.options.aspectRatio) > overflowX1 ? overflowY1 : overflowX1 / cropperState.options.aspectRatio;
223
+ }
224
+ break;
225
+ }
226
+ return cropperPosition;
227
+ }
228
+ function getClientX(event) {
229
+ if ('touches' in event && event.touches[0]) {
230
+ return event.touches[0].clientX;
231
+ }
232
+ else if ('clientX' in event) {
233
+ return event.clientX;
234
+ }
235
+ return 0;
236
+ }
237
+ function getClientY(event) {
238
+ if ('touches' in event && event.touches[0]) {
239
+ return event.touches[0].clientY;
240
+ }
241
+ else if ('clientX' in event) {
242
+ return event.clientY;
243
+ }
244
+ return 0;
245
+ }
246
+
247
+ class CropperState {
10
248
  constructor() {
11
- // From options
12
- this.format = 'png';
13
- this.output = 'blob';
14
- this.maintainAspectRatio = true;
249
+ this.options = {
250
+ format: 'png',
251
+ output: 'blob',
252
+ autoCrop: true,
253
+ maintainAspectRatio: true,
254
+ aspectRatio: 1,
255
+ resetCropOnAspectRatioChange: true,
256
+ resizeToWidth: 0,
257
+ resizeToHeight: 0,
258
+ cropperMinWidth: 0,
259
+ cropperMinHeight: 0,
260
+ cropperMaxHeight: 0,
261
+ cropperMaxWidth: 0,
262
+ cropperStaticWidth: 0,
263
+ cropperStaticHeight: 0,
264
+ canvasRotation: 0,
265
+ roundCropper: false,
266
+ onlyScaleDown: false,
267
+ imageQuality: 92,
268
+ backgroundColor: null,
269
+ containWithinAspectRatio: false,
270
+ hideResizeSquares: false,
271
+ alignImage: 'center',
272
+ cropperFrameAriaLabel: undefined,
273
+ checkImageType: true
274
+ };
275
+ this.cropper = { x1: 0, x2: 0, y1: 0, y2: 0 };
15
276
  this.transform = {};
16
- this.aspectRatio = 1;
17
- this.resetCropOnAspectRatioChange = true;
18
- this.resizeToWidth = 0;
19
- this.resizeToHeight = 0;
20
- this.cropperMinWidth = 0;
21
- this.cropperMinHeight = 0;
22
- this.cropperMaxHeight = 0;
23
- this.cropperMaxWidth = 0;
24
- this.cropperStaticWidth = 0;
25
- this.cropperStaticHeight = 0;
26
- this.canvasRotation = 0;
27
- this.initialStepSize = 3;
28
- this.roundCropper = false;
29
- this.onlyScaleDown = false;
30
- this.imageQuality = 92;
31
- this.autoCrop = true;
32
- this.backgroundColor = null;
33
- this.containWithinAspectRatio = false;
34
- this.hideResizeSquares = false;
35
- this.alignImage = 'center';
36
- this.cropperFrameAriaLabel = 'Crop photo';
37
277
  // Internal
38
278
  this.cropperScaledMinWidth = 20;
39
279
  this.cropperScaledMinHeight = 20;
40
280
  this.cropperScaledMaxWidth = 20;
41
281
  this.cropperScaledMaxHeight = 20;
42
- this.stepSize = this.initialStepSize;
43
- }
44
- setOptions(options) {
45
- Object.keys(options)
46
- .filter((k) => k in this)
47
- .forEach((k) => this[k] = options[k]);
48
- this.validateOptions();
282
+ this.stepSize = 3;
49
283
  }
50
284
  setOptionsFromChanges(changes) {
51
- Object.keys(changes)
52
- .filter((k) => k in this)
53
- .forEach((k) => this[k] = changes[k].currentValue);
285
+ if (changes['options']?.currentValue) {
286
+ this.setOptions(changes['options'].currentValue);
287
+ }
288
+ const options = Object.entries(changes)
289
+ .filter(([key]) => key in this.options)
290
+ .reduce((acc, [key, change]) => ({
291
+ ...acc,
292
+ [key]: change.currentValue
293
+ }), {});
294
+ if (Object.keys(options).length > 0) {
295
+ this.setOptions(options);
296
+ }
297
+ }
298
+ setOptions(options) {
299
+ this.options = {
300
+ ...this.options,
301
+ ...(options || {})
302
+ };
54
303
  this.validateOptions();
304
+ if (!this.loadedImage?.transformed.image.complete || !this.maxSize) {
305
+ return;
306
+ }
307
+ let positionPossiblyChanged = false;
308
+ if ((this.options.maintainAspectRatio && options['aspectRatio']) || options['maintainAspectRatio']) {
309
+ this.setCropperScaledMinSize();
310
+ this.setCropperScaledMaxSize();
311
+ if (this.options.maintainAspectRatio && (this.options.resetCropOnAspectRatioChange || !this.aspectRatioIsCorrect())) {
312
+ this.cropper = this.maxSizeCropperPosition();
313
+ positionPossiblyChanged = true;
314
+ }
315
+ }
316
+ else {
317
+ if (options['cropperMinWidth'] || options['cropperMinHeight']) {
318
+ this.setCropperScaledMinSize();
319
+ positionPossiblyChanged = true;
320
+ }
321
+ if (options['cropperMaxWidth'] || options['cropperMaxHeight']) {
322
+ this.setCropperScaledMaxSize();
323
+ positionPossiblyChanged = true;
324
+ }
325
+ if (options['cropperStaticWidth'] || options['cropperStaticHeight']) {
326
+ positionPossiblyChanged = true;
327
+ }
328
+ }
329
+ if (positionPossiblyChanged) {
330
+ this.cropper = checkCropperPosition(this.cropper, this, false);
331
+ }
55
332
  }
56
333
  validateOptions() {
57
- if (this.maintainAspectRatio && !this.aspectRatio) {
334
+ if (this.options.maintainAspectRatio && !this.options.aspectRatio) {
58
335
  throw new Error('`aspectRatio` should > 0 when `maintainAspectRatio` is enabled');
59
336
  }
60
337
  }
338
+ setMaxSize(width, height) {
339
+ this.maxSize = { width, height };
340
+ this.setCropperScaledMinSize();
341
+ this.setCropperScaledMaxSize();
342
+ }
343
+ setCropperScaledMinSize() {
344
+ if (this.loadedImage?.transformed.size) {
345
+ this.setCropperScaledMinWidth();
346
+ this.setCropperScaledMinHeight();
347
+ }
348
+ else {
349
+ this.cropperScaledMinWidth = 20;
350
+ this.cropperScaledMinHeight = 20;
351
+ }
352
+ }
353
+ setCropperScaledMinWidth() {
354
+ this.cropperScaledMinWidth = this.options.cropperMinWidth > 0
355
+ ? Math.max(20, this.options.cropperMinWidth / this.loadedImage.transformed.size.width * this.maxSize.width)
356
+ : 20;
357
+ }
358
+ setCropperScaledMinHeight() {
359
+ if (this.options.maintainAspectRatio) {
360
+ this.cropperScaledMinHeight = Math.max(20, this.cropperScaledMinWidth / this.options.aspectRatio);
361
+ }
362
+ else if (this.options.cropperMinHeight > 0) {
363
+ this.cropperScaledMinHeight = Math.max(20, this.options.cropperMinHeight / this.loadedImage.transformed.size.height * this.maxSize.height);
364
+ }
365
+ else {
366
+ this.cropperScaledMinHeight = 20;
367
+ }
368
+ }
369
+ setCropperScaledMaxSize() {
370
+ if (this.loadedImage?.transformed.size) {
371
+ const ratio = this.loadedImage.transformed.size.width / this.maxSize.width;
372
+ this.cropperScaledMaxWidth = this.options.cropperMaxWidth > 20 ? this.options.cropperMaxWidth / ratio : this.maxSize.width;
373
+ this.cropperScaledMaxHeight = this.options.cropperMaxHeight > 20 ? this.options.cropperMaxHeight / ratio : this.maxSize.height;
374
+ if (this.options.maintainAspectRatio) {
375
+ if (this.cropperScaledMaxWidth > this.cropperScaledMaxHeight * this.options.aspectRatio) {
376
+ this.cropperScaledMaxWidth = this.cropperScaledMaxHeight * this.options.aspectRatio;
377
+ }
378
+ else if (this.cropperScaledMaxWidth < this.cropperScaledMaxHeight * this.options.aspectRatio) {
379
+ this.cropperScaledMaxHeight = this.cropperScaledMaxWidth / this.options.aspectRatio;
380
+ }
381
+ }
382
+ }
383
+ else {
384
+ this.cropperScaledMaxWidth = this.maxSize.width;
385
+ this.cropperScaledMaxHeight = this.maxSize.height;
386
+ }
387
+ }
388
+ equalsCropperPosition(cropper) {
389
+ return this.cropper == null && cropper == null
390
+ || this.cropper != null && cropper != null
391
+ && this.cropper.x1.toFixed(3) === cropper.x1.toFixed(3)
392
+ && this.cropper.y1.toFixed(3) === cropper.y1.toFixed(3)
393
+ && this.cropper.x2.toFixed(3) === cropper.x2.toFixed(3)
394
+ && this.cropper.y2.toFixed(3) === cropper.y2.toFixed(3);
395
+ }
396
+ equalsTransformTranslate(transform) {
397
+ return (this.transform.translateH ?? 0) === (transform.translateH ?? 0)
398
+ && (this.transform.translateV ?? 0) === (transform.translateV ?? 0);
399
+ }
400
+ equalsTransform(transform) {
401
+ return this.equalsTransformTranslate(transform)
402
+ && (this.transform.scale ?? 1) === (transform.scale ?? 1)
403
+ && (this.transform.rotate ?? 0) === (transform.rotate ?? 0)
404
+ && (this.transform.flipH ?? false) === (transform.flipH ?? false)
405
+ && (this.transform.flipV ?? false) === (transform.flipV ?? false);
406
+ }
407
+ aspectRatioIsCorrect() {
408
+ const currentCropAspectRatio = (this.cropper.x2 - this.cropper.x1) / (this.cropper.y2 - this.cropper.y1);
409
+ return currentCropAspectRatio === this.options.aspectRatio;
410
+ }
411
+ resizeCropperPosition(oldMaxSize) {
412
+ if (!this.cropper) {
413
+ return;
414
+ }
415
+ if (oldMaxSize.width !== this.maxSize.width || oldMaxSize.height !== this.maxSize.height) {
416
+ this.cropper = {
417
+ x1: this.cropper.x1 * this.maxSize.width / oldMaxSize.width,
418
+ x2: this.cropper.x2 * this.maxSize.width / oldMaxSize.width,
419
+ y1: this.cropper.y1 * this.maxSize.height / oldMaxSize.height,
420
+ y2: this.cropper.y2 * this.maxSize.height / oldMaxSize.height
421
+ };
422
+ }
423
+ }
424
+ maxSizeCropperPosition() {
425
+ return {
426
+ x1: 0,
427
+ y1: 0,
428
+ x2: this.maxSize.width,
429
+ y2: this.maxSize.height
430
+ };
431
+ }
61
432
  }
62
433
 
63
434
  var MoveTypes;
@@ -68,46 +439,6 @@ var MoveTypes;
68
439
  MoveTypes["Pinch"] = "pinch";
69
440
  })(MoveTypes || (MoveTypes = {}));
70
441
 
71
- function getPositionForKey(key) {
72
- switch (key) {
73
- case 'ArrowUp':
74
- return 'top';
75
- case 'ArrowRight':
76
- return 'right';
77
- case 'ArrowDown':
78
- return 'bottom';
79
- case 'ArrowLeft':
80
- default:
81
- return 'left';
82
- }
83
- }
84
- function getInvertedPositionForKey(key) {
85
- switch (key) {
86
- case 'ArrowUp':
87
- return 'bottom';
88
- case 'ArrowRight':
89
- return 'left';
90
- case 'ArrowDown':
91
- return 'top';
92
- case 'ArrowLeft':
93
- default:
94
- return 'right';
95
- }
96
- }
97
- function getEventForKey(key, stepSize) {
98
- switch (key) {
99
- case 'ArrowUp':
100
- return { clientX: 0, clientY: stepSize * -1 };
101
- case 'ArrowRight':
102
- return { clientX: stepSize, clientY: 0 };
103
- case 'ArrowDown':
104
- return { clientX: 0, clientY: stepSize };
105
- case 'ArrowLeft':
106
- default:
107
- return { clientX: stepSize * -1, clientY: 0 };
108
- }
109
- }
110
-
111
442
  /*
112
443
  * Hermite resize - fast image resize/resample using Hermite filter.
113
444
  * https://github.com/viliusle/Hermite-resize
@@ -188,8 +519,8 @@ function percentage(percent, totalValue) {
188
519
  }
189
520
 
190
521
  class CropService {
191
- crop(loadedImage, cropper, settings, output, maxSize) {
192
- const imagePosition = this.getImagePosition(loadedImage, cropper, settings, maxSize);
522
+ crop(cropperState, output) {
523
+ const imagePosition = this.getImagePosition(cropperState);
193
524
  const width = imagePosition.x2 - imagePosition.x1;
194
525
  const height = imagePosition.y2 - imagePosition.y1;
195
526
  const cropCanvas = document.createElement('canvas');
@@ -199,344 +530,130 @@ class CropService {
199
530
  if (!ctx) {
200
531
  return null;
201
532
  }
202
- if (settings.backgroundColor != null) {
203
- ctx.fillStyle = settings.backgroundColor;
533
+ if (cropperState.options.backgroundColor != null) {
534
+ ctx.fillStyle = cropperState.options.backgroundColor;
204
535
  ctx.fillRect(0, 0, width, height);
205
536
  }
206
- const scaleX = (settings.transform.scale || 1) * (settings.transform.flipH ? -1 : 1);
207
- const scaleY = (settings.transform.scale || 1) * (settings.transform.flipV ? -1 : 1);
208
- const { translateH, translateV } = this.getCanvasTranslate(loadedImage, settings, maxSize);
209
- const transformedImage = loadedImage.transformed;
537
+ const scaleX = (cropperState.transform.scale || 1) * (cropperState.transform.flipH ? -1 : 1);
538
+ const scaleY = (cropperState.transform.scale || 1) * (cropperState.transform.flipV ? -1 : 1);
539
+ const { translateH, translateV } = this.getCanvasTranslate(cropperState);
540
+ const transformedImage = cropperState.loadedImage.transformed;
210
541
  ctx.setTransform(scaleX, 0, 0, scaleY, transformedImage.size.width / 2 + translateH, transformedImage.size.height / 2 + translateV);
211
542
  ctx.translate(-imagePosition.x1 / scaleX, -imagePosition.y1 / scaleY);
212
- ctx.rotate((settings.transform.rotate || 0) * Math.PI / 180);
543
+ ctx.rotate((cropperState.transform.rotate || 0) * Math.PI / 180);
213
544
  ctx.drawImage(transformedImage.image, -transformedImage.size.width / 2, -transformedImage.size.height / 2);
214
545
  const result = {
215
546
  width, height,
216
547
  imagePosition,
217
- cropperPosition: { ...cropper }
548
+ cropperPosition: { ...cropperState.cropper }
218
549
  };
219
- if (settings.containWithinAspectRatio) {
220
- result.offsetImagePosition = this.getOffsetImagePosition(loadedImage, cropper, settings, maxSize);
550
+ if (cropperState.options.containWithinAspectRatio) {
551
+ result.offsetImagePosition = this.getOffsetImagePosition(cropperState);
221
552
  }
222
- const resizeRatio = this.getResizeRatio(width, height, settings);
553
+ const resizeRatio = this.getResizeRatio(width, height, cropperState.options);
223
554
  if (resizeRatio !== 1) {
224
555
  result.width = Math.round(width * resizeRatio);
225
- result.height = settings.maintainAspectRatio
226
- ? Math.round(result.width / settings.aspectRatio)
556
+ result.height = cropperState.options.maintainAspectRatio
557
+ ? Math.round(result.width / cropperState.options.aspectRatio)
227
558
  : Math.round(height * resizeRatio);
228
559
  resizeCanvas(cropCanvas, result.width, result.height);
229
560
  }
230
561
  if (output === 'blob') {
231
- return this.cropToBlob(result, cropCanvas, settings);
562
+ return this.cropToBlob(result, cropCanvas, cropperState);
232
563
  }
233
564
  else {
234
- result.base64 = cropCanvas.toDataURL('image/' + settings.format, this.getQuality(settings));
565
+ result.base64 = cropCanvas.toDataURL('image/' + cropperState.options.format, this.getQuality(cropperState.options));
235
566
  return result;
236
567
  }
237
568
  }
238
- async cropToBlob(output, cropCanvas, settings) {
239
- output.blob = await new Promise(resolve => cropCanvas.toBlob(resolve, 'image/' + settings.format, this.getQuality(settings)));
569
+ async cropToBlob(output, cropCanvas, cropperState) {
570
+ output.blob = await new Promise(resolve => cropCanvas.toBlob(resolve, 'image/' + cropperState.options.format, this.getQuality(cropperState.options)));
240
571
  if (output.blob) {
241
572
  output.objectUrl = URL.createObjectURL(output.blob);
242
573
  }
243
574
  return output;
244
575
  }
245
- getCanvasTranslate(loadedImage, settings, maxSize) {
246
- if (settings.transform.translateUnit === 'px') {
247
- const ratio = this.getRatio(loadedImage, maxSize);
576
+ getCanvasTranslate(cropperState) {
577
+ if (cropperState.transform.translateUnit === 'px') {
578
+ const ratio = this.getRatio(cropperState);
248
579
  return {
249
- translateH: (settings.transform.translateH || 0) * ratio,
250
- translateV: (settings.transform.translateV || 0) * ratio
580
+ translateH: (cropperState.transform.translateH || 0) * ratio,
581
+ translateV: (cropperState.transform.translateV || 0) * ratio
251
582
  };
252
583
  }
253
584
  else {
254
585
  return {
255
- translateH: settings.transform.translateH ? percentage(settings.transform.translateH, loadedImage.transformed.size.width) : 0,
256
- translateV: settings.transform.translateV ? percentage(settings.transform.translateV, loadedImage.transformed.size.height) : 0
586
+ translateH: cropperState.transform.translateH ? percentage(cropperState.transform.translateH, cropperState.loadedImage.transformed.size.width) : 0,
587
+ translateV: cropperState.transform.translateV ? percentage(cropperState.transform.translateV, cropperState.loadedImage.transformed.size.height) : 0
257
588
  };
258
589
  }
259
590
  }
260
- getRatio(loadedImage, maxSize) {
261
- return loadedImage.transformed.size.width / maxSize.width;
591
+ getRatio(cropperState) {
592
+ return cropperState.loadedImage.transformed.size.width / cropperState.maxSize.width;
262
593
  }
263
- getImagePosition(loadedImage, cropper, settings, maxSize) {
264
- const ratio = this.getRatio(loadedImage, maxSize);
594
+ getImagePosition(cropperState) {
595
+ const ratio = this.getRatio(cropperState);
265
596
  const out = {
266
- x1: Math.round(cropper.x1 * ratio),
267
- y1: Math.round(cropper.y1 * ratio),
268
- x2: Math.round(cropper.x2 * ratio),
269
- y2: Math.round(cropper.y2 * ratio)
597
+ x1: Math.round(cropperState.cropper.x1 * ratio),
598
+ y1: Math.round(cropperState.cropper.y1 * ratio),
599
+ x2: Math.round(cropperState.cropper.x2 * ratio),
600
+ y2: Math.round(cropperState.cropper.y2 * ratio)
270
601
  };
271
- if (!settings.containWithinAspectRatio) {
602
+ if (!cropperState.options.containWithinAspectRatio) {
272
603
  out.x1 = Math.max(out.x1, 0);
273
604
  out.y1 = Math.max(out.y1, 0);
274
- out.x2 = Math.min(out.x2, loadedImage.transformed.size.width);
275
- out.y2 = Math.min(out.y2, loadedImage.transformed.size.height);
605
+ out.x2 = Math.min(out.x2, cropperState.loadedImage.transformed.size.width);
606
+ out.y2 = Math.min(out.y2, cropperState.loadedImage.transformed.size.height);
276
607
  }
277
608
  return out;
278
609
  }
279
- getOffsetImagePosition(loadedImage, cropper, settings, maxSize) {
280
- const canvasRotation = settings.canvasRotation + loadedImage.exifTransform.rotate;
281
- const ratio = this.getRatio(loadedImage, maxSize);
610
+ getOffsetImagePosition(cropperState) {
611
+ const canvasRotation = cropperState.options.canvasRotation + cropperState.loadedImage.exifTransform.rotate;
612
+ const ratio = this.getRatio(cropperState);
282
613
  let offsetX;
283
614
  let offsetY;
284
615
  if (canvasRotation % 2) {
285
- offsetX = (loadedImage.transformed.size.width - loadedImage.original.size.height) / 2;
286
- offsetY = (loadedImage.transformed.size.height - loadedImage.original.size.width) / 2;
616
+ offsetX = (cropperState.loadedImage.transformed.size.width - cropperState.loadedImage.original.size.height) / 2;
617
+ offsetY = (cropperState.loadedImage.transformed.size.height - cropperState.loadedImage.original.size.width) / 2;
287
618
  }
288
619
  else {
289
- offsetX = (loadedImage.transformed.size.width - loadedImage.original.size.width) / 2;
290
- offsetY = (loadedImage.transformed.size.height - loadedImage.original.size.height) / 2;
620
+ offsetX = (cropperState.loadedImage.transformed.size.width - cropperState.loadedImage.original.size.width) / 2;
621
+ offsetY = (cropperState.loadedImage.transformed.size.height - cropperState.loadedImage.original.size.height) / 2;
291
622
  }
292
623
  const out = {
293
- x1: Math.round(cropper.x1 * ratio) - offsetX,
294
- y1: Math.round(cropper.y1 * ratio) - offsetY,
295
- x2: Math.round(cropper.x2 * ratio) - offsetX,
296
- y2: Math.round(cropper.y2 * ratio) - offsetY
624
+ x1: Math.round(cropperState.cropper.x1 * ratio) - offsetX,
625
+ y1: Math.round(cropperState.cropper.y1 * ratio) - offsetY,
626
+ x2: Math.round(cropperState.cropper.x2 * ratio) - offsetX,
627
+ y2: Math.round(cropperState.cropper.y2 * ratio) - offsetY
297
628
  };
298
- if (!settings.containWithinAspectRatio) {
629
+ if (!cropperState.options.containWithinAspectRatio) {
299
630
  out.x1 = Math.max(out.x1, 0);
300
631
  out.y1 = Math.max(out.y1, 0);
301
- out.x2 = Math.min(out.x2, loadedImage.transformed.size.width);
302
- out.y2 = Math.min(out.y2, loadedImage.transformed.size.height);
632
+ out.x2 = Math.min(out.x2, cropperState.loadedImage.transformed.size.width);
633
+ out.y2 = Math.min(out.y2, cropperState.loadedImage.transformed.size.height);
303
634
  }
304
635
  return out;
305
636
  }
306
- getResizeRatio(width, height, settings) {
307
- const ratioWidth = settings.resizeToWidth / width;
308
- const ratioHeight = settings.resizeToHeight / height;
637
+ getResizeRatio(width, height, options) {
638
+ const ratioWidth = options.resizeToWidth / width;
639
+ const ratioHeight = options.resizeToHeight / height;
309
640
  const ratios = new Array();
310
- if (settings.resizeToWidth > 0) {
641
+ if (options.resizeToWidth > 0) {
311
642
  ratios.push(ratioWidth);
312
643
  }
313
- if (settings.resizeToHeight > 0) {
644
+ if (options.resizeToHeight > 0) {
314
645
  ratios.push(ratioHeight);
315
646
  }
316
647
  const result = ratios.length === 0 ? 1 : Math.min(...ratios);
317
- if (result > 1 && !settings.onlyScaleDown) {
648
+ if (result > 1 && !options.onlyScaleDown) {
318
649
  return result;
319
650
  }
320
651
  return Math.min(result, 1);
321
652
  }
322
- getQuality(settings) {
323
- return Math.min(1, Math.max(0, settings.imageQuality / 100));
324
- }
325
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CropService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
326
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CropService, providedIn: 'root' }); }
327
- }
328
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CropService, decorators: [{
329
- type: Injectable,
330
- args: [{ providedIn: 'root' }]
331
- }] });
332
-
333
- class CropperPositionService {
334
- resetCropperPosition(sourceImage, cropperPosition, settings, maxSize) {
335
- if (!sourceImage?.nativeElement) {
336
- return;
337
- }
338
- if (settings.cropperStaticHeight && settings.cropperStaticWidth) {
339
- cropperPosition.x1 = 0;
340
- cropperPosition.x2 = maxSize.width > settings.cropperStaticWidth ?
341
- settings.cropperStaticWidth : maxSize.width;
342
- cropperPosition.y1 = 0;
343
- cropperPosition.y2 = maxSize.height > settings.cropperStaticHeight ?
344
- settings.cropperStaticHeight : maxSize.height;
345
- }
346
- else {
347
- const cropperWidth = Math.min(settings.cropperScaledMaxWidth, maxSize.width);
348
- const cropperHeight = Math.min(settings.cropperScaledMaxHeight, maxSize.height);
349
- if (!settings.maintainAspectRatio) {
350
- cropperPosition.x1 = 0;
351
- cropperPosition.x2 = cropperWidth;
352
- cropperPosition.y1 = 0;
353
- cropperPosition.y2 = cropperHeight;
354
- }
355
- else if (maxSize.width / settings.aspectRatio < maxSize.height) {
356
- cropperPosition.x1 = 0;
357
- cropperPosition.x2 = cropperWidth;
358
- const cropperHeightWithAspectRatio = cropperWidth / settings.aspectRatio;
359
- cropperPosition.y1 = (maxSize.height - cropperHeightWithAspectRatio) / 2;
360
- cropperPosition.y2 = cropperPosition.y1 + cropperHeightWithAspectRatio;
361
- }
362
- else {
363
- cropperPosition.y1 = 0;
364
- cropperPosition.y2 = cropperHeight;
365
- const cropperWidthWithAspectRatio = cropperHeight * settings.aspectRatio;
366
- cropperPosition.x1 = (maxSize.width - cropperWidthWithAspectRatio) / 2;
367
- cropperPosition.x2 = cropperPosition.x1 + cropperWidthWithAspectRatio;
368
- }
369
- }
370
- }
371
- move(event, moveStart, cropperPosition) {
372
- const diffX = this.getClientX(event) - moveStart.clientX;
373
- const diffY = this.getClientY(event) - moveStart.clientY;
374
- cropperPosition.x1 = moveStart.x1 + diffX;
375
- cropperPosition.y1 = moveStart.y1 + diffY;
376
- cropperPosition.x2 = moveStart.x2 + diffX;
377
- cropperPosition.y2 = moveStart.y2 + diffY;
378
- }
379
- resize(event, moveStart, cropperPosition, maxSize, settings) {
380
- const moveX = this.getClientX(event) - moveStart.clientX;
381
- const moveY = this.getClientY(event) - moveStart.clientY;
382
- switch (moveStart.position) {
383
- case 'left':
384
- cropperPosition.x1 = Math.min(Math.max(moveStart.x1 + moveX, cropperPosition.x2 - settings.cropperScaledMaxWidth), cropperPosition.x2 - settings.cropperScaledMinWidth);
385
- break;
386
- case 'topleft':
387
- cropperPosition.x1 = Math.min(Math.max(moveStart.x1 + moveX, cropperPosition.x2 - settings.cropperScaledMaxWidth), cropperPosition.x2 - settings.cropperScaledMinWidth);
388
- cropperPosition.y1 = Math.min(Math.max(moveStart.y1 + moveY, cropperPosition.y2 - settings.cropperScaledMaxHeight), cropperPosition.y2 - settings.cropperScaledMinHeight);
389
- break;
390
- case 'top':
391
- cropperPosition.y1 = Math.min(Math.max(moveStart.y1 + moveY, cropperPosition.y2 - settings.cropperScaledMaxHeight), cropperPosition.y2 - settings.cropperScaledMinHeight);
392
- break;
393
- case 'topright':
394
- cropperPosition.x2 = Math.max(Math.min(moveStart.x2 + moveX, cropperPosition.x1 + settings.cropperScaledMaxWidth), cropperPosition.x1 + settings.cropperScaledMinWidth);
395
- cropperPosition.y1 = Math.min(Math.max(moveStart.y1 + moveY, cropperPosition.y2 - settings.cropperScaledMaxHeight), cropperPosition.y2 - settings.cropperScaledMinHeight);
396
- break;
397
- case 'right':
398
- cropperPosition.x2 = Math.max(Math.min(moveStart.x2 + moveX, cropperPosition.x1 + settings.cropperScaledMaxWidth), cropperPosition.x1 + settings.cropperScaledMinWidth);
399
- break;
400
- case 'bottomright':
401
- cropperPosition.x2 = Math.max(Math.min(moveStart.x2 + moveX, cropperPosition.x1 + settings.cropperScaledMaxWidth), cropperPosition.x1 + settings.cropperScaledMinWidth);
402
- cropperPosition.y2 = Math.max(Math.min(moveStart.y2 + moveY, cropperPosition.y1 + settings.cropperScaledMaxHeight), cropperPosition.y1 + settings.cropperScaledMinHeight);
403
- break;
404
- case 'bottom':
405
- cropperPosition.y2 = Math.max(Math.min(moveStart.y2 + moveY, cropperPosition.y1 + settings.cropperScaledMaxHeight), cropperPosition.y1 + settings.cropperScaledMinHeight);
406
- break;
407
- case 'bottomleft':
408
- cropperPosition.x1 = Math.min(Math.max(moveStart.x1 + moveX, cropperPosition.x2 - settings.cropperScaledMaxWidth), cropperPosition.x2 - settings.cropperScaledMinWidth);
409
- cropperPosition.y2 = Math.max(Math.min(moveStart.y2 + moveY, cropperPosition.y1 + settings.cropperScaledMaxHeight), cropperPosition.y1 + settings.cropperScaledMinHeight);
410
- break;
411
- case 'center':
412
- const scale = event.scale;
413
- const newWidth = Math.min(Math.max(settings.cropperScaledMinWidth, (Math.abs(moveStart.x2 - moveStart.x1)) * scale), settings.cropperScaledMaxWidth);
414
- const newHeight = Math.min(Math.max(settings.cropperScaledMinHeight, (Math.abs(moveStart.y2 - moveStart.y1)) * scale), settings.cropperScaledMaxHeight);
415
- cropperPosition.x1 = moveStart.clientX - newWidth / 2;
416
- cropperPosition.x2 = moveStart.clientX + newWidth / 2;
417
- cropperPosition.y1 = moveStart.clientY - newHeight / 2;
418
- cropperPosition.y2 = moveStart.clientY + newHeight / 2;
419
- if (cropperPosition.x1 < 0) {
420
- cropperPosition.x2 -= cropperPosition.x1;
421
- cropperPosition.x1 = 0;
422
- }
423
- else if (cropperPosition.x2 > maxSize.width) {
424
- cropperPosition.x1 -= (cropperPosition.x2 - maxSize.width);
425
- cropperPosition.x2 = maxSize.width;
426
- }
427
- if (cropperPosition.y1 < 0) {
428
- cropperPosition.y2 -= cropperPosition.y1;
429
- cropperPosition.y1 = 0;
430
- }
431
- else if (cropperPosition.y2 > maxSize.height) {
432
- cropperPosition.y1 -= (cropperPosition.y2 - maxSize.height);
433
- cropperPosition.y2 = maxSize.height;
434
- }
435
- break;
436
- }
437
- if (settings.maintainAspectRatio) {
438
- this.checkAspectRatio(moveStart.position, cropperPosition, maxSize, settings);
439
- }
440
- }
441
- checkAspectRatio(position, cropperPosition, maxSize, settings) {
442
- let overflowX = 0;
443
- let overflowY = 0;
444
- switch (position) {
445
- case 'top':
446
- cropperPosition.x2 = cropperPosition.x1 + (cropperPosition.y2 - cropperPosition.y1) * settings.aspectRatio;
447
- overflowX = Math.max(cropperPosition.x2 - maxSize.width, 0);
448
- overflowY = Math.max(0 - cropperPosition.y1, 0);
449
- if (overflowX > 0 || overflowY > 0) {
450
- cropperPosition.x2 -= (overflowY * settings.aspectRatio) > overflowX ? (overflowY * settings.aspectRatio) : overflowX;
451
- cropperPosition.y1 += (overflowY * settings.aspectRatio) > overflowX ? overflowY : overflowX / settings.aspectRatio;
452
- }
453
- break;
454
- case 'bottom':
455
- cropperPosition.x2 = cropperPosition.x1 + (cropperPosition.y2 - cropperPosition.y1) * settings.aspectRatio;
456
- overflowX = Math.max(cropperPosition.x2 - maxSize.width, 0);
457
- overflowY = Math.max(cropperPosition.y2 - maxSize.height, 0);
458
- if (overflowX > 0 || overflowY > 0) {
459
- cropperPosition.x2 -= (overflowY * settings.aspectRatio) > overflowX ? (overflowY * settings.aspectRatio) : overflowX;
460
- cropperPosition.y2 -= (overflowY * settings.aspectRatio) > overflowX ? overflowY : (overflowX / settings.aspectRatio);
461
- }
462
- break;
463
- case 'topleft':
464
- cropperPosition.y1 = cropperPosition.y2 - (cropperPosition.x2 - cropperPosition.x1) / settings.aspectRatio;
465
- overflowX = Math.max(0 - cropperPosition.x1, 0);
466
- overflowY = Math.max(0 - cropperPosition.y1, 0);
467
- if (overflowX > 0 || overflowY > 0) {
468
- cropperPosition.x1 += (overflowY * settings.aspectRatio) > overflowX ? (overflowY * settings.aspectRatio) : overflowX;
469
- cropperPosition.y1 += (overflowY * settings.aspectRatio) > overflowX ? overflowY : overflowX / settings.aspectRatio;
470
- }
471
- break;
472
- case 'topright':
473
- cropperPosition.y1 = cropperPosition.y2 - (cropperPosition.x2 - cropperPosition.x1) / settings.aspectRatio;
474
- overflowX = Math.max(cropperPosition.x2 - maxSize.width, 0);
475
- overflowY = Math.max(0 - cropperPosition.y1, 0);
476
- if (overflowX > 0 || overflowY > 0) {
477
- cropperPosition.x2 -= (overflowY * settings.aspectRatio) > overflowX ? (overflowY * settings.aspectRatio) : overflowX;
478
- cropperPosition.y1 += (overflowY * settings.aspectRatio) > overflowX ? overflowY : overflowX / settings.aspectRatio;
479
- }
480
- break;
481
- case 'right':
482
- case 'bottomright':
483
- cropperPosition.y2 = cropperPosition.y1 + (cropperPosition.x2 - cropperPosition.x1) / settings.aspectRatio;
484
- overflowX = Math.max(cropperPosition.x2 - maxSize.width, 0);
485
- overflowY = Math.max(cropperPosition.y2 - maxSize.height, 0);
486
- if (overflowX > 0 || overflowY > 0) {
487
- cropperPosition.x2 -= (overflowY * settings.aspectRatio) > overflowX ? (overflowY * settings.aspectRatio) : overflowX;
488
- cropperPosition.y2 -= (overflowY * settings.aspectRatio) > overflowX ? overflowY : overflowX / settings.aspectRatio;
489
- }
490
- break;
491
- case 'left':
492
- case 'bottomleft':
493
- cropperPosition.y2 = cropperPosition.y1 + (cropperPosition.x2 - cropperPosition.x1) / settings.aspectRatio;
494
- overflowX = Math.max(0 - cropperPosition.x1, 0);
495
- overflowY = Math.max(cropperPosition.y2 - maxSize.height, 0);
496
- if (overflowX > 0 || overflowY > 0) {
497
- cropperPosition.x1 += (overflowY * settings.aspectRatio) > overflowX ? (overflowY * settings.aspectRatio) : overflowX;
498
- cropperPosition.y2 -= (overflowY * settings.aspectRatio) > overflowX ? overflowY : overflowX / settings.aspectRatio;
499
- }
500
- break;
501
- case 'center':
502
- cropperPosition.x2 = cropperPosition.x1 + (cropperPosition.y2 - cropperPosition.y1) * settings.aspectRatio;
503
- cropperPosition.y2 = cropperPosition.y1 + (cropperPosition.x2 - cropperPosition.x1) / settings.aspectRatio;
504
- const overflowX1 = Math.max(0 - cropperPosition.x1, 0);
505
- const overflowX2 = Math.max(cropperPosition.x2 - maxSize.width, 0);
506
- const overflowY1 = Math.max(cropperPosition.y2 - maxSize.height, 0);
507
- const overflowY2 = Math.max(0 - cropperPosition.y1, 0);
508
- if (overflowX1 > 0 || overflowX2 > 0 || overflowY1 > 0 || overflowY2 > 0) {
509
- cropperPosition.x1 += (overflowY1 * settings.aspectRatio) > overflowX1 ? (overflowY1 * settings.aspectRatio) : overflowX1;
510
- cropperPosition.x2 -= (overflowY2 * settings.aspectRatio) > overflowX2 ? (overflowY2 * settings.aspectRatio) : overflowX2;
511
- cropperPosition.y1 += (overflowY2 * settings.aspectRatio) > overflowX2 ? overflowY2 : overflowX2 / settings.aspectRatio;
512
- cropperPosition.y2 -= (overflowY1 * settings.aspectRatio) > overflowX1 ? overflowY1 : overflowX1 / settings.aspectRatio;
513
- }
514
- break;
515
- }
516
- }
517
- getClientX(event) {
518
- if ('touches' in event && event.touches[0])
519
- return event.touches[0].clientX;
520
- else if ('clientX' in event) {
521
- return event.clientX;
522
- }
523
- return 0;
653
+ getQuality(options) {
654
+ return Math.min(1, Math.max(0, options.imageQuality / 100));
524
655
  }
525
- getClientY(event) {
526
- if ('touches' in event && event.touches[0])
527
- return event.touches[0].clientY;
528
- else if ('clientX' in event) {
529
- return event.clientY;
530
- }
531
- return 0;
532
- }
533
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CropperPositionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
534
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CropperPositionService, providedIn: 'root' }); }
535
656
  }
536
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CropperPositionService, decorators: [{
537
- type: Injectable,
538
- args: [{ providedIn: 'root' }]
539
- }] });
540
657
 
541
658
  // Black 2x1 JPEG, with the following meta information set:
542
659
  // - EXIF Orientation: 6 (Rotated 90° CCW)
@@ -623,7 +740,10 @@ class LoadImageService {
623
740
  }
624
741
  async loadImageFile(file, cropperSettings) {
625
742
  const arrayBuffer = await file.arrayBuffer();
626
- return await this.checkImageTypeAndLoadImageFromArrayBuffer(arrayBuffer, file.type, cropperSettings);
743
+ if (cropperSettings.options.checkImageType) {
744
+ return await this.checkImageTypeAndLoadImageFromArrayBuffer(arrayBuffer, file.type, cropperSettings);
745
+ }
746
+ return await this.loadImageFromArrayBuffer(arrayBuffer, cropperSettings);
627
747
  }
628
748
  checkImageTypeAndLoadImageFromArrayBuffer(arrayBuffer, imageType, cropperSettings) {
629
749
  if (!this.isValidImageType(imageType)) {
@@ -632,7 +752,7 @@ class LoadImageService {
632
752
  return this.loadImageFromArrayBuffer(arrayBuffer, cropperSettings, imageType);
633
753
  }
634
754
  isValidImageType(type) {
635
- return /image\/(png|jpg|jpeg|bmp|gif|tiff|svg|webp|x-icon|vnd.microsoft.icon)/.test(type);
755
+ return /image\/(png|jpg|jpeg|heic|bmp|gif|tiff|svg|webp|x-icon|vnd.microsoft.icon)/.test(type);
636
756
  }
637
757
  async loadImageFromURL(url, cropperSettings) {
638
758
  const res = await fetch(url);
@@ -654,7 +774,7 @@ class LoadImageService {
654
774
  }
655
775
  return bytes.buffer;
656
776
  }
657
- async loadImageFromArrayBuffer(arrayBuffer, cropperSettings, imageType) {
777
+ async loadImageFromArrayBuffer(arrayBuffer, cropperState, imageType) {
658
778
  const res = await new Promise(async (resolve, reject) => {
659
779
  try {
660
780
  const blob = new Blob([arrayBuffer], imageType ? { type: imageType } : undefined);
@@ -675,7 +795,7 @@ class LoadImageService {
675
795
  reject(e);
676
796
  }
677
797
  });
678
- return await this.transformImageFromArrayBuffer(res, cropperSettings, res.originalImageSize != null);
798
+ return await this.transformImageFromArrayBuffer(res, cropperState, res.originalImageSize != null);
679
799
  }
680
800
  async getSvgImageSize(blob) {
681
801
  const parser = new DOMParser();
@@ -719,10 +839,10 @@ class LoadImageService {
719
839
  };
720
840
  return this.transformLoadedImage(loadedImage, cropperSettings, forceTransform);
721
841
  }
722
- async transformLoadedImage(loadedImage, cropperSettings, forceTransform = false) {
723
- const canvasRotation = cropperSettings.canvasRotation + loadedImage.exifTransform.rotate;
842
+ async transformLoadedImage(loadedImage, cropperState, forceTransform = false) {
843
+ const canvasRotation = cropperState.options.canvasRotation + loadedImage.exifTransform.rotate;
724
844
  const originalSize = loadedImage.original.size;
725
- if (!forceTransform && canvasRotation === 0 && !loadedImage.exifTransform.flip && !cropperSettings.containWithinAspectRatio) {
845
+ if (!forceTransform && canvasRotation === 0 && !loadedImage.exifTransform.flip && !cropperState.options.containWithinAspectRatio) {
726
846
  return {
727
847
  original: {
728
848
  objectUrl: loadedImage.original.objectUrl,
@@ -737,7 +857,7 @@ class LoadImageService {
737
857
  exifTransform: loadedImage.exifTransform
738
858
  };
739
859
  }
740
- const transformedSize = this.getTransformedSize(originalSize, loadedImage.exifTransform, cropperSettings);
860
+ const transformedSize = this.getTransformedSize(originalSize, loadedImage.exifTransform, cropperState);
741
861
  const canvas = document.createElement('canvas');
742
862
  canvas.width = transformedSize.width;
743
863
  canvas.height = transformedSize.height;
@@ -745,7 +865,7 @@ class LoadImageService {
745
865
  ctx?.setTransform(loadedImage.exifTransform.flip ? -1 : 1, 0, 0, 1, canvas.width / 2, canvas.height / 2);
746
866
  ctx?.rotate(Math.PI * (canvasRotation / 2));
747
867
  ctx?.drawImage(loadedImage.original.image, -originalSize.width / 2, -originalSize.height / 2);
748
- const blob = await new Promise(resolve => canvas.toBlob(resolve, cropperSettings.format));
868
+ const blob = await new Promise(resolve => canvas.toBlob(resolve, cropperState.options.format));
749
869
  if (!blob) {
750
870
  throw new Error('Failed to get Blob for transformed image.');
751
871
  }
@@ -776,20 +896,20 @@ class LoadImageService {
776
896
  image.src = objectUrl;
777
897
  }));
778
898
  }
779
- getTransformedSize(originalSize, exifTransform, cropperSettings) {
780
- const canvasRotation = cropperSettings.canvasRotation + exifTransform.rotate;
781
- if (cropperSettings.containWithinAspectRatio) {
899
+ getTransformedSize(originalSize, exifTransform, cropperState) {
900
+ const canvasRotation = cropperState.options.canvasRotation + exifTransform.rotate;
901
+ if (cropperState.options.containWithinAspectRatio) {
782
902
  if (canvasRotation % 2) {
783
- const minWidthToContain = originalSize.width * cropperSettings.aspectRatio;
784
- const minHeightToContain = originalSize.height / cropperSettings.aspectRatio;
903
+ const minWidthToContain = originalSize.width * cropperState.options.aspectRatio;
904
+ const minHeightToContain = originalSize.height / cropperState.options.aspectRatio;
785
905
  return {
786
906
  width: Math.max(originalSize.height, minWidthToContain),
787
907
  height: Math.max(originalSize.width, minHeightToContain)
788
908
  };
789
909
  }
790
910
  else {
791
- const minWidthToContain = originalSize.height * cropperSettings.aspectRatio;
792
- const minHeightToContain = originalSize.width / cropperSettings.aspectRatio;
911
+ const minWidthToContain = originalSize.height * cropperState.options.aspectRatio;
912
+ const minHeightToContain = originalSize.width / cropperState.options.aspectRatio;
793
913
  return {
794
914
  width: Math.max(originalSize.width, minWidthToContain),
795
915
  height: Math.max(originalSize.height, minHeightToContain)
@@ -807,65 +927,68 @@ class LoadImageService {
807
927
  height: originalSize.height
808
928
  };
809
929
  }
810
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LoadImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
811
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LoadImageService, providedIn: 'root' }); }
812
930
  }
813
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LoadImageService, decorators: [{
814
- type: Injectable,
815
- args: [{ providedIn: 'root' }]
816
- }] });
931
+
932
+ function getPositionForKey(key) {
933
+ switch (key) {
934
+ case 'ArrowUp':
935
+ return 'top';
936
+ case 'ArrowRight':
937
+ return 'right';
938
+ case 'ArrowDown':
939
+ return 'bottom';
940
+ case 'ArrowLeft':
941
+ default:
942
+ return 'left';
943
+ }
944
+ }
945
+ function getInvertedPositionForKey(key) {
946
+ switch (key) {
947
+ case 'ArrowUp':
948
+ return 'bottom';
949
+ case 'ArrowRight':
950
+ return 'left';
951
+ case 'ArrowDown':
952
+ return 'top';
953
+ case 'ArrowLeft':
954
+ default:
955
+ return 'right';
956
+ }
957
+ }
958
+ function getEventForKey(key, stepSize) {
959
+ switch (key) {
960
+ case 'ArrowUp':
961
+ return { clientX: 0, clientY: stepSize * -1 };
962
+ case 'ArrowRight':
963
+ return { clientX: stepSize, clientY: 0 };
964
+ case 'ArrowDown':
965
+ return { clientX: 0, clientY: stepSize };
966
+ case 'ArrowLeft':
967
+ default:
968
+ return { clientX: stepSize * -1, clientY: 0 };
969
+ }
970
+ }
817
971
 
818
972
  class ImageCropperComponent {
819
- constructor(cropService, cropperPositionService, loadImageService, sanitizer, cd, zone, hammerLoader) {
820
- this.cropService = cropService;
821
- this.cropperPositionService = cropperPositionService;
822
- this.loadImageService = loadImageService;
973
+ get alignImageStyle() {
974
+ return this.state.options.alignImage;
975
+ }
976
+ constructor(sanitizer, cd, zone) {
823
977
  this.sanitizer = sanitizer;
824
978
  this.cd = cd;
825
979
  this.zone = zone;
826
- this.hammerLoader = hammerLoader;
827
- this.settings = new CropperSettings();
980
+ this.pinchStart$ = new Subject();
981
+ this.cropService = new CropService();
982
+ this.loadImageService = new LoadImageService();
828
983
  this.setImageMaxSizeRetries = 0;
829
984
  this.resizedWhileHidden = false;
830
- this.marginLeft = '0px';
831
- this.maxSize = {
832
- width: 0,
833
- height: 0
834
- };
835
985
  this.moveTypes = MoveTypes;
986
+ this.state = new CropperState();
987
+ this.safeImgDataUrl = signal(undefined);
988
+ this.marginLeft = '0px';
836
989
  this.imageVisible = false;
837
- this.cropperFrameAriaLabel = this.settings.cropperFrameAriaLabel;
838
- this.output = this.settings.output;
839
- this.format = this.settings.format;
840
- this.transform = {};
841
- this.maintainAspectRatio = this.settings.maintainAspectRatio;
842
- this.aspectRatio = this.settings.aspectRatio;
843
- this.resetCropOnAspectRatioChange = this.settings.resetCropOnAspectRatioChange;
844
- this.resizeToWidth = this.settings.resizeToWidth;
845
- this.resizeToHeight = this.settings.resizeToHeight;
846
- this.cropperMinWidth = this.settings.cropperMinWidth;
847
- this.cropperMinHeight = this.settings.cropperMinHeight;
848
- this.cropperMaxHeight = this.settings.cropperMaxHeight;
849
- this.cropperMaxWidth = this.settings.cropperMaxWidth;
850
- this.cropperStaticWidth = this.settings.cropperStaticWidth;
851
- this.cropperStaticHeight = this.settings.cropperStaticHeight;
852
- this.canvasRotation = this.settings.canvasRotation;
853
- this.initialStepSize = this.settings.initialStepSize;
854
- this.roundCropper = this.settings.roundCropper;
855
- this.onlyScaleDown = this.settings.onlyScaleDown;
856
- this.imageQuality = this.settings.imageQuality;
857
- this.autoCrop = this.settings.autoCrop;
858
- this.backgroundColor = this.settings.backgroundColor;
859
- this.containWithinAspectRatio = this.settings.containWithinAspectRatio;
860
- this.hideResizeSquares = this.settings.hideResizeSquares;
861
990
  this.allowMoveImage = false;
862
- this.cropper = {
863
- x1: -100,
864
- y1: -100,
865
- x2: 10000,
866
- y2: 10000
867
- };
868
- this.alignImage = this.settings.alignImage;
991
+ this.checkImageType = true;
869
992
  this.disabled = false;
870
993
  this.hidden = false;
871
994
  this.imageCropped = new EventEmitter();
@@ -874,34 +997,42 @@ class ImageCropperComponent {
874
997
  this.cropperReady = new EventEmitter();
875
998
  this.loadImageFailed = new EventEmitter();
876
999
  this.transformChange = new EventEmitter();
1000
+ this.cropperChange = new EventEmitter();
877
1001
  this.reset();
878
1002
  }
1003
+ ngOnInit() {
1004
+ this.state.stepSize = this.initialStepSize || this.state.stepSize;
1005
+ }
879
1006
  ngOnChanges(changes) {
880
- this.onChangesUpdateSettings(changes);
1007
+ const previousCropperPosition = this.state.cropper;
1008
+ const previousTransform = this.state.transform;
1009
+ const previousBackgroundColor = this.state.options.backgroundColor;
1010
+ this.state.setOptionsFromChanges(changes);
881
1011
  this.onChangesInputImage(changes);
882
- if (this.loadedImage?.original.image.complete && (changes['containWithinAspectRatio'] || changes['canvasRotation'])) {
1012
+ if (changes['transform'] && this.transform) {
1013
+ this.state.transform = this.transform;
1014
+ this.setCssTransform();
1015
+ }
1016
+ if (!this.state.loadedImage?.transformed.image.complete || !this.state.maxSize) {
1017
+ return;
1018
+ }
1019
+ if ((this.containWithinAspectRatio && changes['aspectRatio']) || changes['containWithinAspectRatio'] || changes['canvasRotation']) {
883
1020
  this.loadImageService
884
- .transformLoadedImage(this.loadedImage, this.settings)
1021
+ .transformLoadedImage(this.state.loadedImage, this.state)
885
1022
  .then((res) => this.setLoadedImage(res))
886
1023
  .catch((err) => this.loadImageError(err));
1024
+ return;
887
1025
  }
888
- if (changes['cropper'] || changes['maintainAspectRatio'] || changes['aspectRatio']) {
889
- this.setMaxSize();
890
- this.setCropperScaledMinSize();
891
- this.setCropperScaledMaxSize();
892
- if (this.maintainAspectRatio &&
893
- (this.resetCropOnAspectRatioChange || !this.aspectRatioIsCorrect()) &&
894
- (changes['maintainAspectRatio'] || changes['aspectRatio'])) {
895
- this.resetCropperPosition();
896
- }
897
- else if (changes['cropper']) {
898
- this.checkCropperPosition(false);
899
- this.doAutoCrop();
900
- }
1026
+ if (changes['cropper'] && this.cropper) {
1027
+ this.state.cropper = checkCropperPosition(this.cropper, this.state, true);
901
1028
  }
902
- if (changes['transform']) {
903
- this.transform = this.transform || {};
904
- this.setCssTransform();
1029
+ const cropperChanged = !this.state.equalsCropperPosition(previousCropperPosition);
1030
+ if (cropperChanged && (!this.cropper || !this.state.equalsCropperPosition(this.cropper))) {
1031
+ this.cropperChange.emit(this.state.cropper);
1032
+ }
1033
+ if (cropperChanged
1034
+ || !this.state.equalsTransform(previousTransform)
1035
+ || this.state.options.backgroundColor !== previousBackgroundColor) {
905
1036
  this.doAutoCrop();
906
1037
  }
907
1038
  if (changes['hidden'] && this.resizedWhileHidden && !this.hidden) {
@@ -911,20 +1042,6 @@ class ImageCropperComponent {
911
1042
  });
912
1043
  }
913
1044
  }
914
- onChangesUpdateSettings(changes) {
915
- this.settings.setOptionsFromChanges(changes);
916
- if (this.settings.cropperStaticHeight && this.settings.cropperStaticWidth) {
917
- this.hideResizeSquares = true;
918
- this.settings.setOptions({
919
- hideResizeSquares: true,
920
- cropperMinWidth: this.settings.cropperStaticWidth,
921
- cropperMinHeight: this.settings.cropperStaticHeight,
922
- cropperMaxHeight: this.settings.cropperStaticHeight,
923
- cropperMaxWidth: this.settings.cropperStaticWidth,
924
- maintainAspectRatio: false
925
- });
926
- }
927
- }
928
1045
  onChangesInputImage(changes) {
929
1046
  if (changes['imageChangedEvent'] || changes['imageURL'] || changes['imageBase64'] || changes['imageFile']) {
930
1047
  this.reset();
@@ -946,73 +1063,50 @@ class ImageCropperComponent {
946
1063
  const files = this.imageChangedEvent?.target?.files;
947
1064
  return files instanceof FileList && files.length > 0;
948
1065
  }
949
- setCssTransform() {
950
- const translateUnit = this.transform?.translateUnit || '%';
951
- this.safeTransformStyle = this.sanitizer.bypassSecurityTrustStyle(`translate(${this.transform.translateH || 0}${translateUnit}, ${this.transform.translateV || 0}${translateUnit})` +
952
- ' scaleX(' + (this.transform.scale || 1) * (this.transform.flipH ? -1 : 1) + ')' +
953
- ' scaleY(' + (this.transform.scale || 1) * (this.transform.flipV ? -1 : 1) + ')' +
954
- ' rotate(' + (this.transform.rotate || 0) + 'deg)');
955
- }
956
- ngOnInit() {
957
- this.settings.stepSize = this.initialStepSize;
958
- this.activatePinchGesture();
959
- }
960
1066
  reset() {
961
- this.imageVisible = false;
962
- this.loadedImage = undefined;
963
- this.safeImgDataUrl = 'data:image/png;base64,iVBORw0KGg'
1067
+ this.safeImgDataUrl.set('data:image/png;base64,iVBORw0KGg'
964
1068
  + 'oAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAU'
965
- + 'AAarVyFEAAAAASUVORK5CYII=';
966
- this.moveStart = {
967
- active: false,
968
- type: null,
969
- position: null,
970
- x1: 0,
971
- y1: 0,
972
- x2: 0,
973
- y2: 0,
974
- clientX: 0,
975
- clientY: 0
976
- };
977
- this.maxSize = {
978
- width: 0,
979
- height: 0
980
- };
981
- this.cropper.x1 = -100;
982
- this.cropper.y1 = -100;
983
- this.cropper.x2 = 10000;
984
- this.cropper.y2 = 10000;
1069
+ + 'AAarVyFEAAAAASUVORK5CYII=');
1070
+ this.state.loadedImage = undefined;
1071
+ this.state.maxSize = undefined;
1072
+ this.imageVisible = false;
985
1073
  }
986
1074
  loadImageFile(file) {
987
1075
  this.loadImageService
988
- .loadImageFile(file, this.settings)
1076
+ .loadImageFile(file, this.state)
989
1077
  .then((res) => this.setLoadedImage(res))
990
1078
  .catch((err) => this.loadImageError(err));
991
1079
  }
992
1080
  loadBase64Image(imageBase64) {
993
1081
  this.loadImageService
994
- .loadBase64Image(imageBase64, this.settings)
1082
+ .loadBase64Image(imageBase64, this.state)
995
1083
  .then((res) => this.setLoadedImage(res))
996
1084
  .catch((err) => this.loadImageError(err));
997
1085
  }
998
1086
  loadImageFromURL(url) {
999
1087
  this.loadImageService
1000
- .loadImageFromURL(url, this.settings)
1088
+ .loadImageFromURL(url, this.state)
1001
1089
  .then((res) => this.setLoadedImage(res))
1002
1090
  .catch((err) => this.loadImageError(err));
1003
1091
  }
1004
1092
  setLoadedImage(loadedImage) {
1005
- this.loadedImage = loadedImage;
1006
- this.safeImgDataUrl = this.sanitizer.bypassSecurityTrustResourceUrl(loadedImage.transformed.objectUrl);
1007
- this.cd.markForCheck();
1093
+ this.state.loadedImage = loadedImage;
1094
+ this.safeImgDataUrl.set(this.sanitizer.bypassSecurityTrustResourceUrl(loadedImage.transformed.objectUrl));
1008
1095
  }
1009
1096
  loadImageError(error) {
1010
1097
  console.error(error);
1011
1098
  this.loadImageFailed.emit();
1012
1099
  }
1100
+ setCssTransform() {
1101
+ const translateUnit = this.state.transform?.translateUnit || '%';
1102
+ this.safeTransformStyle = this.sanitizer.bypassSecurityTrustStyle(`translate(${this.state.transform.translateH || 0}${translateUnit}, ${this.state.transform.translateV || 0}${translateUnit})` +
1103
+ ' scaleX(' + (this.state.transform.scale || 1) * (this.state.transform.flipH ? -1 : 1) + ')' +
1104
+ ' scaleY(' + (this.state.transform.scale || 1) * (this.state.transform.flipV ? -1 : 1) + ')' +
1105
+ ' rotate(' + (this.state.transform.rotate || 0) + 'deg)');
1106
+ }
1013
1107
  imageLoadedInView() {
1014
- if (this.loadedImage != null) {
1015
- this.imageLoaded.emit(this.loadedImage);
1108
+ if (this.state.loadedImage != null) {
1109
+ this.imageLoaded.emit(this.state.loadedImage);
1016
1110
  this.setImageMaxSizeRetries = 0;
1017
1111
  setTimeout(() => this.checkImageMaxSizeRecursively());
1018
1112
  }
@@ -1023,10 +1117,17 @@ class ImageCropperComponent {
1023
1117
  }
1024
1118
  else if (this.sourceImageLoaded()) {
1025
1119
  this.setMaxSize();
1026
- this.setCropperScaledMinSize();
1027
- this.setCropperScaledMaxSize();
1028
- this.resetCropperPosition();
1029
- this.cropperReady.emit({ ...this.maxSize });
1120
+ if (this.cropper && (!this.maintainAspectRatio || this.state.aspectRatioIsCorrect())) {
1121
+ this.state.cropper = checkCropperPosition(this.cropper, this.state, true);
1122
+ this.emitCropperPositionChange(this.cropper);
1123
+ }
1124
+ else {
1125
+ this.state.cropper = checkCropperPosition(this.state.maxSizeCropperPosition(), this.state, true);
1126
+ this.cropperChange.emit(this.state.cropper);
1127
+ }
1128
+ this.imageVisible = true;
1129
+ this.cropperReady.emit({ ...this.state.maxSize });
1130
+ this.doAutoCrop();
1030
1131
  this.cd.markForCheck();
1031
1132
  }
1032
1133
  else {
@@ -1035,51 +1136,22 @@ class ImageCropperComponent {
1035
1136
  }
1036
1137
  }
1037
1138
  sourceImageLoaded() {
1038
- return this.sourceImage?.nativeElement?.offsetWidth > 0;
1139
+ return this.sourceImage?.nativeElement?.offsetWidth > 1;
1039
1140
  }
1040
1141
  onResize() {
1041
- if (!this.loadedImage) {
1142
+ if (!this.state.loadedImage) {
1042
1143
  return;
1043
1144
  }
1044
1145
  if (this.hidden) {
1045
1146
  this.resizedWhileHidden = true;
1046
1147
  }
1047
1148
  else {
1048
- const oldMaxSize = { ...this.maxSize };
1149
+ const oldMaxSize = { ...this.state.maxSize };
1049
1150
  this.setMaxSize();
1050
- this.resizeCropperPosition(oldMaxSize);
1051
- this.setCropperScaledMinSize();
1052
- this.setCropperScaledMaxSize();
1053
- }
1054
- }
1055
- async activatePinchGesture() {
1056
- // Loads HammerJS via angular APIs if configured
1057
- await this.hammerLoader?.();
1058
- const Hammer = window?.['Hammer'] || null;
1059
- if (Hammer) {
1060
- const hammer = new Hammer(this.wrapper.nativeElement);
1061
- hammer.get('pinch').set({ enable: true });
1062
- hammer.on('pinchmove', this.onPinch.bind(this));
1063
- hammer.on('pinchend', this.pinchStop.bind(this));
1064
- hammer.on('pinchstart', this.startPinch.bind(this));
1065
- }
1066
- else if (isDevMode()) {
1067
- console.warn('[NgxImageCropper] Could not find HammerJS - Pinch Gesture won\'t work');
1068
- }
1069
- }
1070
- resizeCropperPosition(oldMaxSize) {
1071
- if (oldMaxSize.width !== this.maxSize.width || oldMaxSize.height !== this.maxSize.height) {
1072
- this.cropper.x1 = this.cropper.x1 * this.maxSize.width / oldMaxSize.width;
1073
- this.cropper.x2 = this.cropper.x2 * this.maxSize.width / oldMaxSize.width;
1074
- this.cropper.y1 = this.cropper.y1 * this.maxSize.height / oldMaxSize.height;
1075
- this.cropper.y2 = this.cropper.y2 * this.maxSize.height / oldMaxSize.height;
1151
+ this.state.resizeCropperPosition(oldMaxSize);
1152
+ this.cd.markForCheck();
1076
1153
  }
1077
1154
  }
1078
- resetCropperPosition() {
1079
- this.cropperPositionService.resetCropperPosition(this.sourceImage, this.cropper, this.settings, this.maxSize);
1080
- this.doAutoCrop();
1081
- this.imageVisible = true;
1082
- }
1083
1155
  keyboardAccess(event) {
1084
1156
  this.changeKeyboardStepSize(event);
1085
1157
  this.keyboardMoveCropper(event);
@@ -1087,7 +1159,7 @@ class ImageCropperComponent {
1087
1159
  changeKeyboardStepSize(event) {
1088
1160
  const key = +event.key;
1089
1161
  if (key >= 1 && key <= 9) {
1090
- this.settings.stepSize = key;
1162
+ this.state.stepSize = key;
1091
1163
  }
1092
1164
  }
1093
1165
  keyboardMoveCropper(event) {
@@ -1097,10 +1169,18 @@ class ImageCropperComponent {
1097
1169
  }
1098
1170
  const moveType = event.shiftKey ? MoveTypes.Resize : MoveTypes.Move;
1099
1171
  const position = event.altKey ? getInvertedPositionForKey(event.key) : getPositionForKey(event.key);
1100
- const moveEvent = getEventForKey(event.key, this.settings.stepSize);
1172
+ const moveEvent = getEventForKey(event.key, this.state.stepSize);
1101
1173
  event.preventDefault();
1102
1174
  event.stopPropagation();
1103
- this.startMove({ clientX: 0, clientY: 0 }, moveType, position);
1175
+ this.moveStart = {
1176
+ active: true,
1177
+ type: moveType,
1178
+ position,
1179
+ clientX: 0,
1180
+ clientY: 0,
1181
+ transform: this.state.transform,
1182
+ cropper: this.state.cropper
1183
+ };
1104
1184
  this.handleMouseMove(moveEvent);
1105
1185
  this.handleMouseUp();
1106
1186
  }
@@ -1117,16 +1197,15 @@ class ImageCropperComponent {
1117
1197
  active: true,
1118
1198
  type: moveType,
1119
1199
  position,
1120
- transform: { ...this.transform },
1121
- clientX: this.cropperPositionService.getClientX(event),
1122
- clientY: this.cropperPositionService.getClientY(event),
1123
- ...this.cropper
1200
+ clientX: getClientX(event),
1201
+ clientY: getClientY(event),
1202
+ transform: this.state.transform,
1203
+ cropper: this.state.cropper
1124
1204
  };
1125
1205
  this.initMouseMove();
1126
1206
  }
1127
1207
  initMouseMove() {
1128
- merge(fromEvent(document, 'mousemove'), fromEvent(document, 'touchmove')).pipe(takeUntil(merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend')).pipe(first())))
1129
- .subscribe({
1208
+ merge(fromEvent(document, 'mousemove'), fromEvent(document, 'touchmove')).pipe(takeUntil(merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend'), this.pinchStart$).pipe(first()))).subscribe({
1130
1209
  next: (event) => this.zone.run(() => {
1131
1210
  this.handleMouseMove(event);
1132
1211
  this.cd.markForCheck();
@@ -1137,162 +1216,125 @@ class ImageCropperComponent {
1137
1216
  })
1138
1217
  });
1139
1218
  }
1140
- startPinch(event) {
1141
- if (!this.safeImgDataUrl) {
1219
+ handleMouseMove(event) {
1220
+ if (!this.moveStart?.active) {
1142
1221
  return;
1143
1222
  }
1144
- if (event.preventDefault) {
1223
+ if ('stopPropagation' in event) {
1224
+ event.stopPropagation();
1225
+ }
1226
+ if ('preventDefault' in event) {
1145
1227
  event.preventDefault();
1146
1228
  }
1147
- this.moveStart = {
1148
- active: true,
1149
- type: MoveTypes.Pinch,
1150
- position: 'center',
1151
- clientX: this.cropper.x1 + (this.cropper.x2 - this.cropper.x1) / 2,
1152
- clientY: this.cropper.y1 + (this.cropper.y2 - this.cropper.y1) / 2,
1153
- ...this.cropper
1154
- };
1155
- }
1156
- handleMouseMove(event) {
1157
- if (this.moveStart.active) {
1158
- if ('stopPropagation' in event) {
1159
- event.stopPropagation();
1160
- }
1161
- if ('preventDefault' in event) {
1162
- event.preventDefault();
1163
- }
1164
- if (this.moveStart.type === MoveTypes.Move) {
1165
- this.cropperPositionService.move(event, this.moveStart, this.cropper);
1166
- this.checkCropperPosition(true);
1167
- }
1168
- else if (this.moveStart.type === MoveTypes.Resize) {
1169
- if (!this.cropperStaticWidth && !this.cropperStaticHeight) {
1170
- this.cropperPositionService.resize(event, this.moveStart, this.cropper, this.maxSize, this.settings);
1171
- }
1172
- this.checkCropperPosition(false);
1173
- }
1174
- else if (this.moveStart.type === MoveTypes.Drag) {
1175
- const diffX = this.cropperPositionService.getClientX(event) - this.moveStart.clientX;
1176
- const diffY = this.cropperPositionService.getClientY(event) - this.moveStart.clientY;
1177
- this.transform = {
1178
- ...this.transform,
1179
- translateH: (this.moveStart.transform?.translateH || 0) + diffX,
1180
- translateV: (this.moveStart.transform?.translateV || 0) + diffY
1181
- };
1182
- this.setCssTransform();
1229
+ if (this.moveStart.type === MoveTypes.Move) {
1230
+ this.state.cropper = checkCropperWithinMaxSizeBounds(moveCropper(event, this.moveStart), this.state, true);
1231
+ }
1232
+ else if (this.moveStart.type === MoveTypes.Resize) {
1233
+ if (!this.cropperStaticWidth && !this.cropperStaticHeight) {
1234
+ this.state.cropper = checkCropperWithinMaxSizeBounds(resizeCropper(event, this.moveStart, this.state), this.state, false);
1183
1235
  }
1184
1236
  }
1237
+ else if (this.moveStart.type === MoveTypes.Drag) {
1238
+ const diffX = getClientX(event) - this.moveStart.clientX;
1239
+ const diffY = getClientY(event) - this.moveStart.clientY;
1240
+ this.state.transform = {
1241
+ ...this.state.transform,
1242
+ translateH: (this.moveStart.transform?.translateH || 0) + diffX,
1243
+ translateV: (this.moveStart.transform?.translateV || 0) + diffY
1244
+ };
1245
+ this.setCssTransform();
1246
+ }
1185
1247
  }
1186
- onPinch(event) {
1187
- if (this.moveStart.active) {
1188
- if (event.stopPropagation) {
1189
- event.stopPropagation();
1190
- }
1191
- if (event.preventDefault) {
1192
- event.preventDefault();
1248
+ handleMouseUp() {
1249
+ if (!this.moveStart?.active || this.moveStart?.type === MoveTypes.Pinch) {
1250
+ return;
1251
+ }
1252
+ if (!this.state.equalsCropperPosition(this.moveStart.cropper) || this.moveStart.transform && !this.state.equalsTransform(this.moveStart.transform)) {
1253
+ if (this.moveStart.type === MoveTypes.Drag) {
1254
+ this.transformChange.emit(this.state.transform);
1193
1255
  }
1194
- if (this.moveStart.type === MoveTypes.Pinch) {
1195
- this.cropperPositionService.resize(event, this.moveStart, this.cropper, this.maxSize, this.settings);
1196
- this.checkCropperPosition(false);
1256
+ else {
1257
+ this.cropperChange.emit(this.state.cropper);
1197
1258
  }
1198
- this.cd.markForCheck();
1199
- }
1200
- }
1201
- setMaxSize() {
1202
- if (this.sourceImage) {
1203
- const sourceImageStyle = getComputedStyle(this.sourceImage.nativeElement);
1204
- this.maxSize.width = parseFloat(sourceImageStyle.width);
1205
- this.maxSize.height = parseFloat(sourceImageStyle.height);
1206
- this.marginLeft = this.sanitizer.bypassSecurityTrustStyle('calc(50% - ' + this.maxSize.width / 2 + 'px)');
1259
+ this.doAutoCrop();
1207
1260
  }
1261
+ this.moveStart = undefined;
1208
1262
  }
1209
- setCropperScaledMinSize() {
1210
- if (this.loadedImage?.transformed?.image) {
1211
- this.setCropperScaledMinWidth();
1212
- this.setCropperScaledMinHeight();
1263
+ startPinch(event) {
1264
+ if (this.disabled || !this.sourceImageLoaded() || event.touches.length < 2) {
1265
+ return;
1213
1266
  }
1214
- else {
1215
- this.settings.cropperScaledMinWidth = 20;
1216
- this.settings.cropperScaledMinHeight = 20;
1267
+ if ('preventDefault' in event) {
1268
+ event.preventDefault();
1217
1269
  }
1270
+ this.moveStart = {
1271
+ active: true,
1272
+ type: MoveTypes.Pinch,
1273
+ position: 'center',
1274
+ clientX: this.state.cropper.x1 + (this.state.cropper.x2 - this.state.cropper.x1) / 2,
1275
+ clientY: this.state.cropper.y1 + (this.state.cropper.y2 - this.state.cropper.y1) / 2,
1276
+ cropper: this.state.cropper
1277
+ };
1278
+ this.initPinch();
1218
1279
  }
1219
- setCropperScaledMinWidth() {
1220
- this.settings.cropperScaledMinWidth = this.cropperMinWidth > 0
1221
- ? Math.max(20, this.cropperMinWidth / this.loadedImage.transformed.image.width * this.maxSize.width)
1222
- : 20;
1280
+ initPinch() {
1281
+ this.pinchStart$.next();
1282
+ fromEvent(document, 'touchmove')
1283
+ .pipe(takeUntil(fromEvent(document, 'touchend')))
1284
+ .subscribe({
1285
+ next: (event) => this.zone.run(() => {
1286
+ this.handlePinchMove(event);
1287
+ this.cd.markForCheck();
1288
+ }),
1289
+ complete: () => this.zone.run(() => {
1290
+ this.handlePinchStop();
1291
+ this.cd.markForCheck();
1292
+ })
1293
+ });
1223
1294
  }
1224
- setCropperScaledMinHeight() {
1225
- if (this.maintainAspectRatio) {
1226
- this.settings.cropperScaledMinHeight = Math.max(20, this.settings.cropperScaledMinWidth / this.aspectRatio);
1227
- }
1228
- else if (this.cropperMinHeight > 0) {
1229
- this.settings.cropperScaledMinHeight = Math.max(20, this.cropperMinHeight / this.loadedImage.transformed.image.height * this.maxSize.height);
1295
+ handlePinchMove(event) {
1296
+ if (!this.moveStart?.active) {
1297
+ return;
1230
1298
  }
1231
- else {
1232
- this.settings.cropperScaledMinHeight = 20;
1299
+ if (event.preventDefault) {
1300
+ event.preventDefault();
1233
1301
  }
1234
- }
1235
- setCropperScaledMaxSize() {
1236
- if (this.loadedImage?.transformed?.image) {
1237
- const ratio = this.loadedImage.transformed.size.width / this.maxSize.width;
1238
- this.settings.cropperScaledMaxWidth = this.cropperMaxWidth > 20 ? this.cropperMaxWidth / ratio : this.maxSize.width;
1239
- this.settings.cropperScaledMaxHeight = this.cropperMaxHeight > 20 ? this.cropperMaxHeight / ratio : this.maxSize.height;
1240
- if (this.maintainAspectRatio) {
1241
- if (this.settings.cropperScaledMaxWidth > this.settings.cropperScaledMaxHeight * this.aspectRatio) {
1242
- this.settings.cropperScaledMaxWidth = this.settings.cropperScaledMaxHeight * this.aspectRatio;
1243
- }
1244
- else if (this.settings.cropperScaledMaxWidth < this.settings.cropperScaledMaxHeight * this.aspectRatio) {
1245
- this.settings.cropperScaledMaxHeight = this.settings.cropperScaledMaxWidth / this.aspectRatio;
1246
- }
1302
+ if (this.moveStart.type === MoveTypes.Pinch) {
1303
+ if (!this.cropperStaticWidth && !this.cropperStaticHeight) {
1304
+ this.state.cropper = checkCropperWithinMaxSizeBounds(resizeCropper(event, this.moveStart, this.state), this.state, false);
1247
1305
  }
1248
1306
  }
1249
- else {
1250
- this.settings.cropperScaledMaxWidth = this.maxSize.width;
1251
- this.settings.cropperScaledMaxHeight = this.maxSize.height;
1252
- }
1307
+ this.cd.markForCheck();
1253
1308
  }
1254
- checkCropperPosition(maintainSize = false) {
1255
- if (this.cropper.x1 < 0) {
1256
- this.cropper.x2 -= maintainSize ? this.cropper.x1 : 0;
1257
- this.cropper.x1 = 0;
1258
- }
1259
- if (this.cropper.y1 < 0) {
1260
- this.cropper.y2 -= maintainSize ? this.cropper.y1 : 0;
1261
- this.cropper.y1 = 0;
1262
- }
1263
- if (this.cropper.x2 > this.maxSize.width) {
1264
- this.cropper.x1 -= maintainSize ? (this.cropper.x2 - this.maxSize.width) : 0;
1265
- this.cropper.x2 = this.maxSize.width;
1309
+ handlePinchStop() {
1310
+ if (!this.moveStart?.active) {
1311
+ return;
1266
1312
  }
1267
- if (this.cropper.y2 > this.maxSize.height) {
1268
- this.cropper.y1 -= maintainSize ? (this.cropper.y2 - this.maxSize.height) : 0;
1269
- this.cropper.y2 = this.maxSize.height;
1313
+ if (!this.state.equalsCropperPosition(this.moveStart.cropper)) {
1314
+ this.emitCropperPositionChange(this.moveStart.cropper);
1315
+ this.doAutoCrop();
1270
1316
  }
1317
+ this.moveStart = undefined;
1271
1318
  }
1272
- handleMouseUp() {
1273
- if (this.moveStart.active) {
1274
- this.moveStart.active = false;
1275
- if (this.moveStart?.type === MoveTypes.Drag) {
1276
- this.transformChange.emit(this.transform);
1277
- }
1278
- else {
1279
- this.doAutoCrop();
1280
- }
1319
+ setMaxSize() {
1320
+ if (this.sourceImage) {
1321
+ const sourceImageStyle = getComputedStyle(this.sourceImage.nativeElement);
1322
+ this.state.setMaxSize(parseFloat(sourceImageStyle.width), parseFloat(sourceImageStyle.height));
1323
+ this.marginLeft = this.sanitizer.bypassSecurityTrustStyle('calc(50% - ' + this.state.maxSize.width / 2 + 'px)');
1281
1324
  }
1282
1325
  }
1283
- pinchStop() {
1284
- if (this.moveStart.active) {
1285
- this.moveStart.active = false;
1286
- this.doAutoCrop();
1326
+ emitCropperPositionChange(previousPosition) {
1327
+ if (!this.state.equalsCropperPosition(previousPosition)) {
1328
+ this.cropperChange.emit(this.state.cropper);
1287
1329
  }
1288
1330
  }
1289
1331
  doAutoCrop() {
1290
- if (this.autoCrop) {
1332
+ if (this.state.options.autoCrop) {
1291
1333
  void this.crop();
1292
1334
  }
1293
1335
  }
1294
- crop(output = this.settings.output) {
1295
- if (this.loadedImage?.transformed?.image != null) {
1336
+ crop(output = this.state.options.output) {
1337
+ if (this.state.loadedImage?.transformed?.image != null) {
1296
1338
  this.startCropImage.emit();
1297
1339
  if (output === 'blob') {
1298
1340
  return this.cropToBlob();
@@ -1305,7 +1347,7 @@ class ImageCropperComponent {
1305
1347
  }
1306
1348
  cropToBlob() {
1307
1349
  return new Promise((resolve, reject) => this.zone.run(async () => {
1308
- const result = await this.cropService.crop(this.loadedImage, this.cropper, this.settings, 'blob', this.maxSize);
1350
+ const result = await this.cropService.crop(this.state, 'blob');
1309
1351
  if (result) {
1310
1352
  this.imageCropped.emit(result);
1311
1353
  resolve(result);
@@ -1316,29 +1358,27 @@ class ImageCropperComponent {
1316
1358
  }));
1317
1359
  }
1318
1360
  cropToBase64() {
1319
- const result = this.cropService.crop(this.loadedImage, this.cropper, this.settings, 'base64', this.maxSize);
1361
+ const result = this.cropService.crop(this.state, 'base64');
1320
1362
  if (result) {
1321
1363
  this.imageCropped.emit(result);
1322
1364
  return result;
1323
1365
  }
1324
1366
  return null;
1325
1367
  }
1326
- aspectRatioIsCorrect() {
1327
- const currentCropAspectRatio = (this.cropper.x2 - this.cropper.x1) / (this.cropper.y2 - this.cropper.y1);
1328
- return currentCropAspectRatio === this.aspectRatio;
1368
+ resetCropperPosition() {
1369
+ this.state.cropper = checkCropperPosition(this.state.maxSizeCropperPosition(), this.state, true);
1370
+ this.cropperChange.emit(this.state.cropper);
1329
1371
  }
1330
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageCropperComponent, deps: [{ token: CropService }, { token: CropperPositionService }, { token: LoadImageService }, { token: i4.DomSanitizer }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: HAMMER_LOADER, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
1331
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ImageCropperComponent, isStandalone: true, selector: "image-cropper", inputs: { imageChangedEvent: "imageChangedEvent", imageURL: "imageURL", imageBase64: "imageBase64", imageFile: "imageFile", imageAltText: "imageAltText", cropperFrameAriaLabel: "cropperFrameAriaLabel", output: "output", format: "format", transform: "transform", maintainAspectRatio: "maintainAspectRatio", aspectRatio: "aspectRatio", resetCropOnAspectRatioChange: "resetCropOnAspectRatioChange", resizeToWidth: "resizeToWidth", resizeToHeight: "resizeToHeight", cropperMinWidth: "cropperMinWidth", cropperMinHeight: "cropperMinHeight", cropperMaxHeight: "cropperMaxHeight", cropperMaxWidth: "cropperMaxWidth", cropperStaticWidth: "cropperStaticWidth", cropperStaticHeight: "cropperStaticHeight", canvasRotation: "canvasRotation", initialStepSize: "initialStepSize", roundCropper: "roundCropper", onlyScaleDown: "onlyScaleDown", imageQuality: "imageQuality", autoCrop: "autoCrop", backgroundColor: "backgroundColor", containWithinAspectRatio: "containWithinAspectRatio", hideResizeSquares: "hideResizeSquares", allowMoveImage: "allowMoveImage", cropper: "cropper", alignImage: "alignImage", disabled: "disabled", hidden: "hidden" }, outputs: { imageCropped: "imageCropped", startCropImage: "startCropImage", imageLoaded: "imageLoaded", cropperReady: "cropperReady", loadImageFailed: "loadImageFailed", transformChange: "transformChange" }, host: { listeners: { "window:resize": "onResize()" }, properties: { "style.text-align": "this.alignImage", "class.disabled": "this.disabled", "class.ngx-ix-hidden": "this.hidden" } }, viewQueries: [{ propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true, static: true }, { propertyName: "sourceImage", first: true, predicate: ["sourceImage"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n [style.background]=\"imageVisible && backgroundColor\"\n #wrapper\n>\n <img\n #sourceImage\n class=\"ngx-ic-source-image\"\n role=\"presentation\"\n *ngIf=\"safeImgDataUrl\"\n [src]=\"safeImgDataUrl\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n [style.transform]=\"safeTransformStyle\"\n [class.ngx-ic-draggable]=\"!disabled && allowMoveImage\"\n [attr.alt]=\"imageAltText\"\n (load)=\"imageLoadedInView()\"\n (mousedown)=\"startMove($event, moveTypes.Drag)\"\n (touchstart)=\"startMove($event, moveTypes.Drag)\"\n (error)=\"loadImageError($event)\"\n >\n <div\n class=\"ngx-ic-overlay\"\n [style.width.px]=\"maxSize.width\"\n [style.height.px]=\"maxSize.height\"\n [style.margin-left]=\"alignImage === 'center' ? marginLeft : null\"\n ></div>\n <div class=\"ngx-ic-cropper\"\n *ngIf=\"imageVisible\"\n [class.ngx-ic-round]=\"roundCropper\"\n [attr.aria-label]=\"cropperFrameAriaLabel\"\n [style.top.px]=\"cropper.y1\"\n [style.left.px]=\"cropper.x1\"\n [style.width.px]=\"cropper.x2 - cropper.x1\"\n [style.height.px]=\"cropper.y2 - cropper.y1\"\n [style.margin-left]=\"alignImage === 'center' ? marginLeft : null\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n (keydown)=\"keyboardAccess($event)\"\n tabindex=\"0\"\n >\n <div\n (mousedown)=\"startMove($event, moveTypes.Move)\"\n (touchstart)=\"startMove($event, moveTypes.Move)\"\n class=\"ngx-ic-move\"\n role=\"presentation\">\n </div>\n <ng-container *ngIf=\"!hideResizeSquares\">\n <span class=\"ngx-ic-resize ngx-ic-topleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topleft')\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-top\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-topright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topright')\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-right\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottomright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomright')\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottom\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottomleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomleft')\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-left\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize-bar ngx-ic-top\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'top')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'top')\">\n </span>\n <span class=\"ngx-ic-resize-bar ngx-ic-right\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'right')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'right')\">\n </span>\n <span class=\"ngx-ic-resize-bar ngx-ic-bottom\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottom')\">\n </span>\n <span class=\"ngx-ic-resize-bar ngx-ic-left\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'left')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'left')\">\n </span>\n </ng-container>\n </div>\n</div>\n", styles: [":host{display:flex;position:relative;width:100%;max-width:100%;max-height:100%;overflow:hidden;padding:5px;text-align:center}:host>div{width:100%;position:relative}:host>div img.ngx-ic-source-image{max-width:100%;max-height:100%;transform-origin:center}:host>div img.ngx-ic-source-image.ngx-ic-draggable{user-drag:none;-webkit-user-drag:none;user-select:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;cursor:grab}:host .ngx-ic-overlay{position:absolute;pointer-events:none;touch-action:none;outline:var(--cropper-overlay-color, white) solid 100vw;top:0;left:0}:host .ngx-ic-cropper{position:absolute;display:flex;color:#53535c;background:transparent;outline:rgba(255,255,255,.3) solid 100vw;outline:var(--cropper-outline-color, rgba(255, 255, 255, .3)) solid 100vw;touch-action:none}@media (orientation: portrait){:host .ngx-ic-cropper{outline-width:100vh}}:host .ngx-ic-cropper:after{position:absolute;content:\"\";inset:0;pointer-events:none;border:dashed 1px;opacity:.75;color:inherit;z-index:1}:host .ngx-ic-cropper .ngx-ic-move{width:100%;cursor:move;border:1px solid rgba(255,255,255,.5)}:host .ngx-ic-cropper:focus .ngx-ic-move{border-color:#1e90ff;border-width:2px}:host .ngx-ic-cropper .ngx-ic-resize{position:absolute;display:inline-block;line-height:6px;padding:8px;opacity:.85;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize .ngx-ic-square{display:inline-block;background:#53535c;width:6px;height:6px;border:1px solid rgba(255,255,255,.5);box-sizing:content-box}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topleft{top:-12px;left:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-top{top:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topright{top:-12px;right:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-right{top:calc(50% - 12px);right:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomright{bottom:-12px;right:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottom{bottom:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomleft{bottom:-12px;left:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-left{top:calc(50% - 12px);left:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar{position:absolute;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-top{top:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-right{top:11px;right:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-bottom{bottom:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-left{top:11px;left:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper.ngx-ic-round{outline-color:transparent}:host .ngx-ic-cropper.ngx-ic-round:after{border-radius:100%;box-shadow:0 0 0 100vw #ffffff4d;box-shadow:0 0 0 100vw var(--cropper-outline-color, rgba(255, 255, 255, .3))}@media (orientation: portrait){:host .ngx-ic-cropper.ngx-ic-round:after{box-shadow:0 0 0 100vh #ffffff4d;box-shadow:0 0 0 100vh var(--cropper-outline-color, rgba(255, 255, 255, .3))}}:host .ngx-ic-cropper.ngx-ic-round .ngx-ic-move{border-radius:100%}:host.disabled .ngx-ic-cropper .ngx-ic-resize,:host.disabled .ngx-ic-cropper .ngx-ic-resize-bar,:host.disabled .ngx-ic-cropper .ngx-ic-move{display:none}:host.ngx-ix-hidden{display:none}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1372
+ ngOnDestroy() {
1373
+ this.pinchStart$.complete();
1374
+ }
1375
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ImageCropperComponent, deps: [{ token: i1.DomSanitizer }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
1376
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ImageCropperComponent, isStandalone: true, selector: "image-cropper", inputs: { imageChangedEvent: "imageChangedEvent", imageURL: "imageURL", imageBase64: "imageBase64", imageFile: "imageFile", imageAltText: "imageAltText", options: "options", cropperFrameAriaLabel: "cropperFrameAriaLabel", output: "output", format: "format", autoCrop: "autoCrop", cropper: "cropper", transform: "transform", maintainAspectRatio: "maintainAspectRatio", aspectRatio: "aspectRatio", resetCropOnAspectRatioChange: "resetCropOnAspectRatioChange", resizeToWidth: "resizeToWidth", resizeToHeight: "resizeToHeight", cropperMinWidth: "cropperMinWidth", cropperMinHeight: "cropperMinHeight", cropperMaxHeight: "cropperMaxHeight", cropperMaxWidth: "cropperMaxWidth", cropperStaticWidth: "cropperStaticWidth", cropperStaticHeight: "cropperStaticHeight", canvasRotation: "canvasRotation", initialStepSize: "initialStepSize", roundCropper: "roundCropper", onlyScaleDown: "onlyScaleDown", imageQuality: "imageQuality", backgroundColor: "backgroundColor", containWithinAspectRatio: "containWithinAspectRatio", hideResizeSquares: "hideResizeSquares", allowMoveImage: "allowMoveImage", checkImageType: "checkImageType", alignImage: "alignImage", disabled: "disabled", hidden: "hidden" }, outputs: { imageCropped: "imageCropped", startCropImage: "startCropImage", imageLoaded: "imageLoaded", cropperReady: "cropperReady", loadImageFailed: "loadImageFailed", transformChange: "transformChange", cropperChange: "cropperChange" }, host: { listeners: { "window:resize": "onResize()" }, properties: { "class.disabled": "this.disabled", "class.ngx-ic-hidden": "this.hidden", "style.text-align": "this.alignImageStyle" } }, viewQueries: [{ propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true, static: true }, { propertyName: "sourceImage", first: true, predicate: ["sourceImage"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n [style.background]=\"imageVisible && state.options.backgroundColor\"\n (touchstart)=\"startPinch($event)\"\n>\n <img\n #sourceImage\n class=\"ngx-ic-source-image\"\n role=\"presentation\"\n *ngIf=\"safeImgDataUrl() as src\"\n [src]=\"src\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n [style.transform]=\"safeTransformStyle\"\n [class.ngx-ic-draggable]=\"!disabled && allowMoveImage\"\n [attr.alt]=\"imageAltText\"\n (load)=\"imageLoadedInView()\"\n (mousedown)=\"startMove($event, moveTypes.Drag)\"\n (touchstart)=\"startMove($event, moveTypes.Drag)\"\n (error)=\"loadImageError($event)\"\n >\n <div\n class=\"ngx-ic-overlay\"\n [style.width.px]=\"state.maxSize?.width || 0\"\n [style.height.px]=\"state.maxSize?.height || 0\"\n [style.margin-left]=\"alignImage === 'center' ? marginLeft : null\"\n ></div>\n <div\n class=\"ngx-ic-cropper\"\n *ngIf=\"imageVisible\"\n [class.ngx-ic-round]=\"state.options.roundCropper\"\n [attr.aria-label]=\"state.options.cropperFrameAriaLabel\"\n [style.top.px]=\"state.cropper.y1\"\n [style.left.px]=\"state.cropper.x1\"\n [style.width.px]=\"state.cropper.x2 - state.cropper.x1\"\n [style.height.px]=\"state.cropper.y2 - state.cropper.y1\"\n [style.margin-left]=\"state.options.alignImage === 'center' ? marginLeft : null\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n (keydown)=\"keyboardAccess($event)\"\n tabindex=\"0\"\n >\n <div\n (mousedown)=\"startMove($event, moveTypes.Move)\"\n (touchstart)=\"startMove($event, moveTypes.Move)\"\n class=\"ngx-ic-move\"\n role=\"presentation\">\n </div>\n <ng-container\n *ngIf=\"!state.options.hideResizeSquares && !(state.options.cropperStaticWidth && state.options.cropperStaticHeight)\">\n <span\n class=\"ngx-ic-resize ngx-ic-topleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-top\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-topright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topright')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-right\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-bottomright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottom\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-bottomleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-left\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-top\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'top')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'top')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-right\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'right')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'right')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-bottom\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-left\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'left')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'left')\"\n ></span>\n </ng-container>\n </div>\n</div>\n", styles: [":host{display:flex;position:relative;width:100%;max-width:100%;max-height:100%;overflow:hidden;padding:5px;text-align:center}:host>div{width:100%;position:relative}:host>div img.ngx-ic-source-image{max-width:100%;max-height:100%;transform-origin:center}:host>div img.ngx-ic-source-image.ngx-ic-draggable{user-drag:none;-webkit-user-drag:none;user-select:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;cursor:grab}:host .ngx-ic-overlay{position:absolute;pointer-events:none;touch-action:none;outline:var(--cropper-overlay-color, white) solid 100vw;top:0;left:0}:host .ngx-ic-cropper{position:absolute;display:flex;color:#53535c;background:transparent;outline:rgba(255,255,255,.3) solid 100vw;outline:var(--cropper-outline-color, rgba(255, 255, 255, .3)) solid 100vw;touch-action:none}@media (orientation: portrait){:host .ngx-ic-cropper{outline-width:100vh}}:host .ngx-ic-cropper:after{position:absolute;content:\"\";inset:0;pointer-events:none;border:dashed 1px;opacity:.75;color:inherit;z-index:1}:host .ngx-ic-cropper .ngx-ic-move{width:100%;cursor:move;border:var(--cropper-move-border, 1px solid rgba(255, 255, 255, .5))}:host .ngx-ic-cropper:focus .ngx-ic-move{border-color:#1e90ff;border-width:2px}:host .ngx-ic-cropper .ngx-ic-resize{position:absolute;display:inline-block;line-height:6px;padding:8px;opacity:.85;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize .ngx-ic-square{display:inline-block;background:#53535c;width:6px;height:6px;border:1px solid rgba(255,255,255,.5);box-sizing:content-box}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topleft{top:-12px;left:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-top{top:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topright{top:-12px;right:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-right{top:calc(50% - 12px);right:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomright{bottom:-12px;right:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottom{bottom:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomleft{bottom:-12px;left:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-left{top:calc(50% - 12px);left:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar{position:absolute;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-top{top:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-right{top:11px;right:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-bottom{bottom:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-left{top:11px;left:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper.ngx-ic-round{outline-color:transparent}:host .ngx-ic-cropper.ngx-ic-round:after{border-radius:100%;box-shadow:0 0 0 100vw #ffffff4d;box-shadow:0 0 0 100vw var(--cropper-outline-color, rgba(255, 255, 255, .3))}@media (orientation: portrait){:host .ngx-ic-cropper.ngx-ic-round:after{box-shadow:0 0 0 100vh #ffffff4d;box-shadow:0 0 0 100vh var(--cropper-outline-color, rgba(255, 255, 255, .3))}}:host .ngx-ic-cropper.ngx-ic-round .ngx-ic-move{border-radius:100%}:host.disabled .ngx-ic-cropper .ngx-ic-resize,:host.disabled .ngx-ic-cropper .ngx-ic-resize-bar,:host.disabled .ngx-ic-cropper .ngx-ic-move{display:none}:host.ngx-ic-hidden{display:none}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1332
1377
  }
1333
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ImageCropperComponent, decorators: [{
1378
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ImageCropperComponent, decorators: [{
1334
1379
  type: Component,
1335
- args: [{ selector: 'image-cropper', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgIf], template: "<div\n [style.background]=\"imageVisible && backgroundColor\"\n #wrapper\n>\n <img\n #sourceImage\n class=\"ngx-ic-source-image\"\n role=\"presentation\"\n *ngIf=\"safeImgDataUrl\"\n [src]=\"safeImgDataUrl\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n [style.transform]=\"safeTransformStyle\"\n [class.ngx-ic-draggable]=\"!disabled && allowMoveImage\"\n [attr.alt]=\"imageAltText\"\n (load)=\"imageLoadedInView()\"\n (mousedown)=\"startMove($event, moveTypes.Drag)\"\n (touchstart)=\"startMove($event, moveTypes.Drag)\"\n (error)=\"loadImageError($event)\"\n >\n <div\n class=\"ngx-ic-overlay\"\n [style.width.px]=\"maxSize.width\"\n [style.height.px]=\"maxSize.height\"\n [style.margin-left]=\"alignImage === 'center' ? marginLeft : null\"\n ></div>\n <div class=\"ngx-ic-cropper\"\n *ngIf=\"imageVisible\"\n [class.ngx-ic-round]=\"roundCropper\"\n [attr.aria-label]=\"cropperFrameAriaLabel\"\n [style.top.px]=\"cropper.y1\"\n [style.left.px]=\"cropper.x1\"\n [style.width.px]=\"cropper.x2 - cropper.x1\"\n [style.height.px]=\"cropper.y2 - cropper.y1\"\n [style.margin-left]=\"alignImage === 'center' ? marginLeft : null\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n (keydown)=\"keyboardAccess($event)\"\n tabindex=\"0\"\n >\n <div\n (mousedown)=\"startMove($event, moveTypes.Move)\"\n (touchstart)=\"startMove($event, moveTypes.Move)\"\n class=\"ngx-ic-move\"\n role=\"presentation\">\n </div>\n <ng-container *ngIf=\"!hideResizeSquares\">\n <span class=\"ngx-ic-resize ngx-ic-topleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topleft')\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-top\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-topright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topright')\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-right\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottomright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomright')\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottom\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottomleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomleft')\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-left\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize-bar ngx-ic-top\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'top')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'top')\">\n </span>\n <span class=\"ngx-ic-resize-bar ngx-ic-right\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'right')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'right')\">\n </span>\n <span class=\"ngx-ic-resize-bar ngx-ic-bottom\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottom')\">\n </span>\n <span class=\"ngx-ic-resize-bar ngx-ic-left\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'left')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'left')\">\n </span>\n </ng-container>\n </div>\n</div>\n", styles: [":host{display:flex;position:relative;width:100%;max-width:100%;max-height:100%;overflow:hidden;padding:5px;text-align:center}:host>div{width:100%;position:relative}:host>div img.ngx-ic-source-image{max-width:100%;max-height:100%;transform-origin:center}:host>div img.ngx-ic-source-image.ngx-ic-draggable{user-drag:none;-webkit-user-drag:none;user-select:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;cursor:grab}:host .ngx-ic-overlay{position:absolute;pointer-events:none;touch-action:none;outline:var(--cropper-overlay-color, white) solid 100vw;top:0;left:0}:host .ngx-ic-cropper{position:absolute;display:flex;color:#53535c;background:transparent;outline:rgba(255,255,255,.3) solid 100vw;outline:var(--cropper-outline-color, rgba(255, 255, 255, .3)) solid 100vw;touch-action:none}@media (orientation: portrait){:host .ngx-ic-cropper{outline-width:100vh}}:host .ngx-ic-cropper:after{position:absolute;content:\"\";inset:0;pointer-events:none;border:dashed 1px;opacity:.75;color:inherit;z-index:1}:host .ngx-ic-cropper .ngx-ic-move{width:100%;cursor:move;border:1px solid rgba(255,255,255,.5)}:host .ngx-ic-cropper:focus .ngx-ic-move{border-color:#1e90ff;border-width:2px}:host .ngx-ic-cropper .ngx-ic-resize{position:absolute;display:inline-block;line-height:6px;padding:8px;opacity:.85;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize .ngx-ic-square{display:inline-block;background:#53535c;width:6px;height:6px;border:1px solid rgba(255,255,255,.5);box-sizing:content-box}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topleft{top:-12px;left:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-top{top:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topright{top:-12px;right:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-right{top:calc(50% - 12px);right:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomright{bottom:-12px;right:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottom{bottom:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomleft{bottom:-12px;left:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-left{top:calc(50% - 12px);left:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar{position:absolute;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-top{top:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-right{top:11px;right:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-bottom{bottom:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-left{top:11px;left:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper.ngx-ic-round{outline-color:transparent}:host .ngx-ic-cropper.ngx-ic-round:after{border-radius:100%;box-shadow:0 0 0 100vw #ffffff4d;box-shadow:0 0 0 100vw var(--cropper-outline-color, rgba(255, 255, 255, .3))}@media (orientation: portrait){:host .ngx-ic-cropper.ngx-ic-round:after{box-shadow:0 0 0 100vh #ffffff4d;box-shadow:0 0 0 100vh var(--cropper-outline-color, rgba(255, 255, 255, .3))}}:host .ngx-ic-cropper.ngx-ic-round .ngx-ic-move{border-radius:100%}:host.disabled .ngx-ic-cropper .ngx-ic-resize,:host.disabled .ngx-ic-cropper .ngx-ic-resize-bar,:host.disabled .ngx-ic-cropper .ngx-ic-move{display:none}:host.ngx-ix-hidden{display:none}\n"] }]
1336
- }], ctorParameters: function () { return [{ type: CropService }, { type: CropperPositionService }, { type: LoadImageService }, { type: i4.DomSanitizer }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: undefined, decorators: [{
1337
- type: Optional
1338
- }, {
1339
- type: Inject,
1340
- args: [HAMMER_LOADER]
1341
- }] }]; }, propDecorators: { wrapper: [{
1380
+ args: [{ selector: 'image-cropper', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgIf], template: "<div\n [style.background]=\"imageVisible && state.options.backgroundColor\"\n (touchstart)=\"startPinch($event)\"\n>\n <img\n #sourceImage\n class=\"ngx-ic-source-image\"\n role=\"presentation\"\n *ngIf=\"safeImgDataUrl() as src\"\n [src]=\"src\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n [style.transform]=\"safeTransformStyle\"\n [class.ngx-ic-draggable]=\"!disabled && allowMoveImage\"\n [attr.alt]=\"imageAltText\"\n (load)=\"imageLoadedInView()\"\n (mousedown)=\"startMove($event, moveTypes.Drag)\"\n (touchstart)=\"startMove($event, moveTypes.Drag)\"\n (error)=\"loadImageError($event)\"\n >\n <div\n class=\"ngx-ic-overlay\"\n [style.width.px]=\"state.maxSize?.width || 0\"\n [style.height.px]=\"state.maxSize?.height || 0\"\n [style.margin-left]=\"alignImage === 'center' ? marginLeft : null\"\n ></div>\n <div\n class=\"ngx-ic-cropper\"\n *ngIf=\"imageVisible\"\n [class.ngx-ic-round]=\"state.options.roundCropper\"\n [attr.aria-label]=\"state.options.cropperFrameAriaLabel\"\n [style.top.px]=\"state.cropper.y1\"\n [style.left.px]=\"state.cropper.x1\"\n [style.width.px]=\"state.cropper.x2 - state.cropper.x1\"\n [style.height.px]=\"state.cropper.y2 - state.cropper.y1\"\n [style.margin-left]=\"state.options.alignImage === 'center' ? marginLeft : null\"\n [style.visibility]=\"imageVisible ? 'visible' : 'hidden'\"\n (keydown)=\"keyboardAccess($event)\"\n tabindex=\"0\"\n >\n <div\n (mousedown)=\"startMove($event, moveTypes.Move)\"\n (touchstart)=\"startMove($event, moveTypes.Move)\"\n class=\"ngx-ic-move\"\n role=\"presentation\">\n </div>\n <ng-container\n *ngIf=\"!state.options.hideResizeSquares && !(state.options.cropperStaticWidth && state.options.cropperStaticHeight)\">\n <span\n class=\"ngx-ic-resize ngx-ic-topleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topleft')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-top\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-topright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'topright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'topright')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-right\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-bottomright\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomright')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-bottom\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize ngx-ic-bottomleft\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottomleft')\"\n >\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span class=\"ngx-ic-resize ngx-ic-left\">\n <span class=\"ngx-ic-square\"></span>\n </span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-top\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'top')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'top')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-right\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'right')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'right')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-bottom\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'bottom')\"\n ></span>\n <span\n class=\"ngx-ic-resize-bar ngx-ic-left\"\n role=\"presentation\"\n (mousedown)=\"startMove($event, moveTypes.Resize, 'left')\"\n (touchstart)=\"startMove($event, moveTypes.Resize, 'left')\"\n ></span>\n </ng-container>\n </div>\n</div>\n", styles: [":host{display:flex;position:relative;width:100%;max-width:100%;max-height:100%;overflow:hidden;padding:5px;text-align:center}:host>div{width:100%;position:relative}:host>div img.ngx-ic-source-image{max-width:100%;max-height:100%;transform-origin:center}:host>div img.ngx-ic-source-image.ngx-ic-draggable{user-drag:none;-webkit-user-drag:none;user-select:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;cursor:grab}:host .ngx-ic-overlay{position:absolute;pointer-events:none;touch-action:none;outline:var(--cropper-overlay-color, white) solid 100vw;top:0;left:0}:host .ngx-ic-cropper{position:absolute;display:flex;color:#53535c;background:transparent;outline:rgba(255,255,255,.3) solid 100vw;outline:var(--cropper-outline-color, rgba(255, 255, 255, .3)) solid 100vw;touch-action:none}@media (orientation: portrait){:host .ngx-ic-cropper{outline-width:100vh}}:host .ngx-ic-cropper:after{position:absolute;content:\"\";inset:0;pointer-events:none;border:dashed 1px;opacity:.75;color:inherit;z-index:1}:host .ngx-ic-cropper .ngx-ic-move{width:100%;cursor:move;border:var(--cropper-move-border, 1px solid rgba(255, 255, 255, .5))}:host .ngx-ic-cropper:focus .ngx-ic-move{border-color:#1e90ff;border-width:2px}:host .ngx-ic-cropper .ngx-ic-resize{position:absolute;display:inline-block;line-height:6px;padding:8px;opacity:.85;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize .ngx-ic-square{display:inline-block;background:#53535c;width:6px;height:6px;border:1px solid rgba(255,255,255,.5);box-sizing:content-box}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topleft{top:-12px;left:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-top{top:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-topright{top:-12px;right:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-right{top:calc(50% - 12px);right:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomright{bottom:-12px;right:-12px;cursor:nwse-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottom{bottom:-12px;left:calc(50% - 12px);cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-bottomleft{bottom:-12px;left:-12px;cursor:nesw-resize}:host .ngx-ic-cropper .ngx-ic-resize.ngx-ic-left{top:calc(50% - 12px);left:-12px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar{position:absolute;z-index:1}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-top{top:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-right{top:11px;right:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-bottom{bottom:-11px;left:11px;width:calc(100% - 22px);height:22px;cursor:ns-resize}:host .ngx-ic-cropper .ngx-ic-resize-bar.ngx-ic-left{top:11px;left:-11px;height:calc(100% - 22px);width:22px;cursor:ew-resize}:host .ngx-ic-cropper.ngx-ic-round{outline-color:transparent}:host .ngx-ic-cropper.ngx-ic-round:after{border-radius:100%;box-shadow:0 0 0 100vw #ffffff4d;box-shadow:0 0 0 100vw var(--cropper-outline-color, rgba(255, 255, 255, .3))}@media (orientation: portrait){:host .ngx-ic-cropper.ngx-ic-round:after{box-shadow:0 0 0 100vh #ffffff4d;box-shadow:0 0 0 100vh var(--cropper-outline-color, rgba(255, 255, 255, .3))}}:host .ngx-ic-cropper.ngx-ic-round .ngx-ic-move{border-radius:100%}:host.disabled .ngx-ic-cropper .ngx-ic-resize,:host.disabled .ngx-ic-cropper .ngx-ic-resize-bar,:host.disabled .ngx-ic-cropper .ngx-ic-move{display:none}:host.ngx-ic-hidden{display:none}\n"] }]
1381
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }], propDecorators: { wrapper: [{
1342
1382
  type: ViewChild,
1343
1383
  args: ['wrapper', { static: true }]
1344
1384
  }], sourceImage: [{
@@ -1354,12 +1394,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1354
1394
  type: Input
1355
1395
  }], imageAltText: [{
1356
1396
  type: Input
1397
+ }], options: [{
1398
+ type: Input
1357
1399
  }], cropperFrameAriaLabel: [{
1358
1400
  type: Input
1359
1401
  }], output: [{
1360
1402
  type: Input
1361
1403
  }], format: [{
1362
1404
  type: Input
1405
+ }], autoCrop: [{
1406
+ type: Input
1407
+ }], cropper: [{
1408
+ type: Input
1363
1409
  }], transform: [{
1364
1410
  type: Input
1365
1411
  }], maintainAspectRatio: [{
@@ -1394,8 +1440,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1394
1440
  type: Input
1395
1441
  }], imageQuality: [{
1396
1442
  type: Input
1397
- }], autoCrop: [{
1398
- type: Input
1399
1443
  }], backgroundColor: [{
1400
1444
  type: Input
1401
1445
  }], containWithinAspectRatio: [{
@@ -1404,12 +1448,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1404
1448
  type: Input
1405
1449
  }], allowMoveImage: [{
1406
1450
  type: Input
1407
- }], cropper: [{
1451
+ }], checkImageType: [{
1408
1452
  type: Input
1409
1453
  }], alignImage: [{
1410
- type: HostBinding,
1411
- args: ['style.text-align']
1412
- }, {
1413
1454
  type: Input
1414
1455
  }], disabled: [{
1415
1456
  type: HostBinding,
@@ -1418,7 +1459,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1418
1459
  type: Input
1419
1460
  }], hidden: [{
1420
1461
  type: HostBinding,
1421
- args: ['class.ngx-ix-hidden']
1462
+ args: ['class.ngx-ic-hidden']
1422
1463
  }, {
1423
1464
  type: Input
1424
1465
  }], imageCropped: [{
@@ -1433,6 +1474,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
1433
1474
  type: Output
1434
1475
  }], transformChange: [{
1435
1476
  type: Output
1477
+ }], cropperChange: [{
1478
+ type: Output
1479
+ }], alignImageStyle: [{
1480
+ type: HostBinding,
1481
+ args: ['style.text-align']
1436
1482
  }], onResize: [{
1437
1483
  type: HostListener,
1438
1484
  args: ['window:resize']
@@ -1454,5 +1500,5 @@ function base64ToFile(base64Image) {
1454
1500
  * Generated bundle index. Do not edit.
1455
1501
  */
1456
1502
 
1457
- export { CropService, CropperSettings, ImageCropperComponent, LoadImageService, base64ToFile, resizeCanvas };
1503
+ export { CropService, ImageCropperComponent, LoadImageService, base64ToFile, resizeCanvas };
1458
1504
  //# sourceMappingURL=ngx-image-cropper.mjs.map