@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-image",
3
- "version": "1.3.9",
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": "~2.16.1",
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
- const uriValidation = ImageValidator.validateUri(uri);
26
- if (!uriValidation.isValid) {
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
- const uriValidation = ImageValidator.validateUri(uri);
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: ImageTransformService['mapFormat'](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
- const uriValidation = ImageValidator.validateUri(uri);
82
- if (!uriValidation.isValid) {
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 - Advanced Editor Service
2
+ * Infrastructure - Editor Service
3
3
  *
4
- * Core editing functionality with history management
4
+ * Core editing functionality with layer and tool management
5
5
  */
6
6
 
7
- import { EditorTool, type EditorState, type EditorLayer, type EditorHistory, type EditorOptions } from '../../domain/entities/EditorTypes';
8
- import type { ImageManipulationResult } from '../../domain/entities/ImageTypes';
9
- import { ImageValidator } from '../utils/ImageValidator';
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
- const newHistory: EditorHistory = {
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
- isDirty: true,
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
- const newHistory: EditorHistory = {
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
- isDirty: true,
103
- };
76
+ });
104
77
  }
105
78
 
106
- static updateLayer(
107
- state: EditorState,
108
- layerId: string,
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: EditorState,
132
- layerId: string,
133
- element: any
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
- if (targetLayer.locked) {
145
- throw ImageErrorHandler.createError(
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
- const newHistory: EditorHistory = {
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
- ...newHistoryState,
109
+ ...ImageEditorHistoryUtils.addToHistory(state, history),
110
+ ...additionalState,
168
111
  layers: newLayers,
169
112
  isDirty: true,
170
113
  };
171
114
  }
172
115
 
173
- static undo(state: EditorState): EditorState {
174
- if (state.historyIndex <= 0) {
175
- return state;
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
- private static mapFormat(format?: SaveFormat): ImageManipulator.SaveFormat {
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
- const uriValidation = ImageValidator.validateUri(uri);
44
- if (!uriValidation.isValid) {
45
- throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'resize');
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
- const uriValidation = ImageValidator.validateUri(uri);
70
- if (!uriValidation.isValid) {
71
- throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'crop');
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
- const uriValidation = ImageValidator.validateUri(uri);
96
- if (!uriValidation.isValid) {
97
- throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'rotate');
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
- const uriValidation = ImageValidator.validateUri(uri);
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
- const uriValidation = ImageValidator.validateUri(uri);
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.resize) {
154
- const dimValidation = ImageValidator.validateDimensions(action.resize);
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
- uri: string,
194
- maxWidth: number,
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
- uri: string,
213
- width: number,
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
  }