Forum Xamarin Xamarin.Forms

Unanticipated visual elements present in the raster image generated via its SVG counterpart

hecatehecate Member ✭✭

An unanticipated amount of dregs is present in the background of the PNG images (as seen in the following images) generated from their SVG counterpart (attached to the app as an embedded resource) using the SkiaSharp libraries for use in Button and ToolbarItem views.

At a cursory glance, I believe that the issue pertains to the way the PNG image is generated from the SVG but, as of now, am unable to isolate the portion causing this "improper conversion" as I cannot segregate the problematic portion in the implementation of the GetEquivalentBitmapImagePath() method (shown below).

Code that generates the above entity:

string calculationHistoryIcon = GetEquivalentBitmapImagePath
                          (CALCULATION_HISTORY_ICON_RESOURCE_IDENTIFIER,
                           80, 80);
ToolbarItem calculationHistoryToolbarItem = new ToolbarItem()
                { IconImageSource = calculationHistoryIcon };
this.ToolbarItems.Add(calculationHistoryToolbarItem);

Code that generates the above entity:

string fullKeypadIcon = GetEquivalentBitmapImagePath
                        (FULL_KEYPAD_ICON_RESOURCE_IDENTIFIER,
                         50, 80);
Button keypadBtn = new Button()
{
    HorizontalOptions = LayoutOptions.Fill,
    VerticalOptions = LayoutOptions.Fill
};
keypadBtn.ImageSource = fullKeypadIcon;

The following method is used to generate the PNG image:

private string GetEquivalentBitmapImagePath
        (string embeddedVectorIdentifier,
         float widthOfBitmapImage,
         float heightOfBitmapImage)
    {
        // For converting vector (.svg) images to raster images
        SKSvg svg;
        SKBitmap bitmap;
        SKCanvas canvas;
        SKImage image;
        SKData encodedData;
        Stream imageStream;

        string vectorImageFile;
        Stream embeddedResourceStream;
        FileStream vectorImageStream,
                   bitmapImageStream;
        string bitmapImagePath;

        if (widthOfBitmapImage < 1)
            throw new ArgumentException("Invalid value passed", "widthOfFinalImage");
        if (heightOfBitmapImage < 1)
            throw new ArgumentException("Invalid value passed", "heightOfFinalImage");

        try
        {
            vectorImageFile = Path.Combine(FileSystem.CacheDirectory, embeddedVectorIdentifier);
            embeddedResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedVectorIdentifier);
            vectorImageStream = new FileStream(vectorImageFile, FileMode.Create, FileAccess.Write);
            embeddedResourceStream.CopyTo(vectorImageStream);
            embeddedResourceStream.Flush();
            vectorImageStream.Flush();
            embeddedResourceStream.Close();
            embeddedResourceStream.Dispose();
            vectorImageStream.Close();
            vectorImageStream.Dispose();

            svg = new SKSvg(new SKSize(widthOfBitmapImage,
                                       heightOfBitmapImage));
            svg.Load(vectorImageFile);
            bitmap = new SKBitmap(Convert.ToInt32(svg.CanvasSize.Width),
                                  Convert.ToInt32(svg.CanvasSize.Height));
            canvas = new SKCanvas(bitmap);

            canvas.DrawPicture(svg.Picture);
            canvas.Flush();
            canvas.Save();
            image = SKImage.FromBitmap(bitmap);
            encodedData = image.Encode(SKEncodedImageFormat.Png, 100);
            bitmapImagePath = vectorImageFile.Replace(".svg", ".png");
            bitmapImageStream = File.Open(bitmapImagePath,
                                          FileMode.Create,
                                          FileAccess.Write,
                                          FileShare.None);
            encodedData.SaveTo(bitmapImageStream);
            bitmapImageStream.Flush(true);
            bitmapImageStream.Dispose();
            File.Delete(vectorImageFile);
            return bitmapImagePath;
        }
        catch (Exception ex)
        {
            throw;
        }
    }

Thanks in advance.

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    Could you please post your svg here for testing?
    I tried your code with the svg:
    https://github.com/mono/SkiaSharp/blob/8ca298b448810cf65ab13cd7b2de94c627a033c1/images/SkiaSharpLogo.svg
    It is presented properly on the screen:

    However, if you want to load image from svg, here is a simple method for reference:

    private MemoryStream loadImage(string fileName)
    {
        var svg = new SkiaSharp.Extended.Svg.SKSvg();
        var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(fileName);
    
        svg.Load(stream);
        using (var bitMap = new SKBitmap((int)svg.CanvasSize.Width, (int)svg.CanvasSize.Height))
        using (SKCanvas canvas = new SKCanvas(bitMap))
        {
            canvas.DrawPicture(svg.Picture);
            canvas.Flush();
            canvas.Save();
    
            using (SKImage image = SKImage.FromBitmap(bitMap))
            {
                using (SKData data = image.Encode(SKEncodedImageFormat.Png, 80))
                {
                    MemoryStream memStream = new MemoryStream();
                    data.SaveTo(memStream);
                    memStream.Seek(0, SeekOrigin.Begin);
                    return memStream;
                }
            }
        }
    }
    
    // Usage
    Image img = new Image();
    img.Source = ImageSource.FromStream(() => loadImage("SvgSample.SkiaSharpLogo.svg"));
    

    You could also try FFImageLoading:
    https://github.com/luberda-molinet/FFImageLoading/wiki/SVG-support

Sign In or Register to comment.