【问题标题】:Convert and upload canvas as image将画布转换为图像并上传
【发布时间】:2015-08-26 21:13:03
【问题描述】:

我需要通过 jQuery Ajax 上传一个画布(保存为 png 图像)。如果我通过多部分表单上传图像,用户浏览文件而不是点击提交按钮,它可以工作,但我需要捕获画布并上传图像,用户不上传文件,而是点击按钮让画布转换比上传。

这是一个示例表单提交,一旦用户浏览并上传他们的文件,它就会上传文件:

<form action="http://myrestservice/endpoint" name="form" id="formId" method="post" enctype="multipart/form-data">
<input type="file" name="File1" size="50" maxlength="50" /><a class="textLabel">*** Upload a file is required</a>
<input type="submit" value="Submit Request">
</form>

只是为了证明 Web 服务有效。它指出传输的类型是文档。我也得到了 200 OK 响应。

如果我创建一个带有画布的不同页面并添加一个按钮以将画布上传到图像,它会声明传输类型是 xhr。我也得到了 200 OK 响应。

这是我的 JavaScript,用于在将画布转换为图像后上传画布。有趣的是,这段代码给了我一个“在 Access-Control-Allow-Origin 标头中找不到”。错误,而常规手动上传不会:

$scope.imageMe = function () {
    var canvasImage = document.getElementById("c");
    var img = canvasImage.toDataURL("image/png");
    var filename = 'Test.png';
    var formdata = new FormData();
    formdata.append(filename, img);

    $.ajax({
        url: 'http://myrestservice/endpoint',
        type: "POST",
        data: formdata,
        processData: false,
        contentType: false,
        success: function (result) {
            console.log("Upload complete!");
        },
        error: function (error) {
            console.log("Something went wrong!");
        }            
    });
}

更新:

我可以发帖,但没有收到回复,因为我收到了跨源错误。应用程序供应商已回复:

要使用Ajax调用的页面,需要发送正确的 访问控制允许来源标头。 (这需要由 网络服务器)

由于 Web 服务位于另一个域中,我如何/在何处将其添加到 AJAX 以允许跨源调用?

更新 2:

供应商已响应以下要求。鉴于此,我如何编码我的 AJAX 请求才能工作?

HTTP POST 请求必须满足以下要求:

  • HTTP POST 请求的 Content-Type 标头的值应 在大多数情况下,是多部分/表单数据。
  • HTTP 请求部分可以添加到 HTTP POST 请求以附加数据文件和/或添加参数。
  • 对于添加到 HTTP POST 请求的每个 HTTP 请求部分,都应该存在 Content-Disposition 标头。
  • 对于每个数据文件,数据文件的(UTF-8 编码)文件名应该 在相应的 Content-Disposition 标头中指定。
  • 对于每个参数,参数的名称应该在 相应的 Content-Disposition 标头。
  • HTTP POST 请求的编码应为 base64 或否 编码(例如二进制、8 位……)。

【问题讨论】:

    标签: javascript jquery canvas


    【解决方案1】:

    Access-Control-Allow-Origin 标头错误表示您的服务不允许跨域请求。

    您可以像这样更改此标头(php):

     header("Access-Control-Allow-Origin: *");
    

    请注意,这将允许来自任何域的请求,出于安全原因,我建议将 * 替换为您要从中发出请求的域名。

    【讨论】:

    • 我正在使用 JavaScript 并且无法控制服务器。为什么它适用于表单上传而不是 AJAX 帖子?我可以让我的 AJAX 帖子像表单上传一样吗?
    • Ajax 与常规发帖不同,因为您的用户仍在原网站上,并未转移到服务网站。您还应该尝试将 ajax 的 dataType 更改为:“jsonp”
    • 我刚才又一次又一次地尝试过。它给了我一个 500 错误:500 问题(1)处理 /endpoint 的映射请求:org.w3c.dom.DOMException:INVALID_CHARACTER_ERR:指定了无效或非法的 XML 字符。
    • 你能做一个jsfiddle吗?我会仔细看看。
    • 执行 jQuery ajax 请求时,您可以将 headers 对象添加到您的请求中。将您的供应商请求的任何内容放在那里。 $.ajax(....., headers: {....}, .....);。另外,请检查this link
    【解决方案2】:

    如果您需要将其作为文件上传,例如通过$_FILES['your_file'] 在 php 中访问,您需要先将其转换为 blob。

    不幸的是,canvas 元素的toBlob 方法只在Firefox 中实现,所以我不得不调整这个great answer。 (需要转jpeg的可以使用)。

    $scope.imageMe = function () {
    
         var send= function(blob){
            var filename = 'Test.png';
            var formdata = new FormData();
            formdata.append('your_file', blob, filename);
    
            $.ajax({
               url: 'http://myrestservice/endpoint',
               type: "POST",
               data: formdata,
               processData: false,
               contentType: false,
               success: function (result) {
                  console.log("Upload complete!");
               },
               error: function (error) {
                  console.log("Something went wrong!");
               }
            })            
        }
    
        var canvasImage = document.getElementById("c");
        if(!canvasImage.toBlob){
           var dataURL = canvasImage.toDataURL();
           var bytes = atob(dataURL.split(',')[1])
           var arr = new Uint8Array(bytes.length);
           for(var i=0; i<bytes.length; i++){
              arr[i]=bytes.charCodeAt(i);
           }
           send(new Blob([arr], {type:'image/png'}));
        }
        else
           canvasImage.toBlob(send);
    }
    

    现在至于为什么你会出现这个“Access-Control-Allow-Origin”错误,@Yotam Omer 给了你一个good answer

    【讨论】:

    • 这种方法很有意义。 'your_file' 占位符是干什么用的?
    • 为您的表单命名,并通过$_FILES['your_file']访问它
    • 这有帮助。使用您的代码,我有一个帖子的 200 OK 消息,但回调在访问控制上失败。我今天将与应用程序供应商讨论这个问题
    • 尝试将your_file更改为name
    • 没有这样的运气(名称未在任何地方定义)。有它通常期望的值吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-26
    • 2017-09-08
    • 1970-01-01
    • 1970-01-01
    • 2020-05-14
    • 2021-11-23
    • 1970-01-01
    相关资源
    最近更新 更多