ArrayBuffer转换为Blob

74

我有一个项目需要在浏览器中显示djvu图纸。

我在Github上找到了这个旧的,据我所知,它将djvu文件转换为bmp,然后将其放入canvas元素中。

正如我所说,该库已经过时(最后一次提交是5年前),因此我需要进行一些更改。主要问题是该库使用过时的BlobBuilder。

我采取的解决方法有:

  1. 通过Chrome DevTools解压缩该库
  2. 错误最初出现在第3774行:var c = "undefined" != typeof MozBlobBuilder ? MozBlobBuilder : "undefined" != typeof WebKitBlobBuilder ? WebKitBlobBuilder : console.log("warning: cannot build blobs")
  3. 我注释掉了这一行
  4. 接下来,我还注释掉了c=new c;和一些随后的行。

所以,现在它看起来像这样(变量I是数组缓冲区,ololo1和ololo2是某种偏移量和限制)。

var c = new Blob(new Uint8Array(new Uint8Array(I,ololo1,ololo2)))
              , b = b.createObjectURL(c)
              , c = document.getElementById(kb)
              , f = c.getContext("2d")
              , h = new Image
              , g = a[Ea >> 2]
              , i = a[Fa >> 2]
              , j = c.width
              , k = Math.round(i * j / g);

            h.onload = function()
            {
                var a = g / j;
                4 < a && (a = 4);
                1 > a && (a = 1);
                f.globalAlpha = 1;

                for (N = 0; N < a; N++)
                    f.drawImage(h, N, N, g - a + N, i - a + N, 0, 0, j, k),
                    f.globalAlpha *= 1 - 1 / a;
                R(h.complete, "Image /bmp.bmp could not be decoded")
            }
            ;
            h.onerror = function(errorMsg, url, lineNumber, column, errorObj) {
                console.log(errorMsg, url, lineNumber, column, errorObj);
                console.log("Image /bmp.bmp could not be decoded!")
            }           
            ;

现在我遇到了错误:“Image /bmp.bmp 无法解码!”(在h.onerror处理程序中抛出)。

所以,我的问题是:我做错了什么?


1
原始代码为 c.append((new Uint8Array(new Uint8Array(I,ololo1,ololo2))).buffer)。 我不明白作者为什么将他的Uint8Array嵌套在新的Uint8Array中... 你只需要使用 new Blob([new Uint8Array(I,ololo1,ololo2)]) 就可以了。 - Kaiido
@Kaiido 非常感谢,运行得非常好。你可以将它发表为一个答案吗? - Rulisp
2个回答

137

我不知道为什么作者要在一个新的Uint8Array中包装它... 注意,我对已弃用的BlobBuilder API也不太了解,但是你代码中有一个错误,你需要将你的TypedArray包装在一个普通的Array中:

new Blob([new Uint8Array(buffer, byteOffset, length)]);

Blob() 构造函数以 blobParts sequence 作为第一个参数,然后在此序列中搜索 BufferSourceUSVStringsBlob 元素。因此,当您传递一个 TypedArray 时,它实际上会迭代此 TypedArray 的所有条目,并将这些条目视为 USVString(因此将其数值转换为 UTF-8 字符串在 Blob 中)。这很少是您想要的,因此最好始终在此构造函数中传递一个 Array

请注意,如果您不需要切片缓冲区,则直接传递它可能比使用中间人 Uint8Array 更好(但仍在正常的 Array 中):

new Blob([buffer]);

3
也拯救了我的一天(我传递了一个arrayBuffer以使用二进制数据,但需要将其包装为Array)。然而,我认为应该不用括号传递Uint8Array,因为它已经是一个数组,所以这不是OP的问题。你只需要在ArrayBuffer周围加上括号。 - aamarks
2
@aamarks 不会,如果您传递一个 Uint8Array,由于 Blob 构造函数不会访问其 .buffer 属性并且可能希望将包含的数据保存为二进制数据,因此将保存其所有 0~255 值作为 utf8 字符串。 - Kaiido
我明白了,谢谢。看起来只要在括号中传入缓冲区的Uint8Array视图或者Uint8Array本身,两者都可以正常工作。 - aamarks
20
Uint8Array是浪费,你不需要它,只需使用new Blob([buffer])。ArrayBuffer是一个字节数组。 - Domske
这只是一个视图。不确定起点是ArrayBuffer还是另一个类型的视图?这可能会使新的Blob(...)中的blob builder出现问题。 - mattdlockyer
显示剩余4条评论

58
var buffer = new ArrayBuffer(32);

new Blob([buffer]);

因此,Uint8Array 应该是:

new Blob([new Uint8Array([1, 2, 3, 4]).buffer]);

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