@umituz/react-native-image 1.3.9 → 1.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -3
- package/src/index.ts +3 -0
- package/src/infrastructure/services/ImageConversionService.ts +7 -32
- package/src/infrastructure/services/ImageEditorService.ts +41 -179
- package/src/infrastructure/services/ImageTransformService.ts +28 -168
- package/src/infrastructure/utils/FilterProcessor.ts +21 -236
- package/src/infrastructure/utils/ImageEditorHistoryUtils.ts +63 -0
- package/src/infrastructure/utils/ImageFilterUtils.ts +152 -0
- package/src/infrastructure/utils/ImageTransformUtils.ts +25 -0
- package/src/presentation/components/editor/FilterPickerSheet.tsx +75 -0
- package/src/presentation/components/editor/StickerPickerSheet.tsx +62 -0
- package/src/presentation/components/editor/TextEditorSheet.tsx +98 -0
- package/src/presentation/components/editor/TextEditorTabs.tsx +111 -0
- package/src/presentation/hooks/useImage.ts +5 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-image",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.11",
|
|
4
4
|
"description": "Image manipulation and viewing for React Native apps - resize, crop, rotate, flip, compress, gallery viewer",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"react": ">=18.2.0",
|
|
41
41
|
"react-native": ">=0.74.0",
|
|
42
42
|
"react-native-gesture-handler": ">=2.0.0",
|
|
43
|
-
"react-native-reanimated": ">=3.0.0"
|
|
43
|
+
"react-native-reanimated": ">=3.0.0",
|
|
44
|
+
"@react-native-community/slider": ">=4.0.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@umituz/react-native-design-system": "latest",
|
|
@@ -51,8 +52,13 @@
|
|
|
51
52
|
"@types/react": "~19.1.10",
|
|
52
53
|
"react": "19.1.0",
|
|
53
54
|
"react-native": "0.81.5",
|
|
54
|
-
"react-native-gesture-handler": "
|
|
55
|
+
"react-native-gesture-handler": "^2.20.0",
|
|
55
56
|
"react-native-reanimated": "~3.16.1",
|
|
57
|
+
"react-native-safe-area-context": ">=4.0.0",
|
|
58
|
+
"@react-native-async-storage/async-storage": ">=1.0.0",
|
|
59
|
+
"zustand": ">=4.0.0",
|
|
60
|
+
"@umituz/react-native-filesystem": "latest",
|
|
61
|
+
"@react-native-community/slider": ">=4.0.0",
|
|
56
62
|
"typescript": "~5.9.2"
|
|
57
63
|
},
|
|
58
64
|
"publishConfig": {
|
package/src/index.ts
CHANGED
|
@@ -78,6 +78,9 @@ export { ImageTemplateService } from './infrastructure/services/ImageTemplateSer
|
|
|
78
78
|
// =============================================================================
|
|
79
79
|
|
|
80
80
|
export { ImageGallery, type ImageGalleryProps } from './presentation/components/ImageGallery';
|
|
81
|
+
export { TextEditorSheet, type TextEditorSheetProps } from './presentation/components/editor/TextEditorSheet';
|
|
82
|
+
export { StickerPickerSheet, type StickerPickerSheetProps } from './presentation/components/editor/StickerPickerSheet';
|
|
83
|
+
export { FilterPickerSheet, type FilterPickerSheetProps } from './presentation/components/editor/FilterPickerSheet';
|
|
81
84
|
|
|
82
85
|
export { useImage } from './presentation/hooks/useImage';
|
|
83
86
|
export { useImageTransform } from './presentation/hooks/useImageTransform';
|
|
@@ -12,9 +12,9 @@ import type {
|
|
|
12
12
|
} from '../../domain/entities/ImageTypes';
|
|
13
13
|
import { IMAGE_CONSTANTS } from '../../domain/entities/ImageConstants';
|
|
14
14
|
import { ImageTransformService } from './ImageTransformService';
|
|
15
|
-
import { ImageAdvancedTransformService } from './ImageAdvancedTransformService';
|
|
16
15
|
import { ImageValidator } from '../utils/ImageValidator';
|
|
17
16
|
import { ImageErrorHandler, IMAGE_ERROR_CODES } from '../utils/ImageErrorHandler';
|
|
17
|
+
import { ImageTransformUtils } from '../utils/ImageTransformUtils';
|
|
18
18
|
|
|
19
19
|
export class ImageConversionService {
|
|
20
20
|
static async compress(
|
|
@@ -22,15 +22,8 @@ export class ImageConversionService {
|
|
|
22
22
|
quality: number = IMAGE_CONSTANTS.defaultQuality
|
|
23
23
|
): Promise<ImageManipulationResult> {
|
|
24
24
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'compress');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const qualityValidation = ImageValidator.validateQuality(quality);
|
|
31
|
-
if (!qualityValidation.isValid) {
|
|
32
|
-
throw ImageErrorHandler.createError(qualityValidation.error!, IMAGE_ERROR_CODES.INVALID_QUALITY, 'compress');
|
|
33
|
-
}
|
|
25
|
+
ImageValidator.validateUri(uri);
|
|
26
|
+
ImageValidator.validateQuality(quality);
|
|
34
27
|
|
|
35
28
|
return await ImageManipulator.manipulateAsync(
|
|
36
29
|
uri,
|
|
@@ -48,23 +41,14 @@ export class ImageConversionService {
|
|
|
48
41
|
quality?: number
|
|
49
42
|
): Promise<ImageManipulationResult> {
|
|
50
43
|
try {
|
|
51
|
-
|
|
52
|
-
if (!uriValidation.isValid) {
|
|
53
|
-
throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'convertFormat');
|
|
54
|
-
}
|
|
55
|
-
|
|
44
|
+
ImageValidator.validateUri(uri);
|
|
56
45
|
const compressQuality = quality ?? IMAGE_CONSTANTS.defaultQuality;
|
|
57
|
-
const qualityValidation = ImageValidator.validateQuality(compressQuality);
|
|
58
|
-
if (!qualityValidation.isValid) {
|
|
59
|
-
throw ImageErrorHandler.createError(qualityValidation.error!, IMAGE_ERROR_CODES.INVALID_QUALITY, 'convertFormat');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
46
|
return await ImageManipulator.manipulateAsync(
|
|
63
47
|
uri,
|
|
64
48
|
[],
|
|
65
49
|
{
|
|
66
50
|
compress: compressQuality,
|
|
67
|
-
format:
|
|
51
|
+
format: ImageTransformUtils.mapFormat(format),
|
|
68
52
|
}
|
|
69
53
|
);
|
|
70
54
|
} catch (error) {
|
|
@@ -78,17 +62,8 @@ export class ImageConversionService {
|
|
|
78
62
|
options?: ImageSaveOptions
|
|
79
63
|
): Promise<ImageManipulationResult> {
|
|
80
64
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'createThumbnail');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const dimValidation = ImageValidator.validateDimensions({ width: size, height: size });
|
|
87
|
-
if (!dimValidation.isValid) {
|
|
88
|
-
throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'createThumbnail');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return await ImageAdvancedTransformService.resizeToFit(uri, size, size, {
|
|
65
|
+
ImageValidator.validateUri(uri);
|
|
66
|
+
return await ImageTransformService.resizeToFit(uri, size, size, {
|
|
92
67
|
...options,
|
|
93
68
|
compress: options?.compress ?? IMAGE_CONSTANTS.compressQuality.medium,
|
|
94
69
|
});
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Infrastructure -
|
|
2
|
+
* Infrastructure - Editor Service
|
|
3
3
|
*
|
|
4
|
-
* Core editing functionality with
|
|
4
|
+
* Core editing functionality with layer and tool management
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
import {
|
|
8
|
+
EditorTool,
|
|
9
|
+
type EditorState,
|
|
10
|
+
type EditorLayer,
|
|
11
|
+
type EditorHistory,
|
|
12
|
+
type EditorOptions
|
|
13
|
+
} from '../../domain/entities/EditorTypes';
|
|
10
14
|
import { ImageErrorHandler, IMAGE_ERROR_CODES } from '../utils/ImageErrorHandler';
|
|
15
|
+
import { ImageEditorHistoryUtils } from '../utils/ImageEditorHistoryUtils';
|
|
11
16
|
|
|
12
17
|
export class ImageEditorService {
|
|
13
18
|
private static generateId(): string {
|
|
@@ -45,10 +50,7 @@ export class ImageEditorService {
|
|
|
45
50
|
};
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
static addLayer(
|
|
49
|
-
state: EditorState,
|
|
50
|
-
name?: string
|
|
51
|
-
): EditorState {
|
|
53
|
+
static addLayer(state: EditorState, name?: string): EditorState {
|
|
52
54
|
const newLayer: EditorLayer = {
|
|
53
55
|
id: ImageEditorService.generateId(),
|
|
54
56
|
name: name || `Layer ${state.layers.length}`,
|
|
@@ -58,177 +60,68 @@ export class ImageEditorService {
|
|
|
58
60
|
elements: [],
|
|
59
61
|
};
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
id: ImageEditorService.generateId(),
|
|
63
|
-
timestamp: new Date(),
|
|
64
|
-
layers: [...state.layers, newLayer],
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const newHistoryState = ImageEditorService.addToHistory(state, newHistory);
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
...newHistoryState,
|
|
71
|
-
layers: [...state.layers, newLayer],
|
|
63
|
+
return ImageEditorService.commitHistory(state, [...state.layers, newLayer], {
|
|
72
64
|
selectedLayer: newLayer.id,
|
|
73
|
-
|
|
74
|
-
};
|
|
65
|
+
});
|
|
75
66
|
}
|
|
76
67
|
|
|
77
|
-
static removeLayer(
|
|
78
|
-
state: EditorState,
|
|
79
|
-
layerId: string
|
|
80
|
-
): EditorState {
|
|
68
|
+
static removeLayer(state: EditorState, layerId: string): EditorState {
|
|
81
69
|
if (state.layers.length <= 1) {
|
|
82
|
-
throw ImageErrorHandler.createError(
|
|
83
|
-
'Cannot remove the last layer',
|
|
84
|
-
IMAGE_ERROR_CODES.VALIDATION_ERROR,
|
|
85
|
-
'removeLayer'
|
|
86
|
-
);
|
|
70
|
+
throw ImageErrorHandler.createError('Cannot remove background', IMAGE_ERROR_CODES.VALIDATION_ERROR, 'removeLayer');
|
|
87
71
|
}
|
|
88
72
|
|
|
89
73
|
const newLayers = state.layers.filter(layer => layer.id !== layerId);
|
|
90
|
-
|
|
91
|
-
id: ImageEditorService.generateId(),
|
|
92
|
-
timestamp: new Date(),
|
|
93
|
-
layers: newLayers,
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const newHistoryState = ImageEditorService.addToHistory(state, newHistory);
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
...newHistoryState,
|
|
100
|
-
layers: newLayers,
|
|
74
|
+
return ImageEditorService.commitHistory(state, newLayers, {
|
|
101
75
|
selectedLayer: newLayers[0].id,
|
|
102
|
-
|
|
103
|
-
};
|
|
76
|
+
});
|
|
104
77
|
}
|
|
105
78
|
|
|
106
|
-
static updateLayer(
|
|
107
|
-
state:
|
|
108
|
-
|
|
109
|
-
updates: Partial<EditorLayer>
|
|
110
|
-
): EditorState {
|
|
111
|
-
const newLayers = state.layers.map(layer =>
|
|
112
|
-
layer.id === layerId ? { ...layer, ...updates } : layer
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
const newHistory: EditorHistory = {
|
|
116
|
-
id: ImageEditorService.generateId(),
|
|
117
|
-
timestamp: new Date(),
|
|
118
|
-
layers: newLayers,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const newHistoryState = ImageEditorService.addToHistory(state, newHistory);
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
...newHistoryState,
|
|
125
|
-
layers: newLayers,
|
|
126
|
-
isDirty: true,
|
|
127
|
-
};
|
|
79
|
+
static updateLayer(state: EditorState, layerId: string, updates: Partial<EditorLayer>): EditorState {
|
|
80
|
+
const newLayers = state.layers.map(layer => layer.id === layerId ? { ...layer, ...updates } : layer);
|
|
81
|
+
return ImageEditorService.commitHistory(state, newLayers);
|
|
128
82
|
}
|
|
129
83
|
|
|
130
|
-
static addElementToLayer(
|
|
131
|
-
state
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
): EditorState {
|
|
135
|
-
const targetLayer = state.layers.find(layer => layer.id === layerId);
|
|
136
|
-
if (!targetLayer) {
|
|
137
|
-
throw ImageErrorHandler.createError(
|
|
138
|
-
'Layer not found',
|
|
139
|
-
IMAGE_ERROR_CODES.VALIDATION_ERROR,
|
|
140
|
-
'addElementToLayer'
|
|
141
|
-
);
|
|
84
|
+
static addElementToLayer(state: EditorState, layerId: string, element: any): EditorState {
|
|
85
|
+
const layer = state.layers.find(l => l.id === layerId);
|
|
86
|
+
if (!layer || layer.locked) {
|
|
87
|
+
throw ImageErrorHandler.createError('Invalid layer operation', IMAGE_ERROR_CODES.VALIDATION_ERROR, 'addElementToLayer');
|
|
142
88
|
}
|
|
143
89
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
'Cannot add element to locked layer',
|
|
147
|
-
IMAGE_ERROR_CODES.VALIDATION_ERROR,
|
|
148
|
-
'addElementToLayer'
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const newLayers = state.layers.map(layer =>
|
|
153
|
-
layer.id === layerId
|
|
154
|
-
? { ...layer, elements: [...layer.elements, element] }
|
|
155
|
-
: layer
|
|
90
|
+
const newLayers = state.layers.map(l =>
|
|
91
|
+
l.id === layerId ? { ...l, elements: [...l.elements, element] } : l
|
|
156
92
|
);
|
|
157
93
|
|
|
158
|
-
|
|
94
|
+
return ImageEditorService.commitHistory(state, newLayers);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private static commitHistory(
|
|
98
|
+
state: EditorState,
|
|
99
|
+
newLayers: EditorLayer[],
|
|
100
|
+
additionalState: Partial<EditorState> = {}
|
|
101
|
+
): EditorState {
|
|
102
|
+
const history: EditorHistory = {
|
|
159
103
|
id: ImageEditorService.generateId(),
|
|
160
104
|
timestamp: new Date(),
|
|
161
105
|
layers: newLayers,
|
|
162
106
|
};
|
|
163
107
|
|
|
164
|
-
const newHistoryState = ImageEditorService.addToHistory(state, newHistory);
|
|
165
|
-
|
|
166
108
|
return {
|
|
167
|
-
...
|
|
109
|
+
...ImageEditorHistoryUtils.addToHistory(state, history),
|
|
110
|
+
...additionalState,
|
|
168
111
|
layers: newLayers,
|
|
169
112
|
isDirty: true,
|
|
170
113
|
};
|
|
171
114
|
}
|
|
172
115
|
|
|
173
|
-
static undo
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const newIndex = state.historyIndex - 1;
|
|
179
|
-
const historyState = state.history[newIndex];
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
...state,
|
|
183
|
-
layers: historyState.layers,
|
|
184
|
-
historyIndex: newIndex,
|
|
185
|
-
isDirty: true,
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
static redo(state: EditorState): EditorState {
|
|
190
|
-
if (state.historyIndex >= state.history.length - 1) {
|
|
191
|
-
return state;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const newIndex = state.historyIndex + 1;
|
|
195
|
-
const historyState = state.history[newIndex];
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
...state,
|
|
199
|
-
layers: historyState.layers,
|
|
200
|
-
historyIndex: newIndex,
|
|
201
|
-
isDirty: true,
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
private static addToHistory(
|
|
206
|
-
state: EditorState,
|
|
207
|
-
newHistory: EditorHistory,
|
|
208
|
-
maxHistory: number = 50
|
|
209
|
-
): EditorState {
|
|
210
|
-
const newHistoryArray = [...state.history.slice(0, state.historyIndex + 1), newHistory];
|
|
211
|
-
|
|
212
|
-
// Keep only the last maxHistory states
|
|
213
|
-
if (newHistoryArray.length > maxHistory) {
|
|
214
|
-
newHistoryArray.shift();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
...state,
|
|
219
|
-
history: newHistoryArray,
|
|
220
|
-
historyIndex: newHistoryArray.length - 1,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
116
|
+
static undo = ImageEditorHistoryUtils.undo;
|
|
117
|
+
static redo = ImageEditorHistoryUtils.redo;
|
|
118
|
+
static canUndo = ImageEditorHistoryUtils.canUndo;
|
|
119
|
+
static canRedo = ImageEditorHistoryUtils.canRedo;
|
|
223
120
|
|
|
224
121
|
static setTool(state: EditorState, tool: EditorTool): EditorState {
|
|
225
122
|
return { ...state, tool };
|
|
226
123
|
}
|
|
227
124
|
|
|
228
|
-
static setSelectedLayer(state: EditorState, layerId?: string): EditorState {
|
|
229
|
-
return { ...state, selectedLayer: layerId };
|
|
230
|
-
}
|
|
231
|
-
|
|
232
125
|
static setZoom(state: EditorState, zoom: number): EditorState {
|
|
233
126
|
return { ...state, zoom: Math.max(0.1, Math.min(5, zoom)) };
|
|
234
127
|
}
|
|
@@ -237,38 +130,7 @@ export class ImageEditorService {
|
|
|
237
130
|
return { ...state, pan };
|
|
238
131
|
}
|
|
239
132
|
|
|
240
|
-
static canUndo(state: EditorState): boolean {
|
|
241
|
-
return state.historyIndex > 0;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
static canRedo(state: EditorState): boolean {
|
|
245
|
-
return state.historyIndex < state.history.length - 1;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
133
|
static getVisibleLayers(state: EditorState): EditorLayer[] {
|
|
249
134
|
return state.layers.filter(layer => layer.visible);
|
|
250
135
|
}
|
|
251
|
-
|
|
252
|
-
static getActiveLayers(state: EditorState): EditorLayer[] {
|
|
253
|
-
return state.layers.filter(layer => layer.visible && !layer.locked);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
static exportState(state: EditorState): EditorState {
|
|
257
|
-
return {
|
|
258
|
-
...state,
|
|
259
|
-
currentUri: undefined,
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
static importState(data: any, uri: string): EditorState {
|
|
264
|
-
try {
|
|
265
|
-
return {
|
|
266
|
-
...data,
|
|
267
|
-
originalUri: uri,
|
|
268
|
-
currentUri: undefined,
|
|
269
|
-
};
|
|
270
|
-
} catch (error) {
|
|
271
|
-
throw ImageErrorHandler.handleUnknownError(error, 'importState');
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
136
|
}
|
|
@@ -9,221 +9,81 @@ import type {
|
|
|
9
9
|
ImageManipulateAction,
|
|
10
10
|
ImageSaveOptions,
|
|
11
11
|
ImageManipulationResult,
|
|
12
|
-
SaveFormat,
|
|
13
12
|
ImageCropArea,
|
|
14
13
|
ImageFlipOptions,
|
|
15
14
|
} from '../../domain/entities/ImageTypes';
|
|
16
|
-
import { IMAGE_CONSTANTS } from '../../domain/entities/ImageConstants';
|
|
17
15
|
import { ImageUtils } from '../../domain/utils/ImageUtils';
|
|
18
16
|
import { ImageValidator } from '../utils/ImageValidator';
|
|
19
17
|
import { ImageErrorHandler, IMAGE_ERROR_CODES } from '../utils/ImageErrorHandler';
|
|
18
|
+
import { ImageTransformUtils } from '../utils/ImageTransformUtils';
|
|
20
19
|
|
|
21
20
|
export class ImageTransformService {
|
|
22
|
-
|
|
23
|
-
if (format === 'png') return ImageManipulator.SaveFormat.PNG;
|
|
24
|
-
if (format === 'webp') return ImageManipulator.SaveFormat.WEBP;
|
|
25
|
-
return ImageManipulator.SaveFormat.JPEG;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
private static buildSaveOptions(options?: ImageSaveOptions): ImageManipulator.SaveOptions {
|
|
29
|
-
return {
|
|
30
|
-
compress: options?.compress ?? IMAGE_CONSTANTS.defaultQuality,
|
|
31
|
-
format: this.mapFormat(options?.format),
|
|
32
|
-
base64: options?.base64,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
static async resize(
|
|
37
|
-
uri: string,
|
|
38
|
-
width?: number,
|
|
39
|
-
height?: number,
|
|
40
|
-
options?: ImageSaveOptions
|
|
41
|
-
): Promise<ImageManipulationResult> {
|
|
21
|
+
static async resize(uri: string, width?: number, height?: number, options?: ImageSaveOptions): Promise<ImageManipulationResult> {
|
|
42
22
|
try {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const dimValidation = ImageValidator.validateDimensions({ width, height });
|
|
49
|
-
if (!dimValidation.isValid) {
|
|
50
|
-
throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'resize');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return await ImageManipulator.manipulateAsync(
|
|
54
|
-
uri,
|
|
55
|
-
[{ resize: { width, height } }],
|
|
56
|
-
this.buildSaveOptions(options)
|
|
57
|
-
);
|
|
23
|
+
ImageValidator.validateUri(uri);
|
|
24
|
+
ImageValidator.validateDimensions({ width, height });
|
|
25
|
+
return await ImageManipulator.manipulateAsync(uri, [{ resize: { width, height } }], ImageTransformUtils.buildSaveOptions(options));
|
|
58
26
|
} catch (error) {
|
|
59
27
|
throw ImageErrorHandler.handleUnknownError(error, 'resize');
|
|
60
28
|
}
|
|
61
29
|
}
|
|
62
30
|
|
|
63
|
-
static async crop(
|
|
64
|
-
uri: string,
|
|
65
|
-
cropArea: ImageCropArea,
|
|
66
|
-
options?: ImageSaveOptions
|
|
67
|
-
): Promise<ImageManipulationResult> {
|
|
31
|
+
static async crop(uri: string, cropArea: ImageCropArea, options?: ImageSaveOptions): Promise<ImageManipulationResult> {
|
|
68
32
|
try {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const dimValidation = ImageValidator.validateDimensions(cropArea);
|
|
75
|
-
if (!dimValidation.isValid) {
|
|
76
|
-
throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'crop');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return await ImageManipulator.manipulateAsync(
|
|
80
|
-
uri,
|
|
81
|
-
[{ crop: cropArea }],
|
|
82
|
-
this.buildSaveOptions(options)
|
|
83
|
-
);
|
|
33
|
+
ImageValidator.validateUri(uri);
|
|
34
|
+
ImageValidator.validateDimensions(cropArea);
|
|
35
|
+
return await ImageManipulator.manipulateAsync(uri, [{ crop: cropArea }], ImageTransformUtils.buildSaveOptions(options));
|
|
84
36
|
} catch (error) {
|
|
85
37
|
throw ImageErrorHandler.handleUnknownError(error, 'crop');
|
|
86
38
|
}
|
|
87
39
|
}
|
|
88
40
|
|
|
89
|
-
static async rotate(
|
|
90
|
-
uri: string,
|
|
91
|
-
degrees: number,
|
|
92
|
-
options?: ImageSaveOptions
|
|
93
|
-
): Promise<ImageManipulationResult> {
|
|
41
|
+
static async rotate(uri: string, degrees: number, options?: ImageSaveOptions): Promise<ImageManipulationResult> {
|
|
94
42
|
try {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const rotationValidation = ImageValidator.validateRotation(degrees);
|
|
101
|
-
if (!rotationValidation.isValid) {
|
|
102
|
-
throw ImageErrorHandler.createError(rotationValidation.error!, IMAGE_ERROR_CODES.VALIDATION_ERROR, 'rotate');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return await ImageManipulator.manipulateAsync(
|
|
106
|
-
uri,
|
|
107
|
-
[{ rotate: degrees }],
|
|
108
|
-
this.buildSaveOptions(options)
|
|
109
|
-
);
|
|
43
|
+
ImageValidator.validateUri(uri);
|
|
44
|
+
ImageValidator.validateRotation(degrees);
|
|
45
|
+
return await ImageManipulator.manipulateAsync(uri, [{ rotate: degrees }], ImageTransformUtils.buildSaveOptions(options));
|
|
110
46
|
} catch (error) {
|
|
111
47
|
throw ImageErrorHandler.handleUnknownError(error, 'rotate');
|
|
112
48
|
}
|
|
113
49
|
}
|
|
114
50
|
|
|
115
|
-
static async flip(
|
|
116
|
-
uri: string,
|
|
117
|
-
flip: ImageFlipOptions,
|
|
118
|
-
options?: ImageSaveOptions
|
|
119
|
-
): Promise<ImageManipulationResult> {
|
|
51
|
+
static async flip(uri: string, flip: ImageFlipOptions, options?: ImageSaveOptions): Promise<ImageManipulationResult> {
|
|
120
52
|
try {
|
|
121
|
-
|
|
122
|
-
if (!uriValidation.isValid) {
|
|
123
|
-
throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'flip');
|
|
124
|
-
}
|
|
125
|
-
|
|
53
|
+
ImageValidator.validateUri(uri);
|
|
126
54
|
const actions: ImageManipulator.Action[] = [];
|
|
127
55
|
if (flip.horizontal) actions.push({ flip: ImageManipulator.FlipType.Horizontal });
|
|
128
56
|
if (flip.vertical) actions.push({ flip: ImageManipulator.FlipType.Vertical });
|
|
129
|
-
|
|
130
|
-
return await ImageManipulator.manipulateAsync(
|
|
131
|
-
uri,
|
|
132
|
-
actions,
|
|
133
|
-
this.buildSaveOptions(options)
|
|
134
|
-
);
|
|
57
|
+
return await ImageManipulator.manipulateAsync(uri, actions, ImageTransformUtils.buildSaveOptions(options));
|
|
135
58
|
} catch (error) {
|
|
136
59
|
throw ImageErrorHandler.handleUnknownError(error, 'flip');
|
|
137
60
|
}
|
|
138
61
|
}
|
|
139
62
|
|
|
140
|
-
static async manipulate(
|
|
141
|
-
uri: string,
|
|
142
|
-
action: ImageManipulateAction,
|
|
143
|
-
options?: ImageSaveOptions
|
|
144
|
-
): Promise<ImageManipulationResult> {
|
|
63
|
+
static async manipulate(uri: string, action: ImageManipulateAction, options?: ImageSaveOptions): Promise<ImageManipulationResult> {
|
|
145
64
|
try {
|
|
146
|
-
|
|
147
|
-
if (!uriValidation.isValid) {
|
|
148
|
-
throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'manipulate');
|
|
149
|
-
}
|
|
150
|
-
|
|
65
|
+
ImageValidator.validateUri(uri);
|
|
151
66
|
const actions: ImageManipulator.Action[] = [];
|
|
152
|
-
|
|
153
|
-
if (action.
|
|
154
|
-
|
|
155
|
-
if (!dimValidation.isValid) {
|
|
156
|
-
throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'manipulate');
|
|
157
|
-
}
|
|
158
|
-
actions.push({ resize: action.resize });
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (action.crop) {
|
|
162
|
-
const dimValidation = ImageValidator.validateDimensions(action.crop);
|
|
163
|
-
if (!dimValidation.isValid) {
|
|
164
|
-
throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'manipulate');
|
|
165
|
-
}
|
|
166
|
-
actions.push({ crop: action.crop });
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (action.rotate) {
|
|
170
|
-
const rotationValidation = ImageValidator.validateRotation(action.rotate);
|
|
171
|
-
if (!rotationValidation.isValid) {
|
|
172
|
-
throw ImageErrorHandler.createError(rotationValidation.error!, IMAGE_ERROR_CODES.VALIDATION_ERROR, 'manipulate');
|
|
173
|
-
}
|
|
174
|
-
actions.push({ rotate: action.rotate });
|
|
175
|
-
}
|
|
176
|
-
|
|
67
|
+
if (action.resize) actions.push({ resize: action.resize });
|
|
68
|
+
if (action.crop) actions.push({ crop: action.crop });
|
|
69
|
+
if (action.rotate) actions.push({ rotate: action.rotate });
|
|
177
70
|
if (action.flip) {
|
|
178
71
|
if (action.flip.horizontal) actions.push({ flip: ImageManipulator.FlipType.Horizontal });
|
|
179
72
|
if (action.flip.vertical) actions.push({ flip: ImageManipulator.FlipType.Vertical });
|
|
180
73
|
}
|
|
181
|
-
|
|
182
|
-
return await ImageManipulator.manipulateAsync(
|
|
183
|
-
uri,
|
|
184
|
-
actions,
|
|
185
|
-
this.buildSaveOptions(options)
|
|
186
|
-
);
|
|
74
|
+
return await ImageManipulator.manipulateAsync(uri, actions, ImageTransformUtils.buildSaveOptions(options));
|
|
187
75
|
} catch (error) {
|
|
188
76
|
throw ImageErrorHandler.handleUnknownError(error, 'manipulate');
|
|
189
77
|
}
|
|
190
78
|
}
|
|
191
79
|
|
|
192
|
-
static async resizeToFit(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
maxHeight: number,
|
|
196
|
-
options?: ImageSaveOptions
|
|
197
|
-
): Promise<ImageManipulationResult> {
|
|
198
|
-
try {
|
|
199
|
-
const dimValidation = ImageValidator.validateDimensions({ width: maxWidth, height: maxHeight });
|
|
200
|
-
if (!dimValidation.isValid) {
|
|
201
|
-
throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'resizeToFit');
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const dimensions = ImageUtils.fitToSize(maxWidth, maxHeight, maxWidth, maxHeight);
|
|
205
|
-
return this.resize(uri, dimensions.width, dimensions.height, options);
|
|
206
|
-
} catch (error) {
|
|
207
|
-
throw ImageErrorHandler.handleUnknownError(error, 'resizeToFit');
|
|
208
|
-
}
|
|
80
|
+
static async resizeToFit(uri: string, maxWidth: number, maxHeight: number, options?: ImageSaveOptions): Promise<ImageManipulationResult> {
|
|
81
|
+
const dimensions = ImageUtils.fitToSize(maxWidth, maxHeight, maxWidth, maxHeight);
|
|
82
|
+
return this.resize(uri, dimensions.width, dimensions.height, options);
|
|
209
83
|
}
|
|
210
84
|
|
|
211
|
-
static async cropToSquare(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
height: number,
|
|
215
|
-
options?: ImageSaveOptions
|
|
216
|
-
): Promise<ImageManipulationResult> {
|
|
217
|
-
try {
|
|
218
|
-
const dimValidation = ImageValidator.validateDimensions({ width, height });
|
|
219
|
-
if (!dimValidation.isValid) {
|
|
220
|
-
throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'cropToSquare');
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const cropArea = ImageUtils.getSquareCrop(width, height);
|
|
224
|
-
return this.crop(uri, cropArea, options);
|
|
225
|
-
} catch (error) {
|
|
226
|
-
throw ImageErrorHandler.handleUnknownError(error, 'cropToSquare');
|
|
227
|
-
}
|
|
85
|
+
static async cropToSquare(uri: string, width: number, height: number, options?: ImageSaveOptions): Promise<ImageManipulationResult> {
|
|
86
|
+
const cropArea = ImageUtils.getSquareCrop(width, height);
|
|
87
|
+
return this.crop(uri, cropArea, options);
|
|
228
88
|
}
|
|
229
89
|
}
|