无法使图像 Blob JSON 可序列化

Unable to make an Image Blob JSON Serializable

由于 base64 编码失败而创建的 JIRA 票证:https://jira.appcelerator.org/browse/TC-5876

我目前的配置: 钛 SDK 5.1.2.GA 在 iPhone iOS 9.1

上测试

我在一个客户的项目中遇到了一个问题,该项目需要将在设备(使用相机)上拍摄的图像发送到 WebService,然后才能在使用该应用程序的任何设备上看到(两者都 Android 和 iOS 设备)。 Titanium 在拍照后提供了一个 Ti.Blob 对象 (event.media)(这不是 JSON 可序列化的),我需要以某种方式将其发送到服务器。服务器总是响应一个 JSON 对象,因此这个 Blob 必须以某种方式 JSON 可序列化。

我尝试了很多方法都没有成功:

1 - Base64Encode Blob

var base64blob = Ti.Utils.base64encode(event.media);

不起作用,它会卡住应用程序并引发 ASL 超出最大大小错误。我想图像太大而无法进行base64编码。

2 - 将 Blob 读入缓冲区

var blobStream = Ti.Stream.createStream({ source: event.media, mode: Ti.Stream.MODE_READ });
var buffer = Ti.createBuffer({ length: event.media.length });
var bytes = blobStream.read(buffer);

它有效,但我不知道如何将这个保存图像内容的缓冲区转换为服务器可以 return 在 JSON 对象中的东西,然后再次转换为图像 Blob .

服务器无法管理 Ti.Blob 对象或 Ti.Buffer 对象,因为首先,它们是 Titanium 对象,服务器是基于 C# 的,其次是由于 Ti.Blob并且 Ti.Buffer 不是 JSON 可序列化的,因此 JSON return 不起作用。

我所需要的基本在下面想象的例子中描述:

var imageBlob = event.media;
var JSONSerializableImg = imageBlob.toJSON();
sendImageToServer(JSONSerializableImg);

var imgFromServer = getImageFromServer();
var imageBlob = imgFromServer.toBlob();
var imgView = createImageView({
    image: imageBlob 
});

我希望有人可以帮助我提供任何可能的转换方法。

谢谢

我以前使用过以下方法(不是在 Titanium 中,而是在另一个基于 Web 的移动应用程序平台中)。

function convertToDataURLviaCanvas(url, callback, outputFormat){
    var img = new Image();
    img.crossOrigin = 'Anonymous';
    img.onload = function(){
        var canvas = document.createElement('CANVAS');
        var ctx = canvas.getContext('2d');
        var dataURL;
        canvas.height = this.height;
        canvas.width = this.width;
        ctx.drawImage(this, 0, 0);
        dataURL = canvas.toDataURL(outputFormat);
        callback(dataURL);
        canvas = null; 
    };
    img.src = url;
}

convertToDataURLviaCanvas('http://example.com/image.png', function(base64Img){
    // Base64DataURL
});

我用它来将 base64 编码的图像字符串作为 JSON 发送到我的后端服务器。然后在服务器上重新编码图像。它对我有用,但 base64 编码的字符串很大。

好的,

这就是我认为你必须做的。看看API,这是非常可行的。

1: 您需要创建一个对象服务器端来保存 BLOB。

public class BlobContainer 
{
    public string fileName{get;set;}
    //... (Other properties)
    public byte[] data {get;set;}
}

2:将BLOB中的重要信息转换成二进制数组发送给服务器。

var blobStream = Ti.Stream.createStream({ source: myBlob, mode: Ti.Stream.MODE_READ });
var newBuffer = Ti.createBuffer({ length: myBlob.length });
var bytes = blobStream.read(newBuffer);

3:然后通过Ajax请求向服务器发送字节数据。请注意您要发送的阵列有多大。拆分阵列并在另一侧组合它可能是有利的(可能没有必要):

var dataObjects: [
    { id: 1, data: [BYTE_DATA_PART] },
    { id: 2, data: [BYTE_DATA_PART] }...
]
$.each(dataObjects, function(i,a) {
    $.ajax({ url: "BLA", data: JSON.stringify(a), dataType: "json", type: "POST",
        success: function() { //CONTINUE\ },
        error: function() {alert("ERROR BRO"}) 
    });
});

4:然后服务器端在你的小 blob 容器中获取每个请求,存储在会话对象或缓存对象中,一旦你有 N 个中的 N 个,将它们拼凑在一起并将那个傻瓜存储在数据库中。

5: 以相反的顺序取回东西。请记住,它存储为 byte[] 数据。由于 TI 缓冲区创建字节的方式和 c# 解释字节的方式,您可能不得不弄乱它并将其存储为字符串。最好的事情是反复试验。一旦你把所有的东西都放回客户端。

var newBuffer = Ti.Stream.read(data, 0, data.length);
var newBlob = newBuffer.toBlob();

要向服务器发送二进制数据和从服务器接收二进制数据,最好使用可以发送和接收二进制数据的 Ti.Network.HTTPClient

这里有上传和下载文件的指南: http://docs.appcelerator.com/platform/latest/#!/guide/File_Uploads_and_Downloads

JSON isn't designed to carry binary data, although base64encoded binary data should work. This is what Ti.Utils.base64encode() indeed is for. If you believe the "ASL exceeded maximum size error" you get shouldn't happen, please create a ticket on Appcelerator JIRA

我通过在 server-side 上创建一个专门用于上传照片的单独方法解决了这个问题。对于服务器端,我遵循了下面的 link:

PHP code

在 Titanium 中,我必须像这样设置 XHR header:

this.xhr.setRequestHeader("ContentType", "image/png"); this.xhr.setRequestHeader('enctype', 'multipart/form-data');

就是这样! 谢谢大家的回答。