11import 'dart:io' ;
22
33import 'package:flutter_gen_core/generators/integrations/integration.dart' ;
4+ import 'package:image/image.dart' as img;
45import 'package:image_size_getter/file_input.dart' ;
56import 'package:image_size_getter/image_size_getter.dart' ;
67
@@ -11,9 +12,12 @@ import 'package:image_size_getter/image_size_getter.dart';
1112class ImageIntegration extends Integration {
1213 ImageIntegration (
1314 String packageName, {
15+ required this .parseAnimation,
1416 super .parseMetadata,
1517 }) : super (packageName);
1618
19+ final bool parseAnimation;
20+
1721 String get packageParameter => isPackage ? ' = package' : '' ;
1822
1923 String get keyName =>
@@ -32,6 +36,9 @@ class ImageIntegration extends Integration {
3236 this._assetName, {
3337 this.size,
3438 this.flavors = const {},
39+ this.isAnimation = false,
40+ this.duration = Duration.zero,
41+ this.frames = 1,
3542 });
3643
3744 final String _assetName;
@@ -40,6 +47,9 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''}
4047
4148 final Size? size;
4249 final Set<String> flavors;
50+ final bool isAnimation;
51+ final Duration duration;
52+ final int frames;
4353
4454 Image image({
4555 Key? key,
@@ -116,12 +126,20 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''}
116126
117127 @override
118128 String classInstantiate (AssetType asset) {
119- final info = parseMetadata ? _getMetadata (asset) : null ;
129+ final info = parseMetadata || parseAnimation ? _getMetadata (asset) : null ;
120130 final buffer = StringBuffer (className);
121131 buffer.write ('(' );
122132 buffer.write ('\' ${asset .posixStylePath }\' ' );
123133 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+ }
125143 }
126144 if (asset.flavors.isNotEmpty) {
127145 buffer.write (', flavors: {' );
@@ -161,11 +179,47 @@ ${isPackage ? "\n static const String package = '$packageName';" : ''}
161179 FileInput (File (asset.fullPath)),
162180 );
163181 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+ );
165189 } catch (e) {
166190 stderr
167191 .writeln ('[WARNING] Failed to parse \' ${asset .path }\' metadata: $e ' );
168192 }
169193 return null ;
170194 }
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+ }
171225}
0 commit comments