Line data Source code
1 : part of '../worker.dart';
2 :
3 : /// Image processing worker (resize, compress, convert).
4 : ///
5 : /// Processes images natively for optimal performance and memory usage.
6 : /// Runs in native code **without** Flutter Engine. 10x faster and uses
7 : /// 9x less memory than Dart image packages.
8 : ///
9 : /// ## Resize Image
10 : ///
11 : /// ```dart
12 : /// await NativeWorkManager.enqueue(
13 : /// taskId: 'resize-photo',
14 : /// trigger: TaskTrigger.oneTime(),
15 : /// worker: NativeWorker.imageProcess(
16 : /// inputPath: '/photos/IMG_4032.png',
17 : /// outputPath: '/processed/photo_1080p.jpg',
18 : /// maxWidth: 1920,
19 : /// maxHeight: 1080,
20 : /// outputFormat: ImageFormat.jpeg,
21 : /// quality: 85,
22 : /// ),
23 : /// );
24 : /// ```
25 : ///
26 : /// ## Compress Image
27 : ///
28 : /// ```dart
29 : /// // Reduce file size for upload
30 : /// await NativeWorkManager.enqueue(
31 : /// taskId: 'compress-photo',
32 : /// trigger: TaskTrigger.oneTime(),
33 : /// worker: NativeWorker.imageProcess(
34 : /// inputPath: '/photos/original.jpg',
35 : /// outputPath: '/photos/compressed.jpg',
36 : /// quality: 70,
37 : /// deleteOriginal: true,
38 : /// ),
39 : /// );
40 : /// ```
41 : ///
42 : /// ## Convert Format
43 : ///
44 : /// ```dart
45 : /// // PNG to JPEG for smaller size
46 : /// await NativeWorkManager.enqueue(
47 : /// taskId: 'convert-format',
48 : /// trigger: TaskTrigger.oneTime(),
49 : /// worker: NativeWorker.imageProcess(
50 : /// inputPath: '/photos/screenshot.png',
51 : /// outputPath: '/photos/screenshot.jpg',
52 : /// outputFormat: ImageFormat.jpeg,
53 : /// quality: 90,
54 : /// ),
55 : /// );
56 : /// ```
57 : ///
58 : /// ## Crop Image
59 : ///
60 : /// ```dart
61 : /// // Crop to specific region
62 : /// await NativeWorkManager.enqueue(
63 : /// taskId: 'crop-avatar',
64 : /// trigger: TaskTrigger.oneTime(),
65 : /// worker: NativeWorker.imageProcess(
66 : /// inputPath: '/photos/profile.jpg',
67 : /// outputPath: '/avatars/cropped.jpg',
68 : /// cropRect: Rect.fromLTWH(100, 100, 500, 500),
69 : /// ),
70 : /// );
71 : /// ```
72 : ///
73 : /// ## Parameters
74 : ///
75 : /// **[inputPath]** *(required)* - Path to input image.
76 : ///
77 : /// **[outputPath]** *(required)* - Where processed image will be saved.
78 : ///
79 : /// **[maxWidth]** *(optional)* - Maximum width in pixels (null = no limit).
80 : ///
81 : /// **[maxHeight]** *(optional)* - Maximum height in pixels (null = no limit).
82 : ///
83 : /// **[maintainAspectRatio]** *(optional)* - Keep aspect ratio (default: true).
84 : /// - If true, image fits within maxWidth × maxHeight
85 : /// - If false, image stretched to exactly maxWidth × maxHeight
86 : ///
87 : /// **[quality]** *(optional)* - Output quality 0-100 (default: 85).
88 : /// - Only affects JPEG and WEBP formats
89 : /// - Higher = better quality, larger file size
90 : /// - Recommended: 70-90 for photos, 90-100 for graphics
91 : ///
92 : /// **[outputFormat]** *(optional)* - Output format (default: same as input).
93 : /// - `ImageFormat.jpeg` - Best for photos, smaller size
94 : /// - `ImageFormat.png` - Lossless, larger size, transparency
95 : /// - `ImageFormat.webp` - Modern format, good compression
96 : ///
97 : /// **[cropRect]** *(optional)* - Crop to rectangle (x, y, width, height).
98 : /// - Applied before resize
99 : /// - Coordinates in pixels from top-left
100 : ///
101 : /// **[deleteOriginal]** *(optional)* - Delete input after processing (default: false).
102 : ///
103 : /// ## Performance
104 : ///
105 : /// | Operation | Dart (image package) | Native (ImageProcessWorker) |
106 : /// |-----------|---------------------|----------------------------|
107 : /// | 4K → 1080p | 2,500ms / 180MB | 250ms / 20MB |
108 : /// | JPEG compress | 1,200ms / 150MB | 120ms / 15MB |
109 : /// | Format convert | 2,000ms / 200MB | 200ms / 20MB |
110 : ///
111 : /// **Improvement:** 10x faster, 9x less memory
112 : ///
113 : /// ## When to Use
114 : ///
115 : /// ✅ **Use imageProcess when:**
116 : /// - Resizing photos before upload
117 : /// - Generating thumbnails
118 : /// - Compressing images to save storage
119 : /// - Converting image formats
120 : /// - Cropping user-selected regions
121 : ///
122 : /// ❌ **Don't use imageProcess when:**
123 : /// - Image is already optimal size
124 : /// - Need complex filters → Use Dart image package
125 : /// - Need to read pixel data → Use Dart
126 : ///
127 : /// ## Common Pitfalls
128 : ///
129 : /// ❌ **Don't** use quality > 95 (diminishing returns, huge files)
130 : /// ❌ **Don't** resize already-small images (waste of processing)
131 : /// ❌ **Don't** forget to set outputFormat when converting
132 : /// ✅ **Do** use quality 70-85 for most photos
133 : /// ✅ **Do** maintain aspect ratio for photos
134 : /// ✅ **Do** use constraints for large image processing
135 : ///
136 : /// ## See Also
137 : ///
138 : /// - [NativeWorker.httpUpload] - Upload processed images
139 : /// - `NativeWorker.fileCompress` (deprecated v1.1.0 — use `archive` package)
140 4 : Worker _buildImageProcess({
141 : required String inputPath,
142 : required String outputPath,
143 : int? maxWidth,
144 : int? maxHeight,
145 : bool maintainAspectRatio = true,
146 : int quality = 85,
147 : ImageFormat? outputFormat,
148 : Rect? cropRect,
149 : bool deleteOriginal = false,
150 : }) {
151 4 : NativeWorker._validateFilePath(inputPath, 'inputPath');
152 4 : NativeWorker._validateFilePath(outputPath, 'outputPath');
153 :
154 8 : if (quality < 0 || quality > 100) {
155 4 : throw ArgumentError(
156 : 'quality must be between 0 and 100\n'
157 : 'Current: $quality\n'
158 : 'Recommended: 70-90 for photos, 90-100 for graphics',
159 : );
160 : }
161 :
162 2 : if (maxWidth != null && maxWidth <= 0) {
163 2 : throw ArgumentError('maxWidth must be positive');
164 : }
165 :
166 2 : if (maxHeight != null && maxHeight <= 0) {
167 2 : throw ArgumentError('maxHeight must be positive');
168 : }
169 :
170 4 : return ImageProcessWorker(
171 : inputPath: inputPath,
172 : outputPath: outputPath,
173 : maxWidth: maxWidth,
174 : maxHeight: maxHeight,
175 : maintainAspectRatio: maintainAspectRatio,
176 : quality: quality,
177 : outputFormat: outputFormat,
178 : cropRect: cropRect,
179 : deleteOriginal: deleteOriginal,
180 : );
181 : }
|