【问题标题】:How do I insert a PNG comment block when saving an HTML5 canvas using javascript toDataURL?使用 javascript toDataURL 保存 HTML5 画布时如何插入 PNG 注释块?
【发布时间】:2018-06-22 21:51:34
【问题描述】:

我有一个紧凑的 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');
        }

【问题讨论】:

  • 你想达到什么目的?第二个.replace() 的目的是什么?现有的.replace() 调用的目的是什么?
  • 您不会对 base64 编码数据使用字符串替换。您可能希望将数据重新转换为二进制格式并操作字节(即通过Typed arrays
  • 我的代码改编自我找到的“最佳”示例,用于将画布保存到我的下载目录中的 png 文件。我不完全理解。我的猜测是替换将格式转换为可传输的形式。该代码运行良好。我的目标是添加我想要的所有元数据,以便生成的 png 文件在“tEXt”块中具有标题、作者、描述和所有其他可用的元数据。生成 CRC 是我唯一认为自己做这件事的未知障碍。我仍然很想找到已经这样做的示例代码。
  • 实验并同意guest271314。我删除了替换,它工作正常。

标签: javascript html5-canvas png


【解决方案1】:

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

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

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

*) 块:

  • 对于 tEXt,请注意它仅限于 Latin-1 字符集,这意味着您必须对要使用的字符串进行白化 - 将 iTXt 用于 unicode (UTF-8) 内容 - 我们将为简单起见,请在此处使用tEXt
  • tEXt 块中的关键字和值由 NUL 字节 (0x00) 分隔,并且关键字必须完全按照 spec 中的定义键入。
  • 以这种方式构建块:
    • 从字符串中获取字节大小
    • 添加 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 part(LUT 是构建的 this way)。这是格式化四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
}

【讨论】:

  • 哇!你已经完全按照我的意愿回答了我的问题。我将尝试您编写的内容并编写一个元数据函数来完成我的想法。当我让它工作时,我会在这里发布它。谢谢你。我会尽快将其报告为答案。
  • @jlettvin 进展如何?
  • 我花了几天时间试图让它工作。最后,我不得不转向更紧迫的问题。我会回到这一天,而不是这周。
猜你喜欢
  • 2019-03-04
  • 2012-07-30
  • 2011-09-19
  • 1970-01-01
  • 2012-12-10
  • 2013-05-16
  • 2011-02-02
  • 2011-08-07
  • 2012-06-04
相关资源
最近更新 更多