1+ import 'dart:async' ;
12import 'dart:convert' ;
23
34import 'package:flutter/material.dart' ;
@@ -11,21 +12,30 @@ typedef ImageSourceMatcher = bool Function(
1112);
1213
1314ImageSourceMatcher base64UriMatcher () => (attributes, element) =>
14- attributes["src" ].startsWith ("data:image" ) &&
15- attributes["src" ].contains ("base64," );
15+ _src (attributes) != null &&
16+ _src (attributes).startsWith ("data:image" ) &&
17+ _src (attributes).contains ("base64," );
1618
1719ImageSourceMatcher networkSourceMatcher ({
1820 List <String > schemas: const ["https" , "http" ],
1921 List <String > domains,
2022 String extension ,
2123}) =>
2224 (attributes, element) {
23- final src = Uri .parse (attributes["src" ]);
24- return schemas.contains (src.scheme) &&
25- (domains == null || domains.contains (src.host)) &&
26- (extension == null || src.path.endsWith (".$extension " ));
25+ if (_src (attributes) == null ) return false ;
26+ try {
27+ final src = Uri .parse (_src (attributes));
28+ return schemas.contains (src.scheme) &&
29+ (domains == null || domains.contains (src.host)) &&
30+ (extension == null || src.path.endsWith (".$extension " ));
31+ } catch (e) {
32+ return false ;
33+ }
2734 };
2835
36+ ImageSourceMatcher assetUriMatcher () => (attributes, element) =>
37+ _src (attributes) != null && _src (attributes).startsWith ("asset:" );
38+
2939typedef ImageRender = Widget Function (
3040 RenderContext context,
3141 Map <String , String > attributes,
@@ -34,7 +44,7 @@ typedef ImageRender = Widget Function(
3444
3545ImageRender base64ImageRender () => (context, attributes, element) {
3646 final decodedImage =
37- base64.decode (attributes[ "src" ] .split ("base64," )[1 ].trim ());
47+ base64.decode (_src ( attributes) .split ("base64," )[1 ].trim ());
3848 precacheImage (
3949 MemoryImage (decodedImage),
4050 context.buildContext,
@@ -46,14 +56,38 @@ ImageRender base64ImageRender() => (context, attributes, element) {
4656 decodedImage,
4757 frameBuilder: (ctx, child, frame, _) {
4858 if (frame == null ) {
49- return Text (attributes[ "alt" ] ?? "" ,
59+ return Text (_alt ( attributes) ?? "" ,
5060 style: context.style.generateTextStyle ());
5161 }
5262 return child;
5363 },
5464 );
5565 };
5666
67+ ImageRender assetImageRender ({
68+ double width,
69+ double height,
70+ }) =>
71+ (context, attributes, element) {
72+ final assetPath = _src (attributes).replaceFirst ('asset:' , '' );
73+ if (_src (attributes).endsWith (".svg" )) {
74+ return SvgPicture .asset (assetPath);
75+ } else {
76+ return Image .asset (
77+ assetPath,
78+ width: width ?? _width (attributes),
79+ height: height ?? _height (attributes),
80+ frameBuilder: (ctx, child, frame, _) {
81+ if (frame == null ) {
82+ return Text (_alt (attributes) ?? "" ,
83+ style: context.style.generateTextStyle ());
84+ }
85+ return child;
86+ },
87+ );
88+ }
89+ };
90+
5791ImageRender networkImageRender ({
5892 Map <String , String > headers,
5993 double width,
@@ -62,36 +96,89 @@ ImageRender networkImageRender({
6296}) =>
6397 (context, attributes, element) {
6498 precacheImage (
65- NetworkImage (attributes["src" ]),
99+ NetworkImage (
100+ _src (attributes),
101+ headers: headers,
102+ ),
66103 context.buildContext,
67104 onError: (exception, StackTrace stackTrace) {
68105 context.parser.onImageError? .call (exception, stackTrace);
69106 },
70107 );
71- return Image .network (
72- attributes["src" ],
73- headers: headers,
74- width: width,
75- height: height,
76- frameBuilder: (ctx, child, frame, _) {
77- if (frame == null ) {
78- return altWidget.call (attributes["alt" ]) ??
79- Text (attributes["alt" ] ?? "" ,
80- style: context.style.generateTextStyle ());
81- }
108+ Completer <Size > completer = Completer ();
109+ Image image =
110+ Image .network (_src (attributes), frameBuilder: (ctx, child, frame, _) {
111+ if (frame == null ) {
112+ completer.completeError ("error" );
82113 return child;
114+ } else {
115+ return child;
116+ }
117+ });
118+
119+ image.image.resolve (ImageConfiguration ()).addListener (
120+ ImageStreamListener ((ImageInfo image, bool synchronousCall) {
121+ var myImage = image.image;
122+ Size size =
123+ Size (myImage.width.toDouble (), myImage.height.toDouble ());
124+ completer.complete (size);
125+ }, onError: (object, stacktrace) {
126+ completer.completeError (object);
127+ }),
128+ );
129+ return FutureBuilder <Size >(
130+ future: completer.future,
131+ builder: (BuildContext buildContext, AsyncSnapshot <Size > snapshot) {
132+ if (snapshot.hasData) {
133+ return Image .network (
134+ _src (attributes),
135+ headers: headers,
136+ width: width ?? _width (attributes) ?? snapshot.data.width,
137+ height: height ?? _height (attributes),
138+ frameBuilder: (ctx, child, frame, _) {
139+ if (frame == null ) {
140+ return altWidget.call (_alt (attributes)) ??
141+ Text (_alt (attributes) ?? "" ,
142+ style: context.style.generateTextStyle ());
143+ }
144+ return child;
145+ },
146+ );
147+ } else if (snapshot.hasError) {
148+ return Text (_alt (attributes) ?? "" ,
149+ style: context.style.generateTextStyle ());
150+ } else {
151+ return new CircularProgressIndicator ();
152+ }
83153 },
84154 );
85155 };
86156
87157ImageRender svgNetworkImageRender () => (context, attributes, element) {
88- return SvgPicture .network (
89- attributes["src" ],
90- );
158+ return SvgPicture .network (attributes["src" ]);
91159 };
92160
93161final Map <ImageSourceMatcher , ImageRender > defaultImageRenders = {
94162 base64UriMatcher (): base64ImageRender (),
163+ assetUriMatcher (): assetImageRender (),
95164 networkSourceMatcher (extension : "svg" ): svgNetworkImageRender (),
96165 networkSourceMatcher (): networkImageRender (),
97166};
167+
168+ String _src (Map <String , String > attributes) {
169+ return attributes["src" ];
170+ }
171+
172+ String _alt (Map <String , String > attributes) {
173+ return attributes["alt" ];
174+ }
175+
176+ double _height (Map <String , String > attributes) {
177+ final heightString = attributes["height" ];
178+ return heightString == null ? heightString : double .tryParse (heightString);
179+ }
180+
181+ double _width (Map <String , String > attributes) {
182+ final widthString = attributes["width" ];
183+ return widthString == null ? widthString : double .tryParse (widthString);
184+ }
0 commit comments