locked
How do I draw a dynamically created image on the Blazor Canvas? RRS feed

  • Question

  • User1168746228 posted

    Hi,

    I'm using the Blazor Canvas extensions.  What I need to do is show a button on the page.  When the user clicks the button, I need to:

    1. Dynamically generate a random map (I have this code).
    2. Show an image of the map on the Blazor Canvas

    I can use an <img> to show the image e.g.:  <img @ref="ImageMap" src=@Image64> and generate that image on button click (that works fine), but then I don't know how to show it in the Canvas itself.  I've tried drawImage to no avail (or perhaps I have the call the drawImage in the wrong place).

    If anyone can offer some advice, I'd really appreciate it as I've been working on this for the past week with no success.

    Thanks.
     - Ed.

    Monday, December 28, 2020 3:25 AM

Answers

  • User1168746228 posted

    I finally got this working so here's what I did for anyone in the future who may need help.  You'll need Blazor.Extensions.Canvas as well as SixLabors.ImageSharp libraries.

    Define the image tag:
        <img @ref="ImageMap" class="hidden" src="@Image64">
    along with a property to hold the base64 bytes:
        protected string Image64 { get; set; }
    The "hidden" class is just defined as a style with display: none.

    Then, create the image (map) in OnInitializedAsync() and then update the <img> as follows:

            using (MemoryStream outStream = new MemoryStream())
            {
                using (Image<Rgba32> img = new Image<Rgba32>(500, 500))
                {
                    for (int y = 0; y < _map.height; y++)
                    {
                        for (int x = 0; x < _map.width; x++)
                        {
                            byte alpha = (byte)(_map.Palette[_map.Background[x, y]] >> 24);
                            byte r = (byte)((_map.Palette[_map.Background[x, y]] >> 16) & 0xFF);
                            byte g = (byte)((_map.Palette[_map.Background[x, y]] >> 8) & 0xFF);
                            byte b = (byte)(_map.Palette[_map.Background[x, y]] & 0xFF);
                            img[x, y] = new Rgba32(r, g, b, alpha);
                        }
                    }

                    img.SaveAsPng(outStream);
                }
                Image64 = "data:image/png;base64," + Convert.ToBase64String(outStream.ToArray());
            }

    The image MUST be loaded before calling DrawImage!  Then, in the button click event I just do:
            if (!string.IsNullOrEmpty(Image64))
            {
                await this._context.DrawImageAsync(ImageMap, 0, 0, 500, 500);
            }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, December 29, 2020 2:41 AM

All replies

  • User753101303 posted

    Hi,

    This part is using JavaScript? Seems you are looking for something such as: HTML5 Canvas Load Image Data URL (html5canvastutorials.com)

    As you can see this is done from the onload event to ensure the img content is loaded.

    Monday, December 28, 2020 10:49 AM
  • User-474980206 posted

    Blazor can not access the DOM so it can not get a reference to the image to pass to the drawImage. So you just use JavaScript interop to load the image, using sample code above.

    Monday, December 28, 2020 5:59 PM
  • User1168746228 posted

    I finally got this working so here's what I did for anyone in the future who may need help.  You'll need Blazor.Extensions.Canvas as well as SixLabors.ImageSharp libraries.

    Define the image tag:
        <img @ref="ImageMap" class="hidden" src="@Image64">
    along with a property to hold the base64 bytes:
        protected string Image64 { get; set; }
    The "hidden" class is just defined as a style with display: none.

    Then, create the image (map) in OnInitializedAsync() and then update the <img> as follows:

            using (MemoryStream outStream = new MemoryStream())
            {
                using (Image<Rgba32> img = new Image<Rgba32>(500, 500))
                {
                    for (int y = 0; y < _map.height; y++)
                    {
                        for (int x = 0; x < _map.width; x++)
                        {
                            byte alpha = (byte)(_map.Palette[_map.Background[x, y]] >> 24);
                            byte r = (byte)((_map.Palette[_map.Background[x, y]] >> 16) & 0xFF);
                            byte g = (byte)((_map.Palette[_map.Background[x, y]] >> 8) & 0xFF);
                            byte b = (byte)(_map.Palette[_map.Background[x, y]] & 0xFF);
                            img[x, y] = new Rgba32(r, g, b, alpha);
                        }
                    }

                    img.SaveAsPng(outStream);
                }
                Image64 = "data:image/png;base64," + Convert.ToBase64String(outStream.ToArray());
            }

    The image MUST be loaded before calling DrawImage!  Then, in the button click event I just do:
            if (!string.IsNullOrEmpty(Image64))
            {
                await this._context.DrawImageAsync(ImageMap, 0, 0, 500, 500);
            }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Tuesday, December 29, 2020 2:41 AM