Search code examples
javafile-iobase64bytebufferedimage

Sending image in base64 to Java webserver, convert and save it


I have a website with an ongoing webcam stream which should send snapshots of the video stream to my own Java webserver. The snapshot generating and displaying functionality works perfectly on the website. I want to send the snapshot with a jQuery AJAX POST request to my webserver which looks like that:

$.ajax({
    type: 'POST',
    url: servicePath + "upload",
    contentType: 'multipart/form-data',
    xhrFields: {withCredentials: false},
    headers: {},
    data: hidden_canvas.toDataURL('image/png'),
    success: function(data, status, xhttp) {
        alert(data);
    },
    error: function() {
        alert("Error uploading snapshot file to server!");
    }
}); 

As I mentioned, displaying the hidden_canvas.toDataURL('image/png') inserted in a src attribute of an <img> works perfectly, so it is definitely valid.

My service on the webserver looks as follows:

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadPicture(byte[] imageBytes) {

    String uploadedFileLocation = UPLOAD_FOLDER + "test.png";

    try {
        OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
        out.write(imageBytes);
        out.flush();
        out.close();
    } catch (IOException e) {       
        return Response.status(500).entity("Can not save file<br>" + e.toString()).build();
    }

    return Response.status(200).entity("success").build();
}

Test.png is created successfully but not a valid png, when I open it, it does not display at all. And the file on the server looks as follows: Test.png content

What did I miss? Would there be an alternative way to process the image?


Here's my takeSnapshot method. How could I send the file without the toDataURL()? And what for param would I have to expect then on the server side?

function generateSnapshot() {
   var video = document.querySelector('#camera-stream');
   var hidden_canvas = document.querySelector('#canvas');
   var context = hidden_canvas.getContext('2d');

   var width = video.videoWidth;
   var height = video.videoHeight;

   if (width && height) {
       hidden_canvas.width = width;
       hidden_canvas.height = height;

       // Make a copy of the current frame in the video on the canvas.
       context.drawImage(video, 0, 0, width, height);

       // Turn the canvas image into a dataURL that can be used as a src for our photo.
       return hidden_canvas.toDataURL('image/png');
   }
}

Solution

  • I finally could make it work. The toBlob suggestion from Kayaman put me on the right track. But I was not able to send the blob as expected, I had to put it into a FormData and thus had to adjust my webservice. The solution looks as follows:

    Website Javascript code:

    hidden_canvas.toBlob(function(blob) {
        var fd = new FormData();
        fd.append('fileName', 'testBlob.png');
        fd.append('data', blob);
        sendAJAXFileUploadRequest(fd);
    },'image/png');
    
    function sendAJAXFileUploadRequest(formData) {
       $.ajax({
           type: 'POST',
           url: servicePath + "upload",
           xhrFields: {withCredentials: false},
           headers: {},
           data: formData,
           processData: false,
           contentType: false,
           success: function(data, status, xhttp) {
               alert(data);
           },
           error: function() {
               alert("Error uploading snapshot file to server!");
           }
       });          
    }
    

    And the Java Webservice:

    @POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response uploadPicture(@FormDataParam("data") byte[] imageBytes, @FormDataParam("fileName") String fileName) {
    
        String uploadedFileLocation = UPLOAD_FOLDER + fileName;
    
        try {
            OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
            out.write(imageBytes);
            out.flush();
            out.close();
        } catch (IOException e) {       
            logger.severe("Can not save file (file location: " + uploadedFileLocation + ")");
            return Response.status(500).entity("Can not save file<br>" + e.toString()).build();
        }
    
        return Response.status(200).entity("success").build();
    }