如何上传/发布多个画布元素

Posted

技术标签:

【中文标题】如何上传/发布多个画布元素【英文标题】:How to upload/POST multiple canvas elements 【发布时间】:2011-12-04 11:29:03 【问题描述】:

我必须为未来的项目(无 flash、IE10+、FF7+ 等)创建一个图像上传器,该上传器在客户端而不是服务器上进行图像大小调整/转换/裁剪。

所以我制作了一个 javascript 界面,用户可以在其中“上传”他们的文件并直接在浏览器中调整大小/裁剪,而无需联系服务器。性能还可以,不是很好,但是可以。

最终结果是一组画布元素。用户可以在调整大小后编辑/裁剪图像,因此我将它们保留为画布而不是将它们转换为 jpeg。 (这会恶化初始性能)

现在这工作正常,但我不知道现在将完成的画布元素实际上传到服务器的最佳方式是什么。 (在服务器上使用 asp.net 4 通用处理程序)

我尝试从包含每个画布的 dataurl 的所有元素创建一个 json 对象。

问题是,当我得到 10-40 张图片时,浏览器在创建 dataurl 时开始冻结,尤其是对于大于 2 兆字节的图片。

            //images = array of UploadImage
            for (var i = 0; i < images.length; i++) 
                var data = document.getElementById('cv_' + i).toDataURL('image/jpg');
                images[i].data = data.substr(data.indexOf('base64') + 7);
            

还将它们转换为 json 对象(我使用的是 json2.js)通常会使我的浏览器崩溃。 (FF7)

我的对象

    var UploadImage = function (pFileName, pName, pDescription) 
        this.FileName = pFileName;
        this.Name = pName;
        this.Description = pDescription;
        this.data = null;
    

上传例程

            //images = array of UploadImage
            for (var i = 0; i < images.length; i++) 
                var data = document.getElementById('cv_' + i).toDataURL('image/jpg');
                images[i].data = data.substr(data.indexOf('base64') + 7);
            

            var xhr, provider;
            xhr = jQuery.ajaxSettings.xhr();
            if (xhr.upload) 
                xhr.upload.addEventListener('progress', function (e) 
                    console.log(Math.round((e.loaded * 100) / e.total) + '% done');
                , false);
            
            provider = function () 
                return xhr;
            ;
            var ddd = JSON.stringify(images); //usually crash here
            $.ajax(
                type: 'POST',
                url: 'upload.ashx',
                xhr: provider,
                dataType: 'json',
                success: function (data) 
                    alert('ajax success: data = ' + data);
                ,
                error: function () 
                    alert('ajax error');
                ,
                data: ddd
            );

将画布元素发送到服务器的最佳方式是什么?

我应该一次全部发送还是一个一个发送?

【问题讨论】:

这是一个非常有趣的问题。不知道为什么在没有任何 cmets 的情况下投了 2 票,+1 为什么这个问题被否决了? 生成数据url,一次发送一个。这将减少内存使用量。它还使您能够显示进度(不支持 xhr2)。另一个好处是服务器逻辑会稍微容易一些,服务器上的内存使用会更少。 【参考方案1】:

逐个上传文件更好。需要更少的内存,只要一个文件准备好上传,就可以开始上传,而不是等待所有文件都准备好。

使用FormData 发送文件。允许以二进制格式而不是 base64 编码上传文件。

var formData = new FormData;

如果 Firefox 使用 canvas.mozGetAsFile('image.jpg') 而不是 canvas.toDataUrl()。允许避免从 base64 到二进制的不必要转换。

var file = canvas.mozGetAsFile('image.jpg');
formData.append(file);

在 Chrome 中使用 BlobBuilder 将 base64 转换为 blob(参见 dataURItoBlob 函数

接受 在玩了一些东西之后,我设法自己解决了这个问题。

首先,这会将 dataURI 转换为 Blob:

//added for quick reference
function dataURItoBlob(dataURI) 
    // convert base64/URLEncoded data component to raw binary data held in a string
    var byteString;
    if (dataURI.split(',')[0].indexOf('base64') >= 0)
        byteString = atob(dataURI.split(',')[1]);
    else
        byteString = unescape(dataURI.split(',')[1]);

    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

    // write the bytes of the string to a typed array
    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) 
        ia[i] = byteString.charCodeAt(i);
    

    return new Blob([ia], type:mimeString);

来自this question):

var blob = dataURItoBlob(canvas.toDataURL('image/jpg'));
formData.append(blob);

然后发送formData 对象。我不知道如何在 jQuery 中做到这一点,但是使用普通的 xhr 对象就像这样:

var xhr = new XMLHttpRequest;
xhr.open('POST', 'upload.ashx', false);
xhr.send(formData);

在服务器上,您可以从 Files 集合中获取文件:

context.Request.Files[0].SaveAs(...);

【讨论】:

以上是关于如何上传/发布多个画布元素的主要内容,如果未能解决你的问题,请参考以下文章

通过动态创建 html 文件元素来上传克隆的画布照片,默认值为画布图像

如何将html5画布上的点击事件传递给兄弟画布元素上的事件监听器

如何在画布元素中添加超链接到图像?

如何使用 Vaadin 将图像上传到画布?

画布中的 HTML5 图像适合问题

如何将另一个矩阵雨代码动画添加到我的画布动画中?