简体   繁体   English

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

[英]How do I insert a PNG comment block when saving an HTML5 canvas using javascript toDataURL?

I have a compact canvas-to-png download saver function (see code below). 我有一个紧凑的canvas-to-png下载保护程序功能(请参见下面的代码)。 This code works very well and I am satisfied with its output... mostly. 这段代码非常好用,我对它的输出感到满意。 Would a second replace suffice? 再更换一次就足够了吗? What would that replace look like? 那会是什么样子呢? My only other option is to post-process the file with imagemagick. 我唯一的其他选择是使用imagemagick对文件进行后期处理。 Any ideas? 有任何想法吗?

More completely: I want to add metadata from javascript. 更完整地说:我想从javascript添加元数据。 I found this link http://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files which details the structures, and I may be able to figure it out with sufficient time. 我发现此链接http://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files详细介绍了结构,我也许可以花足够的时间弄清楚它。 If anyone has experience and can shorten this for me, I would appreciate it. 如果有人有经验并且可以为我缩短时间,我将不胜感激。

        //------------------------------------------------------------------
        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');
        }

The Base-64 representation has little to do with the internal chunks. Base-64表示与内部块无关。 It's just [any] binary data encoded as string so it can be transferred over string-only protocols (or displayed in a textual context). 它只是编码为字符串的[任何]二进制数据,因此可以通过仅字符串协议传输(或在文本上下文中显示)。

It's perhaps a bit broad to create an example, but hopefully showing the main steps will help to achieve what you're looking for: 创建示例可能有点宽泛,但是希望展示主要步骤将有助于实现您想要的目标:

  • To add a chunk to a PNG you would first have to convert the data for it into an ArrayBuffer using XHR/ fetch in the case of Data-URIs, or FileReader in case you have the PNG as Blob (which I recommend. See toBlob() ). 要将块添加到PNG,对于Data-URI,您首先必须使用XHR / fetch将其数据转换为ArrayBuffer ,如果将PNG作为Blob ,则必须将FileReader转换为ArrayBuffer (我建议。请参见toBlob() )。
  • Add a DataView to the ArrayBuffer DataView添加到ArrayBuffer
  • Go to position 0x08 in the array which will represent the start of the IHDR chunk, read the length of the chunk ( Uint32 ) (it's very likely it has the same static size for almost any PNG but since it's possible to have changes, and you don't need to remember the chunk size we'll just read it from here). 转到数组中代表IHDR块开始的位置0x08,读取块的长度( Uint32 )(很可能几乎所有PNG的静态大小都相同,但是因为有可能进行更改,所以您无需记住块大小,我们只需从此处读取)。 Add length to position (+4 for CRC-32 at the end of the chunk, and +4 if you didn't move the pointer while reading the length), typically this should land you at position 0x21. 将长度添加到位置(对于块末尾的CRC-32,为+4;如果在读取长度时未移动指针,则为+4),通常这会将您放置在位置0x21处。
  • You now have the position for the next chunk which we can use to insert our own text chunks 现在,您拥有了下一个块的位置,可以用来插入我们自己的文本块
  • Split that first part into a part-array (a regular array) using a sub-array with the original ArrayBuffer, eg new Uint8Array(arraybuffer, 0, position); 使用带有原始ArrayBuffer的子数组将第一部分拆分为一个部分数组(规则数组),例如, new Uint8Array(arraybuffer, 0, position); - you can also use the subarray method. -您也可以使用subarray方法。
  • Produce the new chunk* as typed array and add to part-array 产生新的chunk *作为类型化数组并添加到part-array
  • Add the remaining part of the original PNG array without the first part to the part-array, eg new Uint8Array(arraybuffer, position, length - position); 将原始PNG数组的剩余部分(不包括第一部分)添加到部分数组中,例如, new Uint8Array(arraybuffer, position, length - position);
  • Convert the part-array to a Blob using the part-array directly as argument ( var newPng = new Blob(partArray, {type: "image/png"}) ;). 直接将零件数组用作参数将零件数组转换为Blob( var newPng = new Blob(partArray, {type: "image/png"}) ;)。 This will now contain the custom chunk. 现在,它将包含自定义块。 From there you can use an Object-URL with it to read it back as an image (or make it available for download). 从那里,您可以使用Object-URL并将其读回为图像(或使其可供下载)。

*) Chunk: *)块:

  • For tEXt be aware of it is limited to the Latin-1 charset which means you'll have to whitewash the string you want to use - use iTXt for unicode (UTF-8) content - we'll use tEXt here for simplicity. 对于tEXt注意它仅限于Latin-1字符集,这意味着您将必须粉刷您要使用的字符串-将iTXt用于Unicode(UTF-8)内容-为了简单起见,我们在此使用tEXt
  • The keyword and value is separated by a NUL-byte (0x00) in a tEXt chunk, and the keyword must be exactly typed as defined in the spec . 关键字和值在tEXt块中用NUL字节(0x00) tEXt ,并且关键字必须按照规范中的定义正确键入。
  • Build the chunk this way: 以此方式构建块:
    • get byte-size from string 从字符串获取字节大小
    • add 12 bytes (for length, four-cc and crc-32) 添加12个字节(用于长度,四个cc和crc-32)
    • format the array this way (you can use a DataView here as well): 以这种方式格式化数组(您也可以在此处使用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.

All data in a PNG is big-endian. PNG中的所有数据都是big-endian。

To calculate CRC-32 feel free to use this part of my pngtoy solution (the LUT is built this way ). 要计算CRC-32,请随意使用pngtoy解决方案的这一部分 (以这种方式构建LUT)。 Here is one way to format a four-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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM