@umituz/react-native-image 1.1.0 → 1.1.2
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 +10 -4
- package/src/domain/entities/ImageConstants.ts +21 -0
- package/src/domain/entities/ImageTypes.ts +71 -0
- package/src/domain/utils/ImageUtils.ts +103 -0
- package/src/index.ts +16 -10
- package/src/infrastructure/services/ImageConversionService.ts +66 -0
- package/src/infrastructure/services/ImageStorageService.ts +22 -0
- package/src/infrastructure/services/ImageTransformService.ts +172 -0
- package/src/infrastructure/services/ImageViewerService.ts +1 -1
- package/src/presentation/components/ImageGallery.tsx +54 -0
- package/src/presentation/hooks/useImage.ts +13 -384
- package/src/presentation/hooks/useImageConversion.ts +26 -0
- package/src/presentation/hooks/useImageGallery.ts +1 -1
- package/src/presentation/hooks/useImageOperation.ts +33 -0
- package/src/presentation/hooks/useImageTransform.ts +37 -0
- package/src/domain/entities/Image.ts +0 -273
- package/src/infrastructure/services/ImageService.ts +0 -316
|
@@ -1,393 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* useImage Hook
|
|
3
|
+
*
|
|
4
|
+
* Aggregator hook that combines transformation and conversion capabilities.
|
|
5
|
+
* Kept simple and modular.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import type {
|
|
11
|
-
ImageManipulateAction,
|
|
12
|
-
ImageSaveOptions,
|
|
13
|
-
ImageManipulationResult,
|
|
14
|
-
SaveFormat,
|
|
15
|
-
} from '../../domain/entities/Image';
|
|
8
|
+
import { useImageTransform } from './useImageTransform';
|
|
9
|
+
import { useImageConversion } from './useImageConversion';
|
|
16
10
|
|
|
17
|
-
/**
|
|
18
|
-
* useImage hook for image manipulation
|
|
19
|
-
*
|
|
20
|
-
* USAGE:
|
|
21
|
-
* ```typescript
|
|
22
|
-
* const { resize, crop, rotate, compress, isProcessing } = useImage();
|
|
23
|
-
*
|
|
24
|
-
* // Resize image
|
|
25
|
-
* const resized = await resize(imageUri, 800, 600);
|
|
26
|
-
*
|
|
27
|
-
* // Crop image
|
|
28
|
-
* const cropped = await crop(imageUri, { originX: 0, originY: 0, width: 500, height: 500 });
|
|
29
|
-
*
|
|
30
|
-
* // Compress image
|
|
31
|
-
* const compressed = await compress(imageUri, 0.7);
|
|
32
|
-
* ```
|
|
33
|
-
*/
|
|
34
11
|
export const useImage = () => {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Resize image
|
|
40
|
-
*/
|
|
41
|
-
const resize = useCallback(
|
|
42
|
-
async (
|
|
43
|
-
uri: string,
|
|
44
|
-
width?: number,
|
|
45
|
-
height?: number,
|
|
46
|
-
options?: ImageSaveOptions
|
|
47
|
-
): Promise<ImageManipulationResult | null> => {
|
|
48
|
-
setIsProcessing(true);
|
|
49
|
-
setError(null);
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const result = await ImageService.resize(uri, width, height, options);
|
|
53
|
-
|
|
54
|
-
if (!result) {
|
|
55
|
-
setError('Failed to resize image');
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return result;
|
|
59
|
-
} catch (err) {
|
|
60
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to resize image';
|
|
61
|
-
setError(errorMessage);
|
|
62
|
-
return null;
|
|
63
|
-
} finally {
|
|
64
|
-
setIsProcessing(false);
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
[]
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Crop image
|
|
72
|
-
*/
|
|
73
|
-
const crop = useCallback(
|
|
74
|
-
async (
|
|
75
|
-
uri: string,
|
|
76
|
-
cropArea: { originX: number; originY: number; width: number; height: number },
|
|
77
|
-
options?: ImageSaveOptions
|
|
78
|
-
): Promise<ImageManipulationResult | null> => {
|
|
79
|
-
setIsProcessing(true);
|
|
80
|
-
setError(null);
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
const result = await ImageService.crop(uri, cropArea, options);
|
|
84
|
-
|
|
85
|
-
if (!result) {
|
|
86
|
-
setError('Failed to crop image');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return result;
|
|
90
|
-
} catch (err) {
|
|
91
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to crop image';
|
|
92
|
-
setError(errorMessage);
|
|
93
|
-
return null;
|
|
94
|
-
} finally {
|
|
95
|
-
setIsProcessing(false);
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
[]
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Rotate image
|
|
103
|
-
*/
|
|
104
|
-
const rotate = useCallback(
|
|
105
|
-
async (
|
|
106
|
-
uri: string,
|
|
107
|
-
degrees: number,
|
|
108
|
-
options?: ImageSaveOptions
|
|
109
|
-
): Promise<ImageManipulationResult | null> => {
|
|
110
|
-
setIsProcessing(true);
|
|
111
|
-
setError(null);
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
const result = await ImageService.rotate(uri, degrees, options);
|
|
115
|
-
|
|
116
|
-
if (!result) {
|
|
117
|
-
setError('Failed to rotate image');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return result;
|
|
121
|
-
} catch (err) {
|
|
122
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to rotate image';
|
|
123
|
-
setError(errorMessage);
|
|
124
|
-
return null;
|
|
125
|
-
} finally {
|
|
126
|
-
setIsProcessing(false);
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
[]
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Flip image
|
|
134
|
-
*/
|
|
135
|
-
const flip = useCallback(
|
|
136
|
-
async (
|
|
137
|
-
uri: string,
|
|
138
|
-
flipOptions: { horizontal?: boolean; vertical?: boolean },
|
|
139
|
-
saveOptions?: ImageSaveOptions
|
|
140
|
-
): Promise<ImageManipulationResult | null> => {
|
|
141
|
-
setIsProcessing(true);
|
|
142
|
-
setError(null);
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
const result = await ImageService.flip(uri, flipOptions, saveOptions);
|
|
146
|
-
|
|
147
|
-
if (!result) {
|
|
148
|
-
setError('Failed to flip image');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return result;
|
|
152
|
-
} catch (err) {
|
|
153
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to flip image';
|
|
154
|
-
setError(errorMessage);
|
|
155
|
-
return null;
|
|
156
|
-
} finally {
|
|
157
|
-
setIsProcessing(false);
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
|
-
[]
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Perform multiple manipulations
|
|
165
|
-
*/
|
|
166
|
-
const manipulate = useCallback(
|
|
167
|
-
async (
|
|
168
|
-
uri: string,
|
|
169
|
-
action: ImageManipulateAction,
|
|
170
|
-
options?: ImageSaveOptions
|
|
171
|
-
): Promise<ImageManipulationResult | null> => {
|
|
172
|
-
setIsProcessing(true);
|
|
173
|
-
setError(null);
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
const result = await ImageService.manipulate(uri, action, options);
|
|
177
|
-
|
|
178
|
-
if (!result) {
|
|
179
|
-
setError('Failed to manipulate image');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return result;
|
|
183
|
-
} catch (err) {
|
|
184
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to manipulate image';
|
|
185
|
-
setError(errorMessage);
|
|
186
|
-
return null;
|
|
187
|
-
} finally {
|
|
188
|
-
setIsProcessing(false);
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
[]
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Compress image
|
|
196
|
-
*/
|
|
197
|
-
const compress = useCallback(
|
|
198
|
-
async (uri: string, quality: number = 0.8): Promise<ImageManipulationResult | null> => {
|
|
199
|
-
setIsProcessing(true);
|
|
200
|
-
setError(null);
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
const result = await ImageService.compress(uri, quality);
|
|
204
|
-
|
|
205
|
-
if (!result) {
|
|
206
|
-
setError('Failed to compress image');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return result;
|
|
210
|
-
} catch (err) {
|
|
211
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to compress image';
|
|
212
|
-
setError(errorMessage);
|
|
213
|
-
return null;
|
|
214
|
-
} finally {
|
|
215
|
-
setIsProcessing(false);
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
[]
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Resize to fit within max dimensions
|
|
223
|
-
*/
|
|
224
|
-
const resizeToFit = useCallback(
|
|
225
|
-
async (
|
|
226
|
-
uri: string,
|
|
227
|
-
maxWidth: number,
|
|
228
|
-
maxHeight: number,
|
|
229
|
-
options?: ImageSaveOptions
|
|
230
|
-
): Promise<ImageManipulationResult | null> => {
|
|
231
|
-
setIsProcessing(true);
|
|
232
|
-
setError(null);
|
|
233
|
-
|
|
234
|
-
try {
|
|
235
|
-
const result = await ImageService.resizeToFit(uri, maxWidth, maxHeight, options);
|
|
236
|
-
|
|
237
|
-
if (!result) {
|
|
238
|
-
setError('Failed to resize image to fit');
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return result;
|
|
242
|
-
} catch (err) {
|
|
243
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to resize image to fit';
|
|
244
|
-
setError(errorMessage);
|
|
245
|
-
return null;
|
|
246
|
-
} finally {
|
|
247
|
-
setIsProcessing(false);
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
[]
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Create thumbnail
|
|
255
|
-
*/
|
|
256
|
-
const createThumbnail = useCallback(
|
|
257
|
-
async (
|
|
258
|
-
uri: string,
|
|
259
|
-
size: number = 200,
|
|
260
|
-
options?: ImageSaveOptions
|
|
261
|
-
): Promise<ImageManipulationResult | null> => {
|
|
262
|
-
setIsProcessing(true);
|
|
263
|
-
setError(null);
|
|
264
|
-
|
|
265
|
-
try {
|
|
266
|
-
const result = await ImageService.createThumbnail(uri, size, options);
|
|
267
|
-
|
|
268
|
-
if (!result) {
|
|
269
|
-
setError('Failed to create thumbnail');
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return result;
|
|
273
|
-
} catch (err) {
|
|
274
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to create thumbnail';
|
|
275
|
-
setError(errorMessage);
|
|
276
|
-
return null;
|
|
277
|
-
} finally {
|
|
278
|
-
setIsProcessing(false);
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
|
-
[]
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Crop to square
|
|
286
|
-
*/
|
|
287
|
-
const cropToSquare = useCallback(
|
|
288
|
-
async (
|
|
289
|
-
uri: string,
|
|
290
|
-
width: number,
|
|
291
|
-
height: number,
|
|
292
|
-
options?: ImageSaveOptions
|
|
293
|
-
): Promise<ImageManipulationResult | null> => {
|
|
294
|
-
setIsProcessing(true);
|
|
295
|
-
setError(null);
|
|
296
|
-
|
|
297
|
-
try {
|
|
298
|
-
const result = await ImageService.cropToSquare(uri, width, height, options);
|
|
299
|
-
|
|
300
|
-
if (!result) {
|
|
301
|
-
setError('Failed to crop to square');
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
return result;
|
|
305
|
-
} catch (err) {
|
|
306
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to crop to square';
|
|
307
|
-
setError(errorMessage);
|
|
308
|
-
return null;
|
|
309
|
-
} finally {
|
|
310
|
-
setIsProcessing(false);
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
[]
|
|
314
|
-
);
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Convert image format
|
|
318
|
-
*/
|
|
319
|
-
const convertFormat = useCallback(
|
|
320
|
-
async (
|
|
321
|
-
uri: string,
|
|
322
|
-
format: SaveFormat,
|
|
323
|
-
quality?: number
|
|
324
|
-
): Promise<ImageManipulationResult | null> => {
|
|
325
|
-
setIsProcessing(true);
|
|
326
|
-
setError(null);
|
|
327
|
-
|
|
328
|
-
try {
|
|
329
|
-
const result = await ImageService.convertFormat(uri, format, quality);
|
|
330
|
-
|
|
331
|
-
if (!result) {
|
|
332
|
-
setError('Failed to convert image format');
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return result;
|
|
336
|
-
} catch (err) {
|
|
337
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to convert image format';
|
|
338
|
-
setError(errorMessage);
|
|
339
|
-
return null;
|
|
340
|
-
} finally {
|
|
341
|
-
setIsProcessing(false);
|
|
342
|
-
}
|
|
343
|
-
},
|
|
344
|
-
[]
|
|
345
|
-
);
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Save image to device
|
|
349
|
-
*/
|
|
350
|
-
const saveImage = useCallback(
|
|
351
|
-
async (uri: string, filename?: string): Promise<string | null> => {
|
|
352
|
-
setIsProcessing(true);
|
|
353
|
-
setError(null);
|
|
354
|
-
|
|
355
|
-
try {
|
|
356
|
-
const savedUri = await ImageService.saveImage(uri, filename);
|
|
357
|
-
|
|
358
|
-
if (!savedUri) {
|
|
359
|
-
setError('Failed to save image');
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return savedUri;
|
|
363
|
-
} catch (err) {
|
|
364
|
-
const errorMessage = err instanceof Error ? err.message : 'Failed to save image';
|
|
365
|
-
setError(errorMessage);
|
|
366
|
-
return null;
|
|
367
|
-
} finally {
|
|
368
|
-
setIsProcessing(false);
|
|
369
|
-
}
|
|
370
|
-
},
|
|
371
|
-
[]
|
|
372
|
-
);
|
|
12
|
+
const transform = useImageTransform();
|
|
13
|
+
const conversion = useImageConversion();
|
|
373
14
|
|
|
374
15
|
return {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
manipulate,
|
|
381
|
-
compress,
|
|
382
|
-
resizeToFit,
|
|
383
|
-
createThumbnail,
|
|
384
|
-
cropToSquare,
|
|
385
|
-
convertFormat,
|
|
386
|
-
saveImage,
|
|
387
|
-
|
|
388
|
-
// State
|
|
389
|
-
isProcessing,
|
|
390
|
-
error,
|
|
16
|
+
...transform,
|
|
17
|
+
...conversion,
|
|
18
|
+
// Combined state
|
|
19
|
+
isProcessing: transform.isTransforming || conversion.isConverting,
|
|
20
|
+
error: transform.transformError || conversion.conversionError,
|
|
391
21
|
};
|
|
392
22
|
};
|
|
393
|
-
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { useImageOperation } from './useImageOperation';
|
|
3
|
+
import { ImageConversionService } from '../../infrastructure/services/ImageConversionService';
|
|
4
|
+
import { ImageStorageService } from '../../infrastructure/services/ImageStorageService';
|
|
5
|
+
import type { ImageSaveOptions, SaveFormat } from '../../domain/entities/ImageTypes';
|
|
6
|
+
|
|
7
|
+
export const useImageConversion = () => {
|
|
8
|
+
const { isProcessing, error, execute } = useImageOperation();
|
|
9
|
+
|
|
10
|
+
const compress = useCallback((uri: string, quality: number = 0.8) =>
|
|
11
|
+
execute(() => ImageConversionService.compress(uri, quality), 'Failed to compress'), [execute]);
|
|
12
|
+
|
|
13
|
+
const convertFormat = useCallback((uri: string, format: SaveFormat, quality?: number) =>
|
|
14
|
+
execute(() => ImageConversionService.convertFormat(uri, format, quality), 'Failed to convert'), [execute]);
|
|
15
|
+
|
|
16
|
+
const createThumbnail = useCallback((uri: string, size?: number, options?: ImageSaveOptions) =>
|
|
17
|
+
execute(() => ImageConversionService.createThumbnail(uri, size, options), 'Failed to create thumbnail'), [execute]);
|
|
18
|
+
|
|
19
|
+
const saveImage = useCallback((uri: string, filename?: string) =>
|
|
20
|
+
execute(() => ImageStorageService.saveImage(uri, filename), 'Failed to save'), [execute]);
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
compress, convertFormat, createThumbnail, saveImage,
|
|
24
|
+
isConverting: isProcessing, conversionError: error,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -10,7 +10,7 @@ import { ImageViewerService } from '../../infrastructure/services/ImageViewerSer
|
|
|
10
10
|
import type {
|
|
11
11
|
ImageViewerItem,
|
|
12
12
|
ImageGalleryOptions,
|
|
13
|
-
} from '../../domain/entities/
|
|
13
|
+
} from '../../domain/entities/ImageTypes';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* useImageGallery hook return type
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generic hook to handle image operation states (loading, error)
|
|
5
|
+
* adhering to DRY principles.
|
|
6
|
+
*/
|
|
7
|
+
export const useImageOperation = () => {
|
|
8
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
9
|
+
const [error, setError] = useState<string | null>(null);
|
|
10
|
+
|
|
11
|
+
const execute = useCallback(async <T>(
|
|
12
|
+
operation: () => Promise<T | null>,
|
|
13
|
+
errorMessage: string
|
|
14
|
+
): Promise<T | null> => {
|
|
15
|
+
setIsProcessing(true);
|
|
16
|
+
setError(null);
|
|
17
|
+
try {
|
|
18
|
+
const result = await operation();
|
|
19
|
+
if (!result) {
|
|
20
|
+
setError(errorMessage);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
} catch (err) {
|
|
25
|
+
setError(err instanceof Error ? err.message : errorMessage);
|
|
26
|
+
return null;
|
|
27
|
+
} finally {
|
|
28
|
+
setIsProcessing(false);
|
|
29
|
+
}
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
32
|
+
return { isProcessing, error, execute };
|
|
33
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { useImageOperation } from './useImageOperation';
|
|
3
|
+
import { ImageTransformService } from '../../infrastructure/services/ImageTransformService';
|
|
4
|
+
import type {
|
|
5
|
+
ImageManipulateAction,
|
|
6
|
+
ImageSaveOptions,
|
|
7
|
+
} from '../../domain/entities/ImageTypes';
|
|
8
|
+
|
|
9
|
+
export const useImageTransform = () => {
|
|
10
|
+
const { isProcessing, error, execute } = useImageOperation();
|
|
11
|
+
|
|
12
|
+
const resize = useCallback((uri: string, width?: number, height?: number, options?: ImageSaveOptions) =>
|
|
13
|
+
execute(() => ImageTransformService.resize(uri, width, height, options), 'Failed to resize'), [execute]);
|
|
14
|
+
|
|
15
|
+
const crop = useCallback((uri: string, cropArea: any, options?: ImageSaveOptions) =>
|
|
16
|
+
execute(() => ImageTransformService.crop(uri, cropArea, options), 'Failed to crop'), [execute]);
|
|
17
|
+
|
|
18
|
+
const rotate = useCallback((uri: string, degrees: number, options?: ImageSaveOptions) =>
|
|
19
|
+
execute(() => ImageTransformService.rotate(uri, degrees, options), 'Failed to rotate'), [execute]);
|
|
20
|
+
|
|
21
|
+
const flip = useCallback((uri: string, flipParams: any, options?: ImageSaveOptions) =>
|
|
22
|
+
execute(() => ImageTransformService.flip(uri, flipParams, options), 'Failed to flip'), [execute]);
|
|
23
|
+
|
|
24
|
+
const manipulate = useCallback((uri: string, action: ImageManipulateAction, options?: ImageSaveOptions) =>
|
|
25
|
+
execute(() => ImageTransformService.manipulate(uri, action, options), 'Failed to manipulate'), [execute]);
|
|
26
|
+
|
|
27
|
+
const resizeToFit = useCallback((uri: string, w: number, h: number, opts?: ImageSaveOptions) =>
|
|
28
|
+
execute(() => ImageTransformService.resizeToFit(uri, w, h, opts), 'Failed to resize to fit'), [execute]);
|
|
29
|
+
|
|
30
|
+
const cropToSquare = useCallback((uri: string, w: number, h: number, opts?: ImageSaveOptions) =>
|
|
31
|
+
execute(() => ImageTransformService.cropToSquare(uri, w, h, opts), 'Failed to crop square'), [execute]);
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
resize, crop, rotate, flip, manipulate, resizeToFit, cropToSquare,
|
|
35
|
+
isTransforming: isProcessing, transformError: error,
|
|
36
|
+
};
|
|
37
|
+
};
|