【问题标题】:BlobBuilder ruins binary dataBlobBuilder 破坏二进制数据
【发布时间】:2011-09-04 10:52:35
【问题描述】:

我对 BlobBuilder (Chrome11) 有疑问 我尝试使用 XHR 请求从服务器获取图像。然后我尝试使用 BlobBuilder / FileWriter 将其保存到本地 FS。互联网上的每个示例都是关于使用 text/plain mime 类型的,这些示例运行良好。但是当我尝试写入使用 XHR 获得的二进制数据时,文件大小会比原始文件大小大 1.5-2 倍。并且无法在 Picasa / Eye Of Gnome 中查看。

var xhr = new XMLHttpRequest();
var photoOrigUrl = 'http://www.google.ru/images/nav_logo72.png';
xhr.open('GET', photoOrigUrl, true);
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        var contentType = xhr.getResponseHeader('Content-type');

        fsLink.root.getFile('nav_logo72.png', {'create': true}, function(fileEntry) {
            fileEntry.createWriter(function(fileWriter) {
                var BlobBuilderObj = new (window.BlobBuilder || window.WebKitBlobBuilder)();
                BlobBuilderObj.append(xhr.responseText);

                fileWriter.write(BlobBuilderObj.getBlob(contentType));
            }, function(resultError) {
                console.log('writing file to file system failed (   code ' + resultError.code + ')');
            });
        });
    }
}

xhr.send();

fsLink 存在,这是扩展。

【问题讨论】:

  • 感谢您的提问,答案对我的项目帮助很大!

标签: javascript html google-chrome-extension blob


【解决方案1】:

问题在于BlobBuilder.append(xhr.responseText) 将其参数检测为 UTF-8 字符串,这是 XHR 返回的内容,而不是二进制数据,这才是真正的。有几个技巧可以让 BlobBuilder 将其读取为二进制数据而不是字符串数据:

var xhr = new XMLHttpRequest();
var photoOrigUrl = 'http://www.google.ru/images/nav_logo72.png';
xhr.open('GET', photoOrigUrl, true);

// CHANGE 1: This stops the browser from parsing the data as UTF-8:
xhr.overrideMimeType('text/plain; charset=x-user-defined');

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        var contentType = xhr.getResponseHeader('Content-type');

        fsLink.root.getFile('nav_logo72.png', {'create': true}, function(fileEntry) {
            fileEntry.createWriter(function(fileWriter) {

                // CHANGE 2: convert string object into a binary object
                var byteArray = new Uint8Array(xhr.response.length);
                for (var i = 0; i < xhr.response.length; i++) {
                    byteArray[i] = xhr.response.charCodeAt(i) & 0xff;
                }

                var BlobBuilderObj = new (window.BlobBuilder || window.WebKitBlobBuilder)();

                // CHANGE 3: Pass the BlobBuilder an ArrayBuffer instead of a string
                BlobBuilderObj.append(byteArray.buffer);

                // CHANGE 4: not sure if it's needed, but keep only the necessary
                // part of the Internet Media Type string
                fileWriter.write(BlobBuilderObj.getBlob(contentType.split(";")[0]));
            }, function(resultError) {
                console.log('writing file to file system failed (   code ' + resultError.code + ')');
            });
        });
    }
}

xhr.send();

这给了我一个与xhr.getResponseHeader('Content-Length') 建议的长度相同的文件。

【讨论】:

  • 另外,当您认为答案正确时,请记住接受答案;)
  • 斯托尔夫,你是男人!!!你让我今天一整天都感觉很好!非常感谢你!我唯一不明白的是用这个“text/plain; charset=x-user-defined”覆盖 mimetype。我一直认为可以在这里指定所需的响应 mimetype,但是为什么我们要在这里放“text/plain”呢?
  • 很高兴为您提供帮助 :)。那行只是告诉浏览器不要对请求返回的数据做任何聪明的事情——否则它总是会尝试将其转换为文本,并使用当前页面的文本编码(我认为......)。可能是历史事件,因为 XHR 以前仅用于“text/xml”或“application/xml”,猜测。
  • 不要使用xhr.overrideMimeType(...)。这很 hacky,并且有更好的方法来实现同样的目标。请参阅下面关于使用ArrayBuffer 的回复。
【解决方案2】:

顺便说一句,XHR2 为实现我的任务设置了更好的方法:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.google.ru/images/nav_logo72.png', true);
xhr.responseType = 'blob';

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        // xhr.responseBlob is needed blob data
    }
}

xhr.send();

唯一令人失望的是这仍然是 Chrome 中的一个错误:http://code.google.com/p/chromium/issues/detail?id=52486

【讨论】:

    【解决方案3】:

    您可以使用xhr.responseType='arraybuffer'

    BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
    
    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/path/to/image.png', true);
    xhr.responseType = 'arraybuffer';
    
    xhr.onload = function(e) {
      if (this.status == 200) {
        var bb = new BlobBuilder();
        bb.append(this.response); // Note: not xhr.responseText
    
        var blob = bb.getBlob('image/png');
        ...
      }
    };
    
    xhr.send();
    

    【讨论】:

    • +1 表示朝着正确方向迈出一步。看起来 BlobBuilder 已被弃用,Chrome 要求我改用 window.Blob。
    • 大声笑,你知道的,你的博客链接html5rocks.com/en/tutorials/file/dndfiles
    【解决方案4】:

    XMLHttpRequest 无法加载 http://www.google.ru/images/nav_logo72.png。 Access-Control-Allow-Origin 不允许使用原始文件://。

    【讨论】:

      【解决方案5】:

      我认为 Stoive 是正确的,但我想指出的是,现在可以使用 Blob 构造函数代替 BlobBuilder 来解决问题

       var b = new Blob([byteArray.buffer], {'type': 'application/type'});
      

      我认为这更符合当前标准。非常感谢 Stoive,非常有帮助。

      【讨论】:

      • +1.BlobBuilde 现在已被复制 Blob 应在所有情况下使用。
      猜你喜欢
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-26
      • 1970-01-01
      • 1970-01-01
      • 2017-12-21
      • 1970-01-01
      相关资源
      最近更新 更多