@umituz/react-native-image 1.3.8 → 1.3.9

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.8",
3
+ "version": "1.3.9",
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",
package/src/index.ts CHANGED
@@ -60,7 +60,6 @@ export {
60
60
  // =============================================================================
61
61
 
62
62
  export { ImageTransformService } from './infrastructure/services/ImageTransformService';
63
- export { ImageAdvancedTransformService } from './infrastructure/services/ImageAdvancedTransformService';
64
63
  export { ImageConversionService } from './infrastructure/services/ImageConversionService';
65
64
  export { ImageStorageService } from './infrastructure/services/ImageStorageService';
66
65
  export {
@@ -69,10 +68,9 @@ export {
69
68
  } from './infrastructure/services/ImageViewerService';
70
69
 
71
70
  export { ImageBatchService, type BatchOperation, type BatchProcessingOptions, type BatchProcessingResult } from './infrastructure/services/ImageBatchService';
72
- export { ImageAIEnhancementService, type AutoEnhancementOptions, type EnhancementResult } from './infrastructure/services/ImageAIEnhancementService';
71
+ export { ImageEnhanceService, type AutoEnhancementOptions, type EnhancementResult } from './infrastructure/services/ImageEnhanceService';
73
72
  export { ImageMetadataService, type ImageMetadataExtractionOptions } from './infrastructure/services/ImageMetadataService';
74
73
  export { ImageQualityPresetService, type QualityPreset, type QualityPresets, IMAGE_QUALITY_PRESETS } from './infrastructure/utils/ImageQualityPresets';
75
- export { ImageSpecializedEnhancementService } from './infrastructure/services/ImageSpecializedEnhancementService';
76
74
  export { ImageTemplateService } from './infrastructure/services/ImageTemplateService';
77
75
 
78
76
  // =============================================================================
@@ -91,7 +89,7 @@ export {
91
89
  } from './presentation/hooks/useImageGallery';
92
90
 
93
91
  export { useImageBatch } from './presentation/hooks/useImageBatch';
94
- export { useImageAIEnhancement } from './presentation/hooks/useImageAIEnhancement';
92
+ export { useImageEnhance } from './presentation/hooks/useImageEnhance';
95
93
  export { useImageMetadata } from './presentation/hooks/useImageMetadata';
96
94
 
97
95
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Image Infrastructure - AI Enhancement Service
2
+ * Image Infrastructure - Enhance Service
3
3
  *
4
4
  * AI-powered image enhancement and automatic adjustments
5
5
  */
@@ -11,7 +11,6 @@ import type {
11
11
  } from '../../domain/entities/ImageFilterTypes';
12
12
  import { ImageValidator } from '../utils/ImageValidator';
13
13
  import { ImageErrorHandler, IMAGE_ERROR_CODES } from '../utils/ImageErrorHandler';
14
- import { AIImageAnalysisUtils } from '../utils/AIImageAnalysisUtils';
15
14
 
16
15
  export interface AutoEnhancementOptions {
17
16
  enhanceBrightness?: boolean;
@@ -29,49 +28,7 @@ export interface EnhancementResult {
29
28
  improvementScore: number;
30
29
  }
31
30
 
32
- export class ImageAIEnhancementService {
33
- private static calculateHistogram(imageData: Uint8ClampedArray): number[] {
34
- const histogram = new Array(256).fill(0);
35
- for (let i = 0; i < imageData.length; i += 4) {
36
- const gray = Math.round(0.299 * imageData[i] + 0.587 * imageData[i + 1] + 0.114 * imageData[i + 2]);
37
- histogram[gray]++;
38
- }
39
- return histogram;
40
- }
41
-
42
- private static calculateOptimalBrightness(histogram: number[]): number {
43
- const totalPixels = histogram.reduce((sum, count) => sum + count, 0);
44
- let sum = 0;
45
-
46
- for (let i = 0; i < 256; i++) {
47
- sum += histogram[i] * i;
48
- }
49
-
50
- const meanBrightness = sum / totalPixels;
51
- const targetBrightness = 128;
52
-
53
- return (targetBrightness - meanBrightness) / 255;
54
- }
55
-
56
- private static calculateOptimalContrast(histogram: number[]): number {
57
- const totalPixels = histogram.reduce((sum, count) => sum + count, 0);
58
- let mean = 0;
59
- let variance = 0;
60
-
61
- for (let i = 0; i < 256; i++) {
62
- mean += (histogram[i] / totalPixels) * i;
63
- }
64
-
65
- for (let i = 0; i < 256; i++) {
66
- variance += (histogram[i] / totalPixels) * Math.pow(i - mean, 2);
67
- }
68
-
69
- const standardDeviation = Math.sqrt(variance);
70
- const targetStandardDeviation = 80;
71
-
72
- return Math.max(-1, Math.min(1, (targetStandardDeviation - standardDeviation) / 100));
73
- }
74
-
31
+ export class ImageEnhanceService {
75
32
  static async analyzeImage(uri: string): Promise<ImageQualityMetrics> {
76
33
  try {
77
34
  const uriValidation = ImageValidator.validateUri(uri);
@@ -105,23 +62,19 @@ export class ImageAIEnhancementService {
105
62
  enhanceBrightness = true,
106
63
  enhanceContrast = true,
107
64
  enhanceColor = true,
108
- reduceNoise = false,
109
- sharpen = false,
110
- targetQuality = 85,
111
65
  } = options;
112
66
 
113
- const originalMetrics = await ImageAIEnhancementService.analyzeImage(uri);
67
+ const originalMetrics = await this.analyzeImage(uri);
114
68
  const adjustments: ImageColorAdjustment = {};
115
69
 
116
70
  if (enhanceBrightness) adjustments.brightness = 0.1;
117
71
  if (enhanceContrast) adjustments.contrast = 0.15;
118
72
  if (enhanceColor) adjustments.saturation = 0.1;
119
73
 
120
- const enhancedMetrics = await ImageAIEnhancementService.analyzeImage(uri);
121
- const improvementScore = (
122
- (enhancedMetrics.overallQuality - originalMetrics.overallQuality) /
123
- originalMetrics.overallQuality
124
- ) * 100;
74
+ const enhancedMetrics = await this.analyzeImage(uri);
75
+ const improvementScore = originalMetrics.overallQuality > 0
76
+ ? ((enhancedMetrics.overallQuality - originalMetrics.overallQuality) / originalMetrics.overallQuality) * 100
77
+ : 0;
125
78
 
126
79
  return {
127
80
  originalMetrics,
@@ -133,4 +86,38 @@ export class ImageAIEnhancementService {
133
86
  throw ImageErrorHandler.handleUnknownError(error, 'autoEnhance');
134
87
  }
135
88
  }
136
- }
89
+
90
+ static async enhancePortrait(uri: string): Promise<ImageManipulationResult> {
91
+ try {
92
+ const uriValidation = ImageValidator.validateUri(uri);
93
+ if (!uriValidation.isValid) {
94
+ throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'enhancePortrait');
95
+ }
96
+
97
+ return {
98
+ uri,
99
+ width: 0,
100
+ height: 0,
101
+ };
102
+ } catch (error) {
103
+ throw ImageErrorHandler.handleUnknownError(error, 'enhancePortrait');
104
+ }
105
+ }
106
+
107
+ static async enhanceLandscape(uri: string): Promise<ImageManipulationResult> {
108
+ try {
109
+ const uriValidation = ImageValidator.validateUri(uri);
110
+ if (!uriValidation.isValid) {
111
+ throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'enhanceLandscape');
112
+ }
113
+
114
+ return {
115
+ uri,
116
+ width: 0,
117
+ height: 0,
118
+ };
119
+ } catch (error) {
120
+ throw ImageErrorHandler.handleUnknownError(error, 'enhanceLandscape');
121
+ }
122
+ }
123
+ }
@@ -7,12 +7,16 @@ import { MemeTemplateOptions } from '../../domain/entities/ImageTemplateTypes';
7
7
  */
8
8
  export class ImageTemplateService {
9
9
  /**
10
- * Generates a Memegen.link URL for a given template and texts
10
+ * Generates a meme URL for a given template and texts
11
11
  *
12
12
  * @param options Meme configuration (templateKey, topText, bottomText)
13
- * @returns Formatted memegen.link URL
13
+ * @param baseUrl Optional base URL for the image generation service
14
+ * @returns Formatted image URL
14
15
  */
15
- static generateMemeUrl(options: MemeTemplateOptions): string {
16
+ static generateMemeUrl(
17
+ options: MemeTemplateOptions,
18
+ baseUrl: string = 'https://api.memegen.link'
19
+ ): string {
16
20
  const { templateKey, topText = '', bottomText = '', style, width, height } = options;
17
21
 
18
22
  // Internal helper for memegen-specific encoding
@@ -32,7 +36,9 @@ export class ImageTemplateService {
32
36
  const top = encodeMemeText(topText);
33
37
  const bottom = encodeMemeText(bottomText);
34
38
 
35
- let url = `https://api.memegen.link/images/${templateKey}/${top}/${bottom}.png`;
39
+ // Ensure baseUrl doesn't have a trailing slash
40
+ const base = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
41
+ let url = `${base}/images/${templateKey}/${top}/${bottom}.png`;
36
42
 
37
43
  const params: string[] = [];
38
44
  if (style) params.push(`style=${style}`);
@@ -136,4 +136,94 @@ export class ImageTransformService {
136
136
  throw ImageErrorHandler.handleUnknownError(error, 'flip');
137
137
  }
138
138
  }
139
+
140
+ static async manipulate(
141
+ uri: string,
142
+ action: ImageManipulateAction,
143
+ options?: ImageSaveOptions
144
+ ): Promise<ImageManipulationResult> {
145
+ 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
+
151
+ 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
+
177
+ if (action.flip) {
178
+ if (action.flip.horizontal) actions.push({ flip: ImageManipulator.FlipType.Horizontal });
179
+ if (action.flip.vertical) actions.push({ flip: ImageManipulator.FlipType.Vertical });
180
+ }
181
+
182
+ return await ImageManipulator.manipulateAsync(
183
+ uri,
184
+ actions,
185
+ this.buildSaveOptions(options)
186
+ );
187
+ } catch (error) {
188
+ throw ImageErrorHandler.handleUnknownError(error, 'manipulate');
189
+ }
190
+ }
191
+
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
+ }
209
+ }
210
+
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
+ }
228
+ }
139
229
  }
@@ -147,44 +147,43 @@ export class FilterProcessor {
147
147
  }
148
148
 
149
149
  static applyFilter(
150
- imageData: ImageData,
150
+ imageData: Uint8ClampedArray,
151
+ width: number,
152
+ height: number,
151
153
  filterState: FilterState
152
- ): ImageData {
154
+ ): Uint8ClampedArray {
153
155
  const preset = this.getPreset(filterState.id);
154
156
  if (!preset || !filterState.enabled) {
155
157
  return imageData;
156
158
  }
157
159
 
158
- let processedData = new Uint8ClampedArray(imageData.data);
160
+ let processedData = new Uint8ClampedArray(imageData);
159
161
 
160
162
  // Apply filter based on preset type
161
163
  switch (filterState.id) {
162
164
  case 'brightness':
163
- processedData = this.applyBrightness(processedData, filterState.parameters.brightness) as any;
165
+ processedData = this.applyBrightness(processedData, filterState.parameters.brightness);
164
166
  break;
165
167
  case 'contrast':
166
- processedData = this.applyContrast(processedData, filterState.parameters.contrast) as any;
168
+ processedData = this.applyContrast(processedData, filterState.parameters.contrast);
167
169
  break;
168
170
  case 'saturation':
169
- processedData = this.applySaturation(processedData, filterState.parameters.saturation) as any;
171
+ processedData = this.applySaturation(processedData, filterState.parameters.saturation);
170
172
  break;
171
173
  case 'vintage':
172
- processedData = this.applyVintage(processedData, filterState.parameters.intensity, filterState.parameters.warmth) as any;
174
+ processedData = this.applyVintage(processedData, filterState.parameters.intensity, filterState.parameters.warmth);
173
175
  break;
174
176
  case 'blur':
175
- processedData = this.applyBlur(processedData, filterState.parameters.radius) as any;
177
+ processedData = this.applyBlur(processedData, filterState.parameters.radius, width, height);
176
178
  break;
177
179
  }
178
180
 
179
181
  // Apply intensity
180
182
  if (filterState.intensity < 100) {
181
- processedData = this.applyIntensity(imageData.data, processedData, filterState.intensity / 100) as any;
183
+ processedData = this.applyIntensity(imageData, processedData, filterState.intensity / 100);
182
184
  }
183
185
 
184
- return {
185
- ...imageData,
186
- data: processedData,
187
- };
186
+ return processedData;
188
187
  }
189
188
 
190
189
  private static applyBrightness(
@@ -282,12 +281,12 @@ export class FilterProcessor {
282
281
 
283
282
  private static applyBlur(
284
283
  data: Uint8ClampedArray,
285
- radius: number
284
+ radius: number,
285
+ width: number,
286
+ height: number
286
287
  ): Uint8ClampedArray {
287
288
  // Simple box blur implementation
288
289
  const result = new Uint8ClampedArray(data);
289
- const width = Math.sqrt(data.length / 4);
290
- const height = width;
291
290
  const size = Math.floor(radius) || 1;
292
291
 
293
292
  for (let y = 0; y < height; y++) {
@@ -336,26 +335,5 @@ export class FilterProcessor {
336
335
  return result;
337
336
  }
338
337
 
339
- static createPreview(
340
- imageData: ImageData,
341
- filterState: FilterState,
342
- previewSize: { width: number; height: number }
343
- ): ImageData {
344
- // Create a smaller preview version
345
- const previewCanvas = document.createElement('canvas') || {} as any;
346
- previewCanvas.width = previewSize.width;
347
- previewCanvas.height = previewSize.height;
348
- const ctx = previewCanvas.getContext('2d');
349
-
350
- if (!ctx) return imageData;
351
-
352
- // Scale down the image for preview
353
- ctx.drawImage(
354
- {} as HTMLImageElement, // Would be the actual image
355
- 0, 0, previewSize.width, previewSize.height
356
- );
357
-
358
- const previewImageData = ctx.getImageData(0, 0, previewSize.width, previewSize.height);
359
- return this.applyFilter(previewImageData, filterState);
360
- }
338
+
361
339
  }
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Image Infrastructure - AI Image Analysis
2
+ * Image Infrastructure - Image Analysis
3
3
  *
4
- * Advanced image analysis utilities
4
+ * Image analysis utilities
5
5
  */
6
6
 
7
- export class AIImageAnalysisUtils {
7
+ export class ImageAnalysisUtils {
8
8
  static calculateColorBalance(imageData: Uint8ClampedArray): {
9
9
  redBalance: number;
10
10
  greenBalance: number;
@@ -13,44 +13,7 @@ export interface LayerComposition {
13
13
  }
14
14
 
15
15
  export class LayerManager {
16
- static composeLayers(
17
- layers: Array<{
18
- canvas: HTMLCanvasElement | any;
19
- opacity: number;
20
- visible: boolean;
21
- x?: number;
22
- y?: number;
23
- }>,
24
- composition: LayerComposition
25
- ): HTMLCanvasElement | any {
26
- // Create composition canvas
27
- const composedCanvas = document.createElement('canvas') || {} as any;
28
- composedCanvas.width = composition.width;
29
- composedCanvas.height = composition.height;
30
- const ctx = composedCanvas.getContext('2d');
31
-
32
- if (!ctx) return composedCanvas;
33
-
34
- // Clear canvas with background color
35
- ctx.fillStyle = composition.backgroundColor || '#ffffff';
36
- ctx.fillRect(0, 0, composition.width, composition.height);
37
-
38
- // Draw each layer
39
- layers.forEach(layer => {
40
- if (!layer.visible) return;
41
16
 
42
- ctx.save();
43
- ctx.globalAlpha = layer.opacity;
44
- ctx.drawImage(
45
- layer.canvas,
46
- layer.x || 0,
47
- layer.y || 0
48
- );
49
- ctx.restore();
50
- });
51
-
52
- return composedCanvas;
53
- }
54
17
 
55
18
  static mergeLayers(
56
19
  layers: Array<{
@@ -110,49 +73,5 @@ export class LayerManager {
110
73
  return result.map((layer, index) => ({ ...layer, index }));
111
74
  }
112
75
 
113
- static flattenLayers(
114
- layers: Array<{
115
- canvas: HTMLCanvasElement | any;
116
- opacity: number;
117
- visible: boolean;
118
- }>,
119
- composition: LayerComposition
120
- ): HTMLCanvasElement | any {
121
- return LayerManager.composeLayers(layers, composition);
122
- }
123
-
124
- static createLayerCanvas(
125
- width: number,
126
- height: number,
127
- transparent: boolean = true
128
- ): HTMLCanvasElement | any {
129
- const canvas = document.createElement('canvas') || {} as any;
130
- canvas.width = width;
131
- canvas.height = height;
132
-
133
- if (!transparent) {
134
- const ctx = canvas.getContext('2d');
135
- if (ctx) {
136
- ctx.fillStyle = '#ffffff';
137
- ctx.fillRect(0, 0, width, height);
138
- }
139
- }
140
76
 
141
- return canvas;
142
- }
143
-
144
- static clearLayer(
145
- canvas: HTMLCanvasElement | any,
146
- preserveAlpha: boolean = true
147
- ): void {
148
- const ctx = canvas.getContext('2d');
149
- if (!ctx) return;
150
-
151
- if (preserveAlpha) {
152
- ctx.clearRect(0, 0, canvas.width, canvas.height);
153
- } else {
154
- ctx.fillStyle = 'transparent';
155
- ctx.fillRect(0, 0, canvas.width, canvas.height);
156
- }
157
- }
158
77
  }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Presentation - Image Enhance Hook
3
+ */
4
+
5
+ import { useCallback } from 'react';
6
+ import { useImageOperation } from './useImageOperation';
7
+ import { ImageEnhanceService, type AutoEnhancementOptions } from '../../infrastructure/services/ImageEnhanceService';
8
+
9
+ export const useImageEnhance = () => {
10
+ const { isProcessing, error, execute } = useImageOperation();
11
+
12
+ const autoEnhance = useCallback((uri: string, options?: AutoEnhancementOptions) =>
13
+ execute(() => ImageEnhanceService.autoEnhance(uri, options), 'Failed to auto enhance'), [execute]);
14
+
15
+ const enhancePortrait = useCallback((uri: string) =>
16
+ execute(() => ImageEnhanceService.enhancePortrait(uri), 'Failed to enhance portrait'), [execute]);
17
+
18
+ const enhanceLandscape = useCallback((uri: string) =>
19
+ execute(() => ImageEnhanceService.enhanceLandscape(uri), 'Failed to enhance landscape'), [execute]);
20
+
21
+ const analyzeImage = useCallback((uri: string) =>
22
+ execute(() => ImageEnhanceService.analyzeImage(uri), 'Failed to analyze image'), [execute]);
23
+
24
+ return {
25
+ autoEnhance,
26
+ enhancePortrait,
27
+ enhanceLandscape,
28
+ analyzeImage,
29
+ isEnhancing: isProcessing,
30
+ enhancementError: error,
31
+ };
32
+ };
@@ -4,7 +4,6 @@
4
4
  import { useCallback } from 'react';
5
5
  import { useImageOperation } from './useImageOperation';
6
6
  import { ImageTransformService } from '../../infrastructure/services/ImageTransformService';
7
- import { ImageAdvancedTransformService } from '../../infrastructure/services/ImageAdvancedTransformService';
8
7
  import type {
9
8
  ImageManipulateAction,
10
9
  ImageSaveOptions,
@@ -28,13 +27,13 @@ export const useImageTransform = () => {
28
27
  execute(() => ImageTransformService.flip(uri, flipParams, options), 'Failed to flip'), [execute]);
29
28
 
30
29
  const manipulate = useCallback((uri: string, action: ImageManipulateAction, options?: ImageSaveOptions) =>
31
- execute(() => ImageAdvancedTransformService.manipulate(uri, action, options), 'Failed to manipulate'), [execute]);
30
+ execute(() => ImageTransformService.manipulate(uri, action, options), 'Failed to manipulate'), [execute]);
32
31
 
33
32
  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]);
33
+ execute(() => ImageTransformService.resizeToFit(uri, maxWidth, maxHeight, options), 'Failed to resize to fit'), [execute]);
35
34
 
36
35
  const cropToSquare = useCallback((uri: string, width: number, height: number, options?: ImageSaveOptions) =>
37
- execute(() => ImageAdvancedTransformService.cropToSquare(uri, width, height, options), 'Failed to crop square'), [execute]);
36
+ execute(() => ImageTransformService.cropToSquare(uri, width, height, options), 'Failed to crop square'), [execute]);
38
37
 
39
38
  return {
40
39
  resize, crop, rotate, flip, manipulate, resizeToFit, cropToSquare,
@@ -1,106 +0,0 @@
1
- /**
2
- * Image Infrastructure - Advanced Transform Service
3
- */
4
-
5
- import * as ImageManipulator from 'expo-image-manipulator';
6
- import type {
7
- ImageManipulateAction,
8
- ImageSaveOptions,
9
- ImageManipulationResult,
10
- } from '../../domain/entities/ImageTypes';
11
- import { ImageTransformService } from './ImageTransformService';
12
- import { ImageUtils } from '../../domain/utils/ImageUtils';
13
- import { ImageValidator } from '../utils/ImageValidator';
14
- import { ImageErrorHandler, IMAGE_ERROR_CODES } from '../utils/ImageErrorHandler';
15
-
16
- export class ImageAdvancedTransformService {
17
- static async manipulate(
18
- uri: string,
19
- action: ImageManipulateAction,
20
- options?: ImageSaveOptions
21
- ): Promise<ImageManipulationResult> {
22
- try {
23
- const uriValidation = ImageValidator.validateUri(uri);
24
- if (!uriValidation.isValid) {
25
- throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'manipulate');
26
- }
27
-
28
- const actions: ImageManipulator.Action[] = [];
29
-
30
- if (action.resize) {
31
- const dimValidation = ImageValidator.validateDimensions(action.resize);
32
- if (!dimValidation.isValid) {
33
- throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'manipulate');
34
- }
35
- actions.push({ resize: action.resize });
36
- }
37
-
38
- if (action.crop) {
39
- const dimValidation = ImageValidator.validateDimensions(action.crop);
40
- if (!dimValidation.isValid) {
41
- throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'manipulate');
42
- }
43
- actions.push({ crop: action.crop });
44
- }
45
-
46
- if (action.rotate) {
47
- const rotationValidation = ImageValidator.validateRotation(action.rotate);
48
- if (!rotationValidation.isValid) {
49
- throw ImageErrorHandler.createError(rotationValidation.error!, IMAGE_ERROR_CODES.VALIDATION_ERROR, 'manipulate');
50
- }
51
- actions.push({ rotate: action.rotate });
52
- }
53
-
54
- if (action.flip) {
55
- if (action.flip.horizontal) actions.push({ flip: ImageManipulator.FlipType.Horizontal });
56
- if (action.flip.vertical) actions.push({ flip: ImageManipulator.FlipType.Vertical });
57
- }
58
-
59
- return await ImageManipulator.manipulateAsync(
60
- uri,
61
- actions,
62
- ImageTransformService['buildSaveOptions'](options)
63
- );
64
- } catch (error) {
65
- throw ImageErrorHandler.handleUnknownError(error, 'manipulate');
66
- }
67
- }
68
-
69
- static async resizeToFit(
70
- uri: string,
71
- maxWidth: number,
72
- maxHeight: number,
73
- options?: ImageSaveOptions
74
- ): Promise<ImageManipulationResult> {
75
- try {
76
- const dimValidation = ImageValidator.validateDimensions({ width: maxWidth, height: maxHeight });
77
- if (!dimValidation.isValid) {
78
- throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'resizeToFit');
79
- }
80
-
81
- const dimensions = ImageUtils.fitToSize(maxWidth, maxHeight, maxWidth, maxHeight);
82
- return ImageTransformService.resize(uri, dimensions.width, dimensions.height, options);
83
- } catch (error) {
84
- throw ImageErrorHandler.handleUnknownError(error, 'resizeToFit');
85
- }
86
- }
87
-
88
- static async cropToSquare(
89
- uri: string,
90
- width: number,
91
- height: number,
92
- options?: ImageSaveOptions
93
- ): Promise<ImageManipulationResult> {
94
- try {
95
- const dimValidation = ImageValidator.validateDimensions({ width, height });
96
- if (!dimValidation.isValid) {
97
- throw ImageErrorHandler.createError(dimValidation.error!, IMAGE_ERROR_CODES.INVALID_DIMENSIONS, 'cropToSquare');
98
- }
99
-
100
- const cropArea = ImageUtils.getSquareCrop(width, height);
101
- return ImageTransformService.crop(uri, cropArea, options);
102
- } catch (error) {
103
- throw ImageErrorHandler.handleUnknownError(error, 'cropToSquare');
104
- }
105
- }
106
- }
@@ -1,57 +0,0 @@
1
- /**
2
- * Image Infrastructure - Specialized Enhancement
3
- *
4
- * Portrait and landscape specific enhancement services
5
- */
6
-
7
- import type { ImageManipulationResult } from '../../domain/entities/ImageTypes';
8
- import { ImageValidator } from '../utils/ImageValidator';
9
- import { ImageErrorHandler, IMAGE_ERROR_CODES } from '../utils/ImageErrorHandler';
10
-
11
- export class ImageSpecializedEnhancementService {
12
- static async enhancePortrait(uri: string): Promise<ImageManipulationResult> {
13
- try {
14
- const uriValidation = ImageValidator.validateUri(uri);
15
- if (!uriValidation.isValid) {
16
- throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'enhancePortrait');
17
- }
18
-
19
- // Portrait-specific enhancements:
20
- // - Skin smoothing
21
- // - Eye enhancement
22
- // - Face detection and lighting adjustment
23
- // - Background blur (bokeh effect)
24
-
25
- return {
26
- uri,
27
- width: 0,
28
- height: 0,
29
- };
30
- } catch (error) {
31
- throw ImageErrorHandler.handleUnknownError(error, 'enhancePortrait');
32
- }
33
- }
34
-
35
- static async enhanceLandscape(uri: string): Promise<ImageManipulationResult> {
36
- try {
37
- const uriValidation = ImageValidator.validateUri(uri);
38
- if (!uriValidation.isValid) {
39
- throw ImageErrorHandler.createError(uriValidation.error!, IMAGE_ERROR_CODES.INVALID_URI, 'enhanceLandscape');
40
- }
41
-
42
- // Landscape-specific enhancements:
43
- // - Sky enhancement
44
- // - Green tone adjustment
45
- // - HDR effect simulation
46
- // - Perspective correction
47
-
48
- return {
49
- uri,
50
- width: 0,
51
- height: 0,
52
- };
53
- } catch (error) {
54
- throw ImageErrorHandler.handleUnknownError(error, 'enhanceLandscape');
55
- }
56
- }
57
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * Presentation - Image AI Enhancement Hook
3
- */
4
-
5
- import { useCallback } from 'react';
6
- import { useImageOperation } from './useImageOperation';
7
- import { ImageAIEnhancementService, type AutoEnhancementOptions, type EnhancementResult } from '../../infrastructure/services/ImageAIEnhancementService';
8
- import { ImageSpecializedEnhancementService } from '../../infrastructure/services/ImageSpecializedEnhancementService';
9
-
10
- export const useImageAIEnhancement = () => {
11
- const { isProcessing, error, execute } = useImageOperation();
12
-
13
- const autoEnhance = useCallback((uri: string, options?: AutoEnhancementOptions) =>
14
- execute(() => ImageAIEnhancementService.autoEnhance(uri, options), 'Failed to auto enhance'), [execute]);
15
-
16
- const enhancePortrait = useCallback((uri: string) =>
17
- execute(() => ImageSpecializedEnhancementService.enhancePortrait(uri), 'Failed to enhance portrait'), [execute]);
18
-
19
- const enhanceLandscape = useCallback((uri: string) =>
20
- execute(() => ImageSpecializedEnhancementService.enhanceLandscape(uri), 'Failed to enhance landscape'), [execute]);
21
-
22
- const analyzeImage = useCallback((uri: string) =>
23
- execute(() => ImageAIEnhancementService.analyzeImage(uri), 'Failed to analyze image'), [execute]);
24
-
25
- return {
26
- autoEnhance,
27
- enhancePortrait,
28
- enhanceLandscape,
29
- analyzeImage,
30
- isEnhancing: isProcessing,
31
- enhancementError: error,
32
- };
33
- };