@umituz/react-native-image 1.1.4 → 1.1.6

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 (36) hide show
  1. package/package.json +2 -2
  2. package/src/domain/entities/ImageConstants.ts +32 -15
  3. package/src/domain/entities/ImageFilterTypes.ts +70 -0
  4. package/src/domain/entities/ImageTypes.ts +22 -7
  5. package/src/domain/utils/ImageUtils.ts +6 -6
  6. package/src/index.ts +47 -0
  7. package/src/infrastructure/services/ImageAIEnhancementService.ts +136 -0
  8. package/src/infrastructure/services/ImageAdvancedTransformService.ts +106 -0
  9. package/src/infrastructure/services/ImageAnnotationService.ts +189 -0
  10. package/src/infrastructure/services/ImageBatchService.ts +199 -0
  11. package/src/infrastructure/services/ImageConversionService.ts +51 -18
  12. package/src/infrastructure/services/ImageFilterService.ts +168 -0
  13. package/src/infrastructure/services/ImageMetadataService.ts +187 -0
  14. package/src/infrastructure/services/ImageSpecializedEnhancementService.ts +57 -0
  15. package/src/infrastructure/services/ImageStorageService.ts +22 -7
  16. package/src/infrastructure/services/ImageTransformService.ts +68 -101
  17. package/src/infrastructure/services/ImageViewerService.ts +3 -28
  18. package/src/infrastructure/utils/AIImageAnalysisUtils.ts +122 -0
  19. package/src/infrastructure/utils/CanvasRenderingService.ts +134 -0
  20. package/src/infrastructure/utils/FilterEffects.ts +51 -0
  21. package/src/infrastructure/utils/ImageErrorHandler.ts +40 -0
  22. package/src/infrastructure/utils/ImageQualityPresets.ts +110 -0
  23. package/src/infrastructure/utils/ImageValidator.ts +59 -0
  24. package/src/presentation/components/GalleryHeader.tsx +3 -4
  25. package/src/presentation/components/ImageGallery.tsx +7 -20
  26. package/src/presentation/hooks/useImage.ts +35 -5
  27. package/src/presentation/hooks/useImageAIEnhancement.ts +33 -0
  28. package/src/presentation/hooks/useImageAnnotation.ts +32 -0
  29. package/src/presentation/hooks/useImageBatch.ts +33 -0
  30. package/src/presentation/hooks/useImageConversion.ts +6 -3
  31. package/src/presentation/hooks/useImageEditor.ts +5 -11
  32. package/src/presentation/hooks/useImageFilter.ts +38 -0
  33. package/src/presentation/hooks/useImageGallery.ts +1 -60
  34. package/src/presentation/hooks/useImageMetadata.ts +28 -0
  35. package/src/presentation/hooks/useImageOperation.ts +14 -10
  36. package/src/presentation/hooks/useImageTransform.ts +13 -7
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Presentation - Image Annotation Hook
3
+ */
4
+
5
+ import { useCallback } from 'react';
6
+ import { useImageOperation } from './useImageOperation';
7
+ import { ImageAnnotationService, type ImageAnnotation, type TextOverlay, type DrawingElement, type WatermarkOptions } from '../../infrastructure/services/ImageAnnotationService';
8
+
9
+ export const useImageAnnotation = () => {
10
+ const { isProcessing, error, execute } = useImageOperation();
11
+
12
+ const addTextOverlay = useCallback((uri: string, overlay: TextOverlay) =>
13
+ execute(() => ImageAnnotationService.addTextOverlay(uri, overlay), 'Failed to add text'), [execute]);
14
+
15
+ const addDrawingElements = useCallback((uri: string, elements: DrawingElement[]) =>
16
+ execute(() => ImageAnnotationService.addDrawingElements(uri, elements), 'Failed to add drawing'), [execute]);
17
+
18
+ const addWatermark = useCallback((uri: string, options: WatermarkOptions) =>
19
+ execute(() => ImageAnnotationService.addWatermark(uri, options), 'Failed to add watermark'), [execute]);
20
+
21
+ const applyAnnotation = useCallback((uri: string, annotation: ImageAnnotation) =>
22
+ execute(() => ImageAnnotationService.applyAnnotation(uri, annotation), 'Failed to apply annotation'), [execute]);
23
+
24
+ return {
25
+ addTextOverlay,
26
+ addDrawingElements,
27
+ addWatermark,
28
+ applyAnnotation,
29
+ isAnnotating: isProcessing,
30
+ annotationError: error,
31
+ };
32
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Presentation - Image Batch Hook
3
+ */
4
+
5
+ import { useCallback } from 'react';
6
+ import { useImageOperation } from './useImageOperation';
7
+ import { ImageBatchService, type BatchOperation, type BatchProcessingOptions } from '../../infrastructure/services/ImageBatchService';
8
+ import type { ImageFilter } from '../../domain/entities/ImageFilterTypes';
9
+
10
+ export const useImageBatch = () => {
11
+ const { isProcessing, error, execute } = useImageOperation();
12
+
13
+ const processBatch = useCallback((operations: BatchOperation[], options?: BatchProcessingOptions) =>
14
+ execute(() => ImageBatchService.processBatch(operations, options), 'Failed to process batch'), [execute]);
15
+
16
+ const resizeBatch = useCallback((uris: string[], width?: number, height?: number, options?: BatchProcessingOptions & { saveOptions?: any }) =>
17
+ execute(() => ImageBatchService.resizeBatch(uris, width, height, options), 'Failed to resize batch'), [execute]);
18
+
19
+ const compressBatch = useCallback((uris: string[], quality?: number, options?: BatchProcessingOptions) =>
20
+ execute(() => ImageBatchService.compressBatch(uris, quality, options), 'Failed to compress batch'), [execute]);
21
+
22
+ const filterBatch = useCallback((uris: string[], filter: ImageFilter, options?: BatchProcessingOptions) =>
23
+ execute(() => ImageBatchService.filterBatch(uris, filter, options), 'Failed to filter batch'), [execute]);
24
+
25
+ return {
26
+ processBatch,
27
+ resizeBatch,
28
+ compressBatch,
29
+ filterBatch,
30
+ isBatchProcessing: isProcessing,
31
+ batchError: error,
32
+ };
33
+ };
@@ -1,3 +1,6 @@
1
+ /**
2
+ * Presentation - Image Conversion Hook
3
+ */
1
4
  import { useCallback } from 'react';
2
5
  import { useImageOperation } from './useImageOperation';
3
6
  import { ImageConversionService } from '../../infrastructure/services/ImageConversionService';
@@ -7,17 +10,17 @@ import type { ImageSaveOptions, SaveFormat } from '../../domain/entities/ImageTy
7
10
  export const useImageConversion = () => {
8
11
  const { isProcessing, error, execute } = useImageOperation();
9
12
 
10
- const compress = useCallback((uri: string, quality: number = 0.8) =>
13
+ const compress = useCallback((uri: string, quality?: number) =>
11
14
  execute(() => ImageConversionService.compress(uri, quality), 'Failed to compress'), [execute]);
12
15
 
13
16
  const convertFormat = useCallback((uri: string, format: SaveFormat, quality?: number) =>
14
- execute(() => ImageConversionService.convertFormat(uri, format, quality), 'Failed to convert'), [execute]);
17
+ execute(() => ImageConversionService.convertFormat(uri, format, quality), 'Failed to convert format'), [execute]);
15
18
 
16
19
  const createThumbnail = useCallback((uri: string, size?: number, options?: ImageSaveOptions) =>
17
20
  execute(() => ImageConversionService.createThumbnail(uri, size, options), 'Failed to create thumbnail'), [execute]);
18
21
 
19
22
  const saveImage = useCallback((uri: string, filename?: string) =>
20
- execute(() => ImageStorageService.saveImage(uri, filename), 'Failed to save'), [execute]);
23
+ execute(() => ImageStorageService.saveImage(uri, filename), 'Failed to save image'), [execute]);
21
24
 
22
25
  return {
23
26
  compress, convertFormat, createThumbnail, saveImage,
@@ -1,10 +1,10 @@
1
1
  /**
2
- * useImageEditor Hook
3
- * Provides image editing functionality with crop, rotate, flip
2
+ * Presentation - Image Editor Hook
3
+ *
4
+ * NOTE: This hook is deprecated - use useImageTransform instead
4
5
  */
5
6
 
6
7
  import { useState, useCallback } from 'react';
7
- import * as ImageManipulator from 'expo-image-manipulator';
8
8
  import type { Action } from 'expo-image-manipulator';
9
9
 
10
10
  interface UseImageEditorOptions {
@@ -30,20 +30,14 @@ export function useImageEditor({ onSave }: UseImageEditorOptions = {}) {
30
30
  if (!currentUri) return;
31
31
 
32
32
  try {
33
- const result = await ImageManipulator.manipulateAsync(
34
- currentUri,
35
- actions,
36
- { compress: 0.9, format: ImageManipulator.SaveFormat.JPEG }
37
- );
38
-
39
33
  if (onSave) {
40
- await onSave(result.uri);
34
+ await onSave(currentUri);
41
35
  }
42
36
 
43
37
  setIsEditing(false);
44
38
  setCurrentUri(null);
45
39
 
46
- return result.uri;
40
+ return currentUri;
47
41
  } catch (error) {
48
42
  throw error;
49
43
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Presentation - Image Filter Hook
3
+ */
4
+
5
+ import { useCallback } from 'react';
6
+ import { useImageOperation } from './useImageOperation';
7
+ import { ImageFilterService } from '../../infrastructure/services/ImageFilterService';
8
+ import type {
9
+ ImageFilter,
10
+ ImageColorAdjustment,
11
+ ImageQualityMetrics,
12
+ ImageColorPalette,
13
+ } from '../../domain/entities/ImageFilterTypes';
14
+
15
+ export const useImageFilter = () => {
16
+ const { isProcessing, error, execute } = useImageOperation();
17
+
18
+ const applyFilter = useCallback((uri: string, filter: ImageFilter) =>
19
+ execute(() => ImageFilterService.applyFilter(uri, filter), 'Failed to apply filter'), [execute]);
20
+
21
+ const applyColorAdjustment = useCallback((uri: string, adjustment: ImageColorAdjustment) =>
22
+ execute(() => ImageFilterService.applyColorAdjustment(uri, adjustment), 'Failed to adjust colors'), [execute]);
23
+
24
+ const analyzeQuality = useCallback((uri: string) =>
25
+ execute(() => ImageFilterService.analyzeQuality(uri), 'Failed to analyze quality'), [execute]);
26
+
27
+ const extractColorPalette = useCallback((uri: string, colorCount?: number) =>
28
+ execute(() => ImageFilterService.extractColorPalette(uri, colorCount), 'Failed to extract colors'), [execute]);
29
+
30
+ return {
31
+ applyFilter,
32
+ applyColorAdjustment,
33
+ analyzeQuality,
34
+ extractColorPalette,
35
+ isFiltering: isProcessing,
36
+ filterError: error,
37
+ };
38
+ };
@@ -1,8 +1,5 @@
1
1
  /**
2
- * Image Domain - useImageGallery Hook
3
- *
4
- * React hook for image gallery and viewer using react-native-image-viewing.
5
- * Provides full-screen image viewer with zoom, swipe, and gallery features.
2
+ * Presentation - Image Gallery Hook
6
3
  */
7
4
 
8
5
  import { useState, useCallback, useMemo } from 'react';
@@ -12,51 +9,16 @@ import type {
12
9
  ImageGalleryOptions,
13
10
  } from '../../domain/entities/ImageTypes';
14
11
 
15
- /**
16
- * useImageGallery hook return type
17
- */
18
12
  export interface UseImageGalleryReturn {
19
- // State
20
13
  visible: boolean;
21
14
  currentIndex: number;
22
15
  images: ImageViewerItem[];
23
-
24
- // Actions
25
16
  open: (images: ImageViewerItem[] | string[], startIndex?: number, options?: ImageGalleryOptions) => void;
26
17
  close: () => void;
27
18
  setIndex: (index: number) => void;
28
-
29
- // Gallery options
30
19
  options: ImageGalleryOptions;
31
20
  }
32
21
 
33
- /**
34
- * useImageGallery hook for full-screen image viewer
35
- *
36
- * USAGE:
37
- * ```typescript
38
- * const { visible, currentIndex, images, open, close, options } = useImageGallery();
39
- *
40
- * // Open gallery with image URIs
41
- * open(['uri1', 'uri2', 'uri3']);
42
- *
43
- * // Open gallery with metadata
44
- * open([
45
- * { uri: 'uri1', title: 'Photo 1' },
46
- * { uri: 'uri2', title: 'Photo 2' },
47
- * ], 0, { backgroundColor: '#000000' });
48
- *
49
- * // Render ImageViewing component
50
- * <ImageViewing
51
- * images={images}
52
- * imageIndex={currentIndex}
53
- * visible={visible}
54
- * onRequestClose={close}
55
- * onIndexChange={setIndex}
56
- * {...options}
57
- * />
58
- * ```
59
- */
60
22
  export const useImageGallery = (
61
23
  defaultOptions?: ImageGalleryOptions
62
24
  ): UseImageGalleryReturn => {
@@ -67,16 +29,12 @@ export const useImageGallery = (
67
29
  defaultOptions || ImageViewerService.getDefaultOptions()
68
30
  );
69
31
 
70
- /**
71
- * Open gallery with images
72
- */
73
32
  const open = useCallback(
74
33
  (
75
34
  imageData: ImageViewerItem[] | string[],
76
35
  startIndex: number = 0,
77
36
  options?: ImageGalleryOptions
78
37
  ) => {
79
- // Prepare images based on input type
80
38
  const preparedImages =
81
39
  typeof imageData[0] === 'string'
82
40
  ? ImageViewerService.prepareImages(imageData as string[])
@@ -85,7 +43,6 @@ export const useImageGallery = (
85
43
  setImages(preparedImages);
86
44
  setCurrentIndex(options?.index ?? startIndex);
87
45
 
88
- // Merge options with defaults
89
46
  if (options) {
90
47
  setGalleryOptions({
91
48
  ...galleryOptions,
@@ -98,33 +55,22 @@ export const useImageGallery = (
98
55
  [galleryOptions]
99
56
  );
100
57
 
101
- /**
102
- * Close gallery
103
- */
104
58
  const close = useCallback(() => {
105
59
  setVisible(false);
106
60
 
107
- // Call onDismiss if provided
108
61
  if (galleryOptions.onDismiss) {
109
62
  galleryOptions.onDismiss();
110
63
  }
111
64
  }, [galleryOptions]);
112
65
 
113
- /**
114
- * Set current image index
115
- */
116
66
  const setIndex = useCallback((index: number) => {
117
67
  setCurrentIndex(index);
118
68
 
119
- // Call onIndexChange if provided
120
69
  if (galleryOptions.onIndexChange) {
121
70
  galleryOptions.onIndexChange(index);
122
71
  }
123
72
  }, [galleryOptions]);
124
73
 
125
- /**
126
- * Memoized options for ImageViewing component
127
- */
128
74
  const options = useMemo(() => ({
129
75
  backgroundColor: galleryOptions.backgroundColor || '#000000',
130
76
  swipeToCloseEnabled: galleryOptions.swipeToCloseEnabled ?? true,
@@ -132,17 +78,12 @@ export const useImageGallery = (
132
78
  }), [galleryOptions]);
133
79
 
134
80
  return {
135
- // State
136
81
  visible,
137
82
  currentIndex,
138
83
  images,
139
-
140
- // Actions
141
84
  open,
142
85
  close,
143
86
  setIndex,
144
-
145
- // Gallery options
146
87
  options,
147
88
  };
148
89
  };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Presentation - Image Metadata Hook
3
+ */
4
+
5
+ import { useCallback } from 'react';
6
+ import { useImageOperation } from './useImageOperation';
7
+ import { ImageMetadataService, type ImageMetadataExtractionOptions } from '../../infrastructure/services/ImageMetadataService';
8
+
9
+ export const useImageMetadata = () => {
10
+ const { isProcessing, error, execute } = useImageOperation();
11
+
12
+ const extractMetadata = useCallback((uri: string, options?: ImageMetadataExtractionOptions) =>
13
+ execute(() => ImageMetadataService.extractMetadata(uri, options), 'Failed to extract metadata'), [execute]);
14
+
15
+ const getBasicInfo = useCallback((uri: string) =>
16
+ execute(() => ImageMetadataService.getBasicInfo(uri), 'Failed to get basic info'), [execute]);
17
+
18
+ const hasMetadata = useCallback((uri: string) =>
19
+ execute(() => ImageMetadataService.hasMetadata(uri), 'Failed to check metadata'), [execute]);
20
+
21
+ return {
22
+ extractMetadata,
23
+ getBasicInfo,
24
+ hasMetadata,
25
+ isExtracting: isProcessing,
26
+ metadataError: error,
27
+ };
28
+ };
@@ -1,28 +1,32 @@
1
- import { useState, useCallback } from 'react';
2
-
3
1
  /**
4
- * Generic hook to handle image operation states (loading, error)
5
- * adhering to DRY principles.
2
+ * Presentation - Image Operation Hook
3
+ *
4
+ * Generic state management for async image operations
6
5
  */
6
+
7
+ import { useState, useCallback } from 'react';
8
+ import { ImageError } from '../../infrastructure/utils/ImageErrorHandler';
9
+
7
10
  export const useImageOperation = () => {
8
11
  const [isProcessing, setIsProcessing] = useState(false);
9
12
  const [error, setError] = useState<string | null>(null);
10
13
 
11
14
  const execute = useCallback(async <T>(
12
- operation: () => Promise<T | null>,
15
+ operation: () => Promise<T>,
13
16
  errorMessage: string
14
17
  ): Promise<T | null> => {
15
18
  setIsProcessing(true);
16
19
  setError(null);
20
+
17
21
  try {
18
22
  const result = await operation();
19
- if (!result) {
20
- setError(errorMessage);
21
- return null;
22
- }
23
23
  return result;
24
24
  } catch (err) {
25
- setError(err instanceof Error ? err.message : errorMessage);
25
+ if (err instanceof ImageError) {
26
+ setError(err.message);
27
+ } else {
28
+ setError(err instanceof Error ? err.message : errorMessage);
29
+ }
26
30
  return null;
27
31
  } finally {
28
32
  setIsProcessing(false);
@@ -1,9 +1,15 @@
1
+ /**
2
+ * Presentation - Image Transform Hook
3
+ */
1
4
  import { useCallback } from 'react';
2
5
  import { useImageOperation } from './useImageOperation';
3
6
  import { ImageTransformService } from '../../infrastructure/services/ImageTransformService';
7
+ import { ImageAdvancedTransformService } from '../../infrastructure/services/ImageAdvancedTransformService';
4
8
  import type {
5
9
  ImageManipulateAction,
6
10
  ImageSaveOptions,
11
+ ImageCropArea,
12
+ ImageFlipOptions,
7
13
  } from '../../domain/entities/ImageTypes';
8
14
 
9
15
  export const useImageTransform = () => {
@@ -12,23 +18,23 @@ export const useImageTransform = () => {
12
18
  const resize = useCallback((uri: string, width?: number, height?: number, options?: ImageSaveOptions) =>
13
19
  execute(() => ImageTransformService.resize(uri, width, height, options), 'Failed to resize'), [execute]);
14
20
 
15
- const crop = useCallback((uri: string, cropArea: any, options?: ImageSaveOptions) =>
21
+ const crop = useCallback((uri: string, cropArea: ImageCropArea, options?: ImageSaveOptions) =>
16
22
  execute(() => ImageTransformService.crop(uri, cropArea, options), 'Failed to crop'), [execute]);
17
23
 
18
24
  const rotate = useCallback((uri: string, degrees: number, options?: ImageSaveOptions) =>
19
25
  execute(() => ImageTransformService.rotate(uri, degrees, options), 'Failed to rotate'), [execute]);
20
26
 
21
- const flip = useCallback((uri: string, flipParams: any, options?: ImageSaveOptions) =>
27
+ const flip = useCallback((uri: string, flipParams: ImageFlipOptions, options?: ImageSaveOptions) =>
22
28
  execute(() => ImageTransformService.flip(uri, flipParams, options), 'Failed to flip'), [execute]);
23
29
 
24
30
  const manipulate = useCallback((uri: string, action: ImageManipulateAction, options?: ImageSaveOptions) =>
25
- execute(() => ImageTransformService.manipulate(uri, action, options), 'Failed to manipulate'), [execute]);
31
+ execute(() => ImageAdvancedTransformService.manipulate(uri, action, options), 'Failed to manipulate'), [execute]);
26
32
 
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]);
33
+ const resizeToFit = useCallback((uri: string, maxWidth: number, maxHeight: number, options?: ImageSaveOptions) =>
34
+ execute(() => ImageAdvancedTransformService.resizeToFit(uri, maxWidth, maxHeight, options), 'Failed to resize to fit'), [execute]);
29
35
 
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]);
36
+ const cropToSquare = useCallback((uri: string, width: number, height: number, options?: ImageSaveOptions) =>
37
+ execute(() => ImageAdvancedTransformService.cropToSquare(uri, width, height, options), 'Failed to crop square'), [execute]);
32
38
 
33
39
  return {
34
40
  resize, crop, rotate, flip, manipulate, resizeToFit, cropToSquare,