使用javascript toDataURL保存HTML5画布时如何插入PNG注释块?

时间:2018-01-13 18:41:04

标签: javascript html5-canvas png

我有一个紧凑的canvas-to-png下载保护程序功能(参见下面的代码)。 这段代码工作得非常好,我对它的输出很满意......主要是。 第二次更换是否足够?那替换会是什么样的? 我唯一的另一种选择是使用imagemagick对文件进行后处理。 有什么想法吗?

更完整:我想从javascript添加元数据。 我找到了这个链接http://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files 详细介绍了结构,我可以用足够的时间来弄清楚它。 如果有人有经验并可以为我缩短这一点,我将不胜感激。

        //------------------------------------------------------------------
        function save ()  // has to be function not var for onclick to work.
        //------------------------------------------------------------------
        {
            var element = document.getElementById("saver");
            element.download = savename;
            element.href = document.
                getElementById(id.figure1a.canvas).
                toDataURL("image/png").
                replace(/^data:image\/[^;]/,'data:application/octet-stream');
        }

1 个答案:

答案 0 :(得分:1)

Base-64表示与内部块几乎没有关系。它只是[任何]二进制数据编码为字符串,因此它可以通过字符串协议传输(或在文本上下文中显示)。

创建一个示例可能有点宽泛,但希望显示主要步骤将有助于实现您的目标:

  • 要向PNG添加块,首先必须在数据URI的情况下使用XHR / ArrayBufferfetch的数据转换为FileReader,或者Blob in如果您将PNG设为toBlob()(我建议使用。请参阅DataView)。
  • Uint32添加到ArrayBuffer
  • 转到数组中的位置0x08,它将代表IHDR块的开始,读取块的长度(subarray)(很可能几乎任何PNG都具有相同的静态大小,但是因为它是可能有变化,你不需要记住我们将从这里读取的块大小)。将长度添加到位置(块的末尾为CRC-32为+4,如果在读取长度时没有移动指针,则为+4),通常这应该位于0x21位置。
  • 您现在可以使用下一个块的位置来插入我们自己的文本块
  • 使用具有原始ArrayBuffer的子数组将第一部分拆分为部分数组(常规数组),例如new Uint8Array(arraybuffer, 0, position); - 您还可以使用spec方法。
  • 将新块*生成为类型化数组并添加到part-array
  • 将没有第一部分的原始PNG数组的剩余部分添加到部分数组中,例如new Uint8Array(arraybuffer, position, length - position);
  • 使用零件数组直接将零件数组转换为Blob作为参数(var newPng = new Blob(partArray, {type: "image/png"});)。这将包含自定义块。从那里你可以使用Object-URL将其作为图像读回(或使其可供下载)。

*)Chunk:

  • 对于tEXt,请注意它仅限于Latin-1字符集,这意味着您必须粉饰您要使用的字符串 - 使用iTXt作为unicode(UTF-8)内容 - 为简单起见,我们在这里使用tEXt
  • 关键字和值由tEXt块中的NUL字节(0x00)分隔,关键字必须按照this part中的定义进行输入。
  • 以这种方式构建块:
    • 从字符串中获取字节大小
    • 添加12个字节(长度,4-cc和crc-32)
    • 以这种方式格式化数组(您也可以在这里使用DataView):
      Uint32 - length of chunk (data only in number of bytes) Uint32 - "tEXt" as four-cc [...] - The data itself (copy byte-wise) Uint32 - CRC32* which includes the FourCC but not length and itself.

PNG中的所有数据都是大端的。

要计算CRC-32,请随意使用我的pngtoy解决方案的this way(构建LUT https://github.com/bvaughn/react-virtualized/blob/master/docs/Grid.md#cellrangerenderer)。以下是格式化四个cc的一种方法:

function makeFourCC(n) {  // n = "tEXt" etc., big-endian
    var c = n.charCodeAt.bind(n);
    return (c(0) & 0x7f) << 24 | (c(1) & 0x7f) << 16 | (c(2) & 0x7f) << 8 | c(3) & 0x7f
}