使用Java Servlet保存HTML5 <canvas>图像

3
我知道已经有很多关于这个问题的StackOverflow问题了,但我已经尽可能地搜索了所有相关问题,但仍然无法使我的代码工作,所以我最终发布了自己的问题。
我的目标是将网页上HTML5 <canvas>中的图像保存到服务器上的文件中。我希望使用Java servlet来完成这个任务。
我的JavaScript代码获取画布图像数据如下:
var canvas = document.getElementById("screenshotCanvas");
var context = canvas.getContext("2d");                    
var imageDataURL = canvas.toDataURL('image/png');
// I'm not if I need to do this, I've tried several different ways to no avail
//imageDataURL = imageDataURL.replace("image/png", "image/octet-stream");
//imageDataURL = imageDataURL.replace(/^data:image\/(png|jpeg);base64,/,"");

$.ajax({
    url: screenshotCreateUrl,
    type: "POST",
    data: { imgBase64: imageDataURL },
    error: function(jqXHR, textStatus, errorThrown) {
        // Handle errors
    },
    success: function(data, textStatus, jqXHR) {
        // Do some stuff
    }
});

我的Java servlet尝试这样保存图像:

try {
    HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper(request);
    HttpServletRequestWrapper requestWithWrapper = (HttpServletRequestWrapper) wrappedRequest.getRequest();
    byte[] contentData = requestWithWrapper.getContentData();
    byte[] decodedData = Base64.decodeBase64(contentData);          
    FileOutputStream fos = new FileOutputStream("testOutput.png");
    fos.write(decodedData);
    fos.close();
} catch(Exception e) {
    // Handle exceptions
}

这个servlet成功地写出了一个图片文件,但是它没有正确打开,并且不包含其中的所有图片数据。我的Javascript成功地获取了<canvas>中的图片数据,它看起来像这样:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAgAElEQVR4nJTa51NcaZ7ge+QBIZBAwgoEkvDeJt577733njRk4r3PhDRAJkkmiTdCXqWqUlVXtZl209OzvWN27t17/5rvvoCu7t6ZmN158YnfcyJOnIjz4vnGEyeOWdRmAP+RaI3fT2I0PiTtBJF9KKD8TTKVb5IpPosl+zCMdFMgKQY/otTPCFl3IljhSPiWB5E7XkToPAnVexNq8CVyP5Cwg0CCDwII2vfHx+TDC6MXz3df8mznGc7bTthu2PJwxRrrufvcnzbn4bQFjnNWuK3a4r3hQrDmBSGbLwlRvyR0w5OQ9ZeErHsRsuFLyIYvQeu+BCh88Zf74K/wxU8ZgL8qEH9VEAHq0L8RqAkjeCuCsO1IwrVRhGujCNNdCdVFEayNJEQXdUUfTYg+mmC9AH99BL47YfjuhOK7G4KvIRhfQzDee4F47QXibQrCe98f730/vPf98N3zw9/kT+B+IG . . . [and so on]

有什么想法是我错过了什么吗?我感觉自己犯了一些微小的错误,但就是找不出来。


到目前为止,我甚至不知道JavaScript能够将画布编码为图像......为什么不尝试将数据作为请求参数传递,并使用request.getParameter("imgBase64")获取它呢? - cljk
另外,我会简化JS代码为: $.post(screenshotCreateUrl, {imgBase64: imageDataURL }); - cljk
2个回答

3

我曾经有类似的任务,并且成功地完成了它(不使用jQuery,而是借助于maclema的回复),通过使用multipart/form-data内容类型:

var xhr = new XMLHttpRequest();
xhr.open("post", "AddressOfYourServlet", false);
var boundary = Math.random().toString().substr(2);
xhr.setRequestHeader("content-type", 
    "multipart/form-data; charset=utf-8; boundary=" + boundary);
var multipart = "--" + boundary + "\r\n" +
    "Content-Disposition: form-data; name=myImg\r\n" +
    "Content-type: image/png\r\n\r\n" +
    canvas.toDataURL("image/png") + "\r\n" +
    "--" + boundary + "--\r\n";
xhr.send(multipart);

要异步处理或者如果您有更多的部分需要发送(例如多张图片),或者您想要使用响应,请参阅如何通过ajax(不使用jQuery)发送multipart/form-data表单内容? 您的servlet的doPost方法应该如下所示:
protected void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException {
  Part part = request.getPart("myImg");
  BufferedReader br = new BufferedReader(new InputStreamReader(part.getInputStream(),
      Charset.forName("utf-8")));
  String sImg = br.readLine();
  sImg = sImg.substring("data:image/png;base64,".length());
  byte[] bImg64 = sImg.getBytes();
  byte[] bImg = Base64.decodeBase64(bImg64); // apache-commons-codec
  FileOutputStream fos = new FileOutputStream("img.png");
  fos.write(bImg);
}

希望这能帮到你。

@Steph 如果这个解决了你的问题,你可以将其标记为最佳答案 :-) - legolas108
非常感谢您的帮助。它很好地解决了我的问题。我自己永远无法想出这个。 - Kiwi

1
你想获取请求的POST参数而不是内容数据。此外,你还需要去除编码信息。
试试这个:
try {
    HttpServletRequestWrapper wrappedRequest = new HttpServletRequestWrapper(request);
    HttpServletRequestWrapper requestWithWrapper = (HttpServletRequestWrapper) wrappedRequest.getRequest();
    String imageString = wrappedRequest.getParameter("imgBase64");
    imageString = imageString.substring("data:image/png;base64,".length);
    byte[] contentData = imageString.getBytes();
    byte[] decodedData = Base64.decodeBase64( contentData );          
    FileOutputStream fos = new FileOutputStream("testOutput.png");
    fos.write(decodedData);
    fos.close();
} catch(Exception e) {
    // Handle exceptions
    e.printStackTrace();
}

谢谢你的帮助,我尝试了这个方法,但它仍然没有完全工作。testOutput.png文件已经被写出并在图像查看器中打开,但是图像似乎是空白的。如果我在文本编辑器中打开文件,我可以看到里面有很多数据,但可能格式不完全正确或其他原因导致无法正常显示。 - Steph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接