Search code examples
c#.netblazor

Blazor WebAssembly - Read images larger than 500kb


Within my blazor webassembly i have an image upload which i convert to base64 to display to the user back like this:

protected async Task HandleFileSelection(InputFileChangeEventArgs e)
    {
        var file = e.GetMultipleFiles().FirstOrDefault();
        if (file != null)
        {
            var buffer = new byte[file.Size];
            await using (var stream = file.OpenReadStream())
            {
                var readAsync = await stream.ReadAsync(buffer, 0, buffer.Length);
            }
            UploadedImgBase64 = Convert.ToBase64String(buffer);
            TypeOfUploadedImg = file.ContentType.Split('/')[1];
    
            ImageSource = $"data:image/{TypeOfUploadedImg};base64,{UploadedImgBase64}";
        }
        StateHasChanged();
    }

This works only with tiny images. How would I do this with larger images for example with a max of 10mb as im going to upload them in a blob storage in azure and that can handle large images. but right now i get an error of

Uncaught (in promise) Error: System.IO.IOException: Supplied file with size 3437206 bytes exceeds the maximum of 512000 bytes.

Is there any way of displaying the uploaded image back to the user before sending it to azure without turning it into a base 64 string? As browsers don't let you have access to the file path so I cant just make the src of the image the file path.

Edit: Would I upload it to Azure first and get the link? I thought of that but it sounds kinda stupid as what if the user cancels. Then i have over written their previous image. How do bigger companies display large images when I upload them before clicking save?


Solution

  • I managed to fix this. There is no way that i know of that c# or blazor can display larger images so i can to use js interop to make it work. In my JS file i added this:

    function PreviewImg(){
        var uploadImg = document.querySelector("#uploadImg");
        var uploadedImgPreview = document.querySelector("#uploadedImgPreview");
        uploadImg.addEventListener("change", (event) => {
            const file = event.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.addEventListener("load", (event) => {
                    uploadedImgPreview.src = event.target.result;
                });
                reader.readAsDataURL(file);
            }
        });
    }
    

    my Page has these components:

    <div class="mt-5 mb-2">
        <img id="uploadedImgPreview" class="rounded w-[90%] mx-auto @(!LoadedImg ? "hidden" : "")" src="" alt="preview">
    </div>
    <div class="w-[300px] mx-auto">
        <InputFile OnChange="HandleFileSelection" id="uploadImg" accept="image/*" class="w-[100%] rounded-md px-4 h-10 cursor-pointer bg-white border border-black/10 dark:border-dark-supportColor shadow-sm mr-4 mt-5 grid place-content-center"></InputFile>
    </div>
    

    and in the base class for this page:

      [Inject]
        public IJSRuntime Js { get; set; }
        [Parameter]
        public TypeOfUpdate UpdateOfType { get; set; }
        [Parameter]
        public EventCallback Cancel { get; set; }
    
        protected bool LoadedImg { get; set; } = false;
        protected IBrowserFile? SelectedImg { get; set; } = null;
    
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if(firstRender)
                await Js.InvokeVoidAsync("PreviewImg",SelectedImg);
        }
        protected void HandleFileSelection(InputFileChangeEventArgs e)
        {
            SelectedImg = e.GetMultipleFiles().FirstOrDefault();
            LoadedImg = true;
        }
    
    

    So to fix this you can just pass the file to javascript and it can easily display it.