javascriptasp.netmediacapture

POST image from canvas element - Javascript / .net core


I'm using the Media Capture and Streams API to connect to webcams and other peripheral cameras. We use the cameras to take still photos. My question is how can I POST or upload those photos to the server?

I'm capturing photos like so:

captureImage: function () {
    // canvas is just a <canvas> element
    const context = canvas.getContext("2d");
    canvas.width = 320;
    canvas.height = 240;
    context.drawImage(video, 0, 0, 320, 240); // video is a <video> tag with live feed of camera
    return canvas.toDataURL("image/png"); // can be used to set src of <img>
}

How can I POST the image to my .net endpoint so I can save it in Azure? So far I have tried:

    var imageData = document.getElementById("img-canvas").toDataURL("image/png");
    imageData = imageData.replace('data:image/png;base64,', '');

    var TestViewModel = {
        UploadFiles: document.getElementById("img-canvas").toDataURL("image/png"),
        ImageData: imageData
    }

    $.ajax({
        type: "POST",
        url: "/Orders/Evaluation/UploadFiles",
        data: TestViewModel, //JSON.stringify(TestViewModel),
        //contentType: 'application/json',
        dataType: "json",
        async: true,
        success: function (response) {
            console.log("success");
        },
        error: function (response) {
            console.log("fail");
        },
    });

On the server side, I have a simple endpoint setup:

[HttpPost("Orders/UploadFiles")]
public async Task<IActionResult> UploadPhotos(TestViewModel viewModel)
{
    // save photo to Azure
}

And the TestViewModel looks like:

public class TestViewModel
{
    public IFormFile UploadFiles { get; set; }
    public string ImageData { get; set; }
}

The problem I'm having is the viewModel.UploadFiles is always null. The viewModel.ImageData is a string that I need to convert into a file. I don't know if either of these options is even appropriate or if there is a better way to upload captured images that aren't yet files.


Solution

  • The best option I have found is to send images as FormData.

    First, you need to convert your base64string to a blob and post that blob as FormData. Then, you need to catch that file as IFormFile on the dotnet side.

    function convertBase64ToBlob(base64Image) {
        // Split into two parts
        var parts = base64Image.split(';base64,');
    
        // Hold the content type
        var imageType = parts[0].split(':')[1];
    
       // Decode Base64 string
        var decodedData = window.atob(parts[1]);
    
        // Create UNIT8ARRAY of size same as row data length
        var uInt8Array = new Uint8Array(decodedData.length);
    
       // Insert all character code into uInt8Array
        for (var i = 0; i < decodedData.length; ++i) {
            uInt8Array[i] = decodedData.charCodeAt(i);
        }
    
        // Return BLOB image after conversion
        return {
            blob: new Blob([uInt8Array], { type: imageType }),
            type: imageType
        }
    }
    
    function postImage(imageBlobData) {
        var formData = new FormData();
        var imageBlob = {
            blob: imageBlobData.blob,
            fileName: ('testImage' + imageBlobData.type.replace('image/', ''))
        }
        formData.append('imageFile', imageBlob.blob, imageBlob.fileName);
        $.ajax({
            url: '/Orders/UploadFiles',
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function (response) {
                // Handle success
            },
            error: function (error) {
                // Handle error
            }
         });
    }
    
    var imageData = document.getElementById("img-canvas").toDataURL();
    var blobData = convertBase64ToBlob(imageData);
    postImage(blobData);
    

    On the server side

    [HttpPost("Orders/UploadFiles")]
    public async Task<IActionResult> UploadImage(IFormFile imageFile)
    {
        try
        {
            if (imageFile != null && imageFile.Length > 0)
            {
                // Read the file stream
                using (var memoryStream = new MemoryStream())
                {
                    imageFile.CopyTo(memoryStream);
                    byte[] imageBytes = memoryStream.ToArray();
                    string fileName = imageFile.FileName;
    
                    //save image
    
                    return Json(new { success = true, message = "Image uploaded successfully." });
                }
            }
            else 
            {
                return Json(new { success = false, message = "No image file received." });
            }
        }
        catch (Exception ex)
        {
            return Json(new { success = false, message = "An error occurred: "  ex.Message });
        }
    }