Issue Explanation
The reported error involves a runtime crash when the vector_graphics package attempts to draw an <image>
element from an SVG. The stack trace suggests a TypeError
is happening during onDrawImage
, likely due to the decoding of image bytes into a Dart/Flutter UI image object not producing the expected type.
Prior to Flutter 3.10, decodeImageFromList
was the conventional method to decode images from byte arrays. However, with updated Flutter versions and web compatibility changes, decodeImageFromList
on the web may not return the expected ui.Image
type, causing type errors at runtime. Instead, it's recommended to use the newer image decoding approach that involves ImmutableBuffer
, ImageDescriptor
, and Codec
.
Root Cause
- The
onDrawImage
method inFlutterVectorGraphicsListener
is expecting aui.Image
, but the decoding method used might be returning something else or failing silently, leading to aTypeError
. - If the code previously relied on
decodeImageFromList
, this can fail on web because that method is not fully supported. Using the newerui.ImageDescriptor
-based pipeline ensures a properui.Image
object is obtained.
Proposed Fix
Replace any usage of decodeImageFromList
with the newer decoding API. This ensures compatibility across all platforms and avoids type issues. For example, in listener.dart
(around line 773 where onDrawImage
is implemented), update the image decoding logic:
Before (old approach):
ui.decodeImageFromList(imageBytes, (ui.Image image) {
// ... code to use image ...
});
After (new, robust approach):
Future<void> onDrawImage(Uint8List imageBytes, double x, double y, double width, double height, Rect? clipRect) async {
if (imageBytes.isEmpty) {
// No image data, just return.
return;
}
// Use the newer decoding pipeline:
final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(imageBytes);
final ui.ImageDescriptor descriptor = await ui.ImageDescriptor.encoded(buffer);
final ui.Codec codec = await descriptor.instantiateCodec();
final ui.FrameInfo frameInfo = await codec.getNextFrame();
final ui.Image image = frameInfo.image;
// Now that we have a proper ui.Image, we can safely draw it:
paintImage(
canvas: canvas,
image: image,
rect: Rect.fromLTWH(x, y, width, height),
fit: BoxFit.contain,
);
}
Additional Notes:
- Ensure that
canvas
and related variables are in scope when drawing the image. - If the existing code uses a listener or callback-based approach, adapt it to the async/await style used above.
- Handle any potential null checks or exceptions during decoding gracefully.
By making this change, you ensure that images embedded in your SVGs decode reliably into ui.Image
instances, preventing the TypeError
and runtime crashes previously encountered.