1
1
import 'dart:io' ;
2
2
3
3
import 'package:flutter_gen_core/generators/integrations/integration.dart' ;
4
+ import 'package:image/image.dart' as img;
4
5
import 'package:image_size_getter/file_input.dart' ;
5
6
import 'package:image_size_getter/image_size_getter.dart' ;
6
7
@@ -11,9 +12,12 @@ import 'package:image_size_getter/image_size_getter.dart';
11
12
class ImageIntegration extends Integration {
12
13
ImageIntegration (
13
14
String packageName, {
15
+ required this .parseAnimation,
14
16
super .parseMetadata,
15
17
}) : super (packageName);
16
18
19
+ final bool parseAnimation;
20
+
17
21
String get packageParameter => isPackage ? ' = package' : '' ;
18
22
19
23
String get keyName =>
@@ -32,6 +36,9 @@ class ImageIntegration extends Integration {
32
36
this._assetName, {
33
37
this.size,
34
38
this.flavors = const {},
39
+ this.isAnimation = false,
40
+ this.duration = Duration.zero,
41
+ this.frames = 1,
35
42
});
36
43
37
44
final String _assetName;
@@ -40,6 +47,9 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''}
40
47
41
48
final Size? size;
42
49
final Set<String> flavors;
50
+ final bool isAnimation;
51
+ final Duration duration;
52
+ final int frames;
43
53
44
54
Image image({
45
55
Key? key,
@@ -116,12 +126,20 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''}
116
126
117
127
@override
118
128
String classInstantiate (AssetType asset) {
119
- final info = parseMetadata ? _getMetadata (asset) : null ;
129
+ final info = parseMetadata || parseAnimation ? _getMetadata (asset) : null ;
120
130
final buffer = StringBuffer (className);
121
131
buffer.write ('(' );
122
132
buffer.write ('\' ${asset .posixStylePath }\' ' );
123
133
if (info != null ) {
124
- buffer.write (', size: Size(${info .width }, ${info .height })' );
134
+ buffer.write (', size: const Size(${info .width }, ${info .height })' );
135
+
136
+ if (info.animation case final animation? ) {
137
+ buffer.write (', isAnimation: ${animation .frames > 1 }' );
138
+ buffer.write (
139
+ ', duration: const Duration(milliseconds: ${animation .duration .inMilliseconds })' ,
140
+ );
141
+ buffer.write (', frames: ${animation .frames }' );
142
+ }
125
143
}
126
144
if (asset.flavors.isNotEmpty) {
127
145
buffer.write (', flavors: {' );
@@ -161,11 +179,47 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''}
161
179
FileInput (File (asset.fullPath)),
162
180
);
163
181
final size = result.size;
164
- return ImageMetadata (size.width.toDouble (), size.height.toDouble ());
182
+ final animation = parseAnimation ? _parseAnimation (asset) : null ;
183
+
184
+ return ImageMetadata (
185
+ width: size.width.toDouble (),
186
+ height: size.height.toDouble (),
187
+ animation: animation,
188
+ );
165
189
} catch (e) {
166
190
stderr
167
191
.writeln ('[WARNING] Failed to parse \' ${asset .path }\' metadata: $e ' );
168
192
}
169
193
return null ;
170
194
}
195
+
196
+ ImageAnimation ? _parseAnimation (AssetType asset) {
197
+ final decoder = switch (asset.mime) {
198
+ 'image/gif' => img.GifDecoder (),
199
+ 'image/webp' => img.WebPDecoder (),
200
+ _ => null ,
201
+ };
202
+
203
+ if (decoder == null ) {
204
+ return null ;
205
+ }
206
+
207
+ final file = File (asset.fullPath);
208
+ final bytes = file.readAsBytesSync ();
209
+ final image = decoder.decode (bytes);
210
+
211
+ if (image == null ) {
212
+ return null ;
213
+ }
214
+
215
+ return ImageAnimation (
216
+ frames: image.frames.length,
217
+ duration: Duration (
218
+ milliseconds: image.frames.fold (
219
+ 0 ,
220
+ (duration, frame) => duration + frame.frameDuration,
221
+ ),
222
+ ),
223
+ );
224
+ }
171
225
}
0 commit comments