@umituz/react-native-image 1.1.5 → 1.2.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 (37) hide show
  1. package/package.json +25 -10
  2. package/src/domain/entities/EditorTypes.ts +180 -0
  3. package/src/domain/entities/ImageFilterTypes.ts +70 -0
  4. package/src/index.ts +54 -0
  5. package/src/infrastructure/services/ImageAIEnhancementService.ts +136 -0
  6. package/src/infrastructure/services/ImageAnnotationService.ts +189 -0
  7. package/src/infrastructure/services/ImageBatchService.ts +199 -0
  8. package/src/infrastructure/services/ImageEditorService.ts +274 -0
  9. package/src/infrastructure/services/ImageFilterService.ts +168 -0
  10. package/src/infrastructure/services/ImageMetadataService.ts +187 -0
  11. package/src/infrastructure/services/ImageSpecializedEnhancementService.ts +57 -0
  12. package/src/infrastructure/utils/AIImageAnalysisUtils.ts +122 -0
  13. package/src/infrastructure/utils/CanvasRenderingService.ts +134 -0
  14. package/src/infrastructure/utils/CropTool.ts +260 -0
  15. package/src/infrastructure/utils/DrawingEngine.ts +210 -0
  16. package/src/infrastructure/utils/FilterEffects.ts +51 -0
  17. package/src/infrastructure/utils/FilterProcessor.ts +361 -0
  18. package/src/infrastructure/utils/ImageQualityPresets.ts +110 -0
  19. package/src/infrastructure/utils/LayerManager.ts +158 -0
  20. package/src/infrastructure/utils/ShapeRenderer.ts +168 -0
  21. package/src/infrastructure/utils/TextEditor.ts +273 -0
  22. package/src/presentation/components/CropComponent.tsx +183 -0
  23. package/src/presentation/components/Editor.tsx +261 -0
  24. package/src/presentation/components/EditorCanvas.tsx +135 -0
  25. package/src/presentation/components/EditorPanel.tsx +321 -0
  26. package/src/presentation/components/EditorToolbar.tsx +180 -0
  27. package/src/presentation/components/FilterSlider.tsx +123 -0
  28. package/src/presentation/components/GalleryHeader.tsx +87 -25
  29. package/src/presentation/components/ImageGallery.tsx +97 -48
  30. package/src/presentation/hooks/useEditorTools.ts +188 -0
  31. package/src/presentation/hooks/useImage.ts +33 -2
  32. package/src/presentation/hooks/useImageAIEnhancement.ts +33 -0
  33. package/src/presentation/hooks/useImageAnnotation.ts +32 -0
  34. package/src/presentation/hooks/useImageBatch.ts +33 -0
  35. package/src/presentation/hooks/useImageEditor.ts +165 -38
  36. package/src/presentation/hooks/useImageFilter.ts +38 -0
  37. package/src/presentation/hooks/useImageMetadata.ts +28 -0
@@ -1,55 +1,182 @@
1
1
  /**
2
- * Presentation - Image Editor Hook
3
- *
4
- * NOTE: This hook is deprecated - use useImageTransform instead
2
+ * Presentation - Advanced Image Editor Hook
5
3
  */
6
4
 
7
- import { useState, useCallback } from 'react';
8
- import type { Action } from 'expo-image-manipulator';
5
+ import { useState, useCallback, useRef } from 'react';
6
+ import type {
7
+ EditorState,
8
+ EditorTool,
9
+ EditorOptions,
10
+ EditorExportOptions,
11
+ } from '../../domain/entities/EditorTypes';
12
+ import { ImageEditorService } from '../../infrastructure/services/ImageEditorService';
13
+ import type { ImageManipulationResult } from '../../domain/entities/ImageTypes';
9
14
 
10
- interface UseImageEditorOptions {
11
- onSave?: (uri: string) => void | Promise<void>;
15
+ interface UseEditorConfig {
16
+ onSave?: (result: ImageManipulationResult) => void | Promise<void>;
17
+ onCancel?: () => void;
18
+ options?: EditorOptions;
12
19
  }
13
20
 
14
- export function useImageEditor({ onSave }: UseImageEditorOptions = {}) {
15
- const [isEditing, setIsEditing] = useState(false);
16
- const [currentUri, setCurrentUri] = useState<string | null>(null);
21
+ export function useImageEditor({ onSave, onCancel, options }: UseEditorConfig = {}) {
22
+ const [editorState, setEditorState] = useState<EditorState | null>(null);
23
+ const [isProcessing, setIsProcessing] = useState(false);
24
+ const [error, setError] = useState<string | null>(null);
25
+
26
+ const canvasRef = useRef<HTMLCanvasElement | null>(null);
17
27
 
18
- const startEditing = useCallback((uri: string) => {
19
- setCurrentUri(uri);
20
- setIsEditing(true);
21
- }, []);
28
+ const initializeEditor = useCallback(async (uri: string) => {
29
+ try {
30
+ setError(null);
31
+ setIsProcessing(true);
32
+
33
+ // Get image dimensions
34
+ const dimensions = await getImageDimensions(uri);
35
+ const state = ImageEditorService.createInitialState(uri, dimensions, options);
36
+
37
+ setEditorState(state);
38
+ setIsProcessing(false);
39
+ } catch (err) {
40
+ setError(err instanceof Error ? err.message : 'Failed to initialize editor');
41
+ setIsProcessing(false);
42
+ }
43
+ }, [options]);
22
44
 
23
- const cancelEditing = useCallback(() => {
24
- setIsEditing(false);
25
- setCurrentUri(null);
26
- }, []);
45
+ const setTool = useCallback((tool: EditorTool) => {
46
+ if (!editorState) return;
47
+
48
+ const newState = ImageEditorService.setTool(editorState, tool);
49
+ setEditorState(newState);
50
+ }, [editorState]);
27
51
 
28
- const saveEdit = useCallback(
29
- async (actions: Action[]) => {
30
- if (!currentUri) return;
52
+ const addLayer = useCallback((name?: string) => {
53
+ if (!editorState) return;
54
+
55
+ const newState = ImageEditorService.addLayer(editorState, name);
56
+ setEditorState(newState);
57
+ }, [editorState]);
31
58
 
32
- try {
33
- if (onSave) {
34
- await onSave(currentUri);
35
- }
59
+ const removeLayer = useCallback((layerId: string) => {
60
+ if (!editorState) return;
61
+
62
+ try {
63
+ const newState = ImageEditorService.removeLayer(editorState, layerId);
64
+ setEditorState(newState);
65
+ } catch (err) {
66
+ setError(err instanceof Error ? err.message : 'Failed to remove layer');
67
+ }
68
+ }, [editorState]);
36
69
 
37
- setIsEditing(false);
38
- setCurrentUri(null);
70
+ const undo = useCallback(() => {
71
+ if (!editorState) return;
72
+
73
+ const newState = ImageEditorService.undo(editorState);
74
+ setEditorState(newState);
75
+ }, [editorState]);
39
76
 
40
- return currentUri;
41
- } catch (error) {
42
- throw error;
77
+ const redo = useCallback(() => {
78
+ if (!editorState) return;
79
+
80
+ const newState = ImageEditorService.redo(editorState);
81
+ setEditorState(newState);
82
+ }, [editorState]);
83
+
84
+ const exportImage = useCallback(async (exportOptions?: EditorExportOptions) => {
85
+ if (!editorState || !canvasRef.current) return null;
86
+
87
+ try {
88
+ setIsProcessing(true);
89
+ setError(null);
90
+
91
+ // Compose all layers
92
+ const canvas = canvasRef.current;
93
+ const result = await composeAndExport(canvas, editorState, exportOptions);
94
+
95
+ if (onSave) {
96
+ await onSave(result);
43
97
  }
44
- },
45
- [currentUri, onSave]
46
- );
98
+
99
+ setIsProcessing(false);
100
+ return result;
101
+ } catch (err) {
102
+ setError(err instanceof Error ? err.message : 'Failed to export image');
103
+ setIsProcessing(false);
104
+ return null;
105
+ }
106
+ }, [editorState, onSave]);
107
+
108
+ const cancel = useCallback(() => {
109
+ setEditorState(null);
110
+ setError(null);
111
+ onCancel?.();
112
+ }, [onCancel]);
47
113
 
48
114
  return {
49
- isEditing,
50
- currentUri,
51
- startEditing,
52
- cancelEditing,
53
- saveEdit,
115
+ // State
116
+ editorState,
117
+ isProcessing,
118
+ error,
119
+ canUndo: editorState ? ImageEditorService.canUndo(editorState) : false,
120
+ canRedo: editorState ? ImageEditorService.canRedo(editorState) : false,
121
+
122
+ // Actions
123
+ initializeEditor,
124
+ setTool,
125
+ addLayer,
126
+ removeLayer,
127
+ undo,
128
+ redo,
129
+ exportImage,
130
+ cancel,
131
+
132
+ // Refs
133
+ canvasRef,
54
134
  };
55
135
  }
136
+
137
+ async function getImageDimensions(uri: string): Promise<{ width: number; height: number }> {
138
+ return new Promise((resolve) => {
139
+ const img = new Image();
140
+ img.onload = () => {
141
+ resolve({ width: img.width, height: img.height });
142
+ };
143
+ img.src = uri;
144
+ });
145
+ }
146
+
147
+ async function composeAndExport(
148
+ canvas: HTMLCanvasElement,
149
+ state: EditorState,
150
+ options?: EditorExportOptions
151
+ ): Promise<ImageManipulationResult> {
152
+ const ctx = canvas.getContext('2d');
153
+ if (!ctx) throw new Error('Failed to get canvas context');
154
+
155
+ // Clear canvas
156
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
157
+
158
+ // Apply all layers
159
+ const visibleLayers = ImageEditorService.getVisibleLayers(state);
160
+
161
+ // Background layer (original image)
162
+ if (visibleLayers.length > 0) {
163
+ const backgroundLayer = visibleLayers[0];
164
+ // Would render original image here
165
+ }
166
+
167
+ // Export canvas to blob
168
+ return new Promise((resolve) => {
169
+ canvas.toBlob(async (blob) => {
170
+ if (!blob) throw new Error('Failed to create blob');
171
+
172
+ const url = URL.createObjectURL(blob);
173
+ resolve({
174
+ uri: url,
175
+ width: canvas.width,
176
+ height: canvas.height,
177
+ });
178
+
179
+ URL.revokeObjectURL(url);
180
+ }, options?.format || 'jpeg', options?.quality || 0.9);
181
+ });
182
+ }
@@ -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
+ };
@@ -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
+ };