maui icon indicating copy to clipboard operation
maui copied to clipboard

SVG Image loaded with ImageSource.FromStream() not displayed

Open drossoft opened this issue 2 years ago • 8 comments

Description

I'm loading PNG and SVG images stored in a database. I have gotten this to work correctly in the Xamarin version of the application, using FFImageLoading Nuget, using the SVGImageSource class.

PNG files work fine, but SVG are not displayed.

This is how it was on Xamarin:

//ImageFormat is a string that contains the value of FileResult.ContentType, to know if it is PNG or SVG

if (image.ImageFormat != null && image.ImageFormat.ToLower().Contains("svg"))
{
    imageSource = SvgImageSource.FromStream(() => new MemoryStream(image.ImageData));
}
else
{
    imageSource = ImageSource.FromStream(() => new MemoryStream(image.ImageData));
}

MAUI:

    imageSource = ImageSource.FromStream(() => new MemoryStream(image.ImageData));

The documentation inticates that ImageSource.FromStream can load SVG and also animated .GIF, so, no need to check if its PNG or SVG. Anyway, i haven't found anything similar to SvgImageSource.

Steps to Reproduce

  1. Load a SVG File (PNG works fine)
FileResult fileData = await MediaPicker.PickPhotoAsync(options);
  1. Read data from the file
var imageData = await fileData.OpenReadAsync();
  1. Get byte[] from imageData
byte[] imageByteArray = new byte[imageData.Length];
await imageData.ReadAsync(imageByteArray, 0, (int)imageData.Length);
ImageData = imageByteArray;
  1. Get ImageSource from byte[] to bind it to an Image Control
//If you try to get an ImageSource from this byte[] the image is not displayed if is an SVG image
ImageSource ImageData = ImageSource.FromStream(() => new MemoryStream(item.ImageData));
  1. Bind the control on the view to the ImageData Property
<Image Source="{Binding ImageData }" WidthRequest="64" HeightRequest="64" Margin="4,0"/>

Link to public reproduction project repository

https://github.com/drossoft/SVGImageLoadSample

Version with bug

7.0 (current)

Last version that worked well

Unknown/Other

Affected platforms

Android, Windows, I was not able test on other platforms

Affected platform versions

Windows SDK 10.0.19041.0, Android 11

Did you find any workaround?

Not yet

Relevant log output

Microsoft.Maui.StreamImageSourceService: Warning: Unable to load image stream.

System.Runtime.InteropServices.COMException (0x88982F50): The component cannot be found. (0x88982F50)
   at Microsoft.Maui.StreamImageSourceService.GetImageSourceAsync(IStreamImageSource imageSource, Single scale, CancellationToken cancellationToken)

drossoft avatar Nov 19 '22 18:11 drossoft

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost avatar Nov 21 '22 15:11 ghost

Is there any workaround? Can't upgrade my app without loading SVG Image from byte[].

drossoft avatar Nov 21 '22 18:11 drossoft

Any news?

AramMar avatar Feb 15 '23 08:02 AramMar

No, and I haven't found any workaround yet

drossoft avatar Feb 15 '23 18:02 drossoft

We're running into this issue with an maui app build on .NET 7.0.103, android. Not only with SVG, also with Jpg and similar image types.

Our workaround is to cache the image in file and using ImageSource FromFile. It's not nice but works like a charm.

daDomas avatar Feb 20 '23 09:02 daDomas

Yes, that seems to be the best option, I will try that as well. Thanks!

drossoft avatar Feb 23 '23 18:02 drossoft

Any news?

scriptBoris avatar Mar 02 '23 11:03 scriptBoris

I've tried caching the image in the file and loading it using ImageSource.FromFile, but it still doesn't work for SVG files.

string localPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); string imagesPath = Path.Combine(localPath, "Images");

string imageFullPath = Path.Combine(imagesPath, "image_test.svg");

File.WriteAllBytes(imageFullPath, imageBytes); //imageBytes is the byte[] read from database image = ImageSource.FromFile(imageFullPath);

I see that the image is correctly saved to the file when I open it in File Explorer, and the variable "image" is an ImageSource pointing to the file, but it doesn't show up when I bind it in my view.

@daDomas, have you checked that SVG images work with your solution or only JPG images?

drossoft avatar Mar 11 '23 15:03 drossoft

For anyone having trouble with this, I have found a solution. I have implemented a method using SkiaSharp to get an ImageSource from a byte[] (with the help of ChatGPT).

You need these nugets:

  • SkiaSharp.Svg (1.60.0)
  • SkiaSharp.Views.Maui.Core (2.88.3)
using SkiaSharp;

public ImageSource ConvertSvgToImageSource(byte[] svgData)
{
            using (var stream = new MemoryStream(svgData))
            {
                var svgDocument = new SkiaSharp.Extended.Svg.SKSvg();
                svgDocument.Load(stream);

                var bitmap = new SKBitmap((int)svgDocument.Picture.CullRect.Width, (int)svgDocument.Picture.CullRect.Height);

                using (var surface = SKSurface.Create(new SKImageInfo(bitmap.Width, bitmap.Height)))
                {
                    var canvas = surface.Canvas;
                    canvas.Clear(SKColors.Transparent);
                    canvas.DrawPicture(svgDocument.Picture);
                    surface.Canvas.Flush();

                    var image = surface.Snapshot();
                    bitmap = SKBitmap.FromImage(image);
                    var data = bitmap.Encode(SKEncodedImageFormat.Png, 100);

                    var imageStream = new MemoryStream(data.ToArray());
                    var imageSource = ImageSource.FromStream(() => imageStream);

                    return imageSource;
                }
            }
}

drossoft avatar Apr 03 '23 12:04 drossoft

@drossoft your workarround dont work well when we have a svg with gradients.

flipper09112 avatar Nov 30 '23 12:11 flipper09112

Yes, we've noticed, but that's the best we've come up with for now.

drossoft avatar Nov 30 '23 21:11 drossoft