使用javascript toDataURL保存HTML5画布时,如何插入PNG注释块? [英] How do I insert a PNG comment block when saving an HTML5 canvas using javascript toDataURL?
问题描述
我有一个紧凑的canvas-to-png下载保护程序功能(请参见下面的代码).这段代码效果很好,我对它的输出感到满意……大部分情况下.再更换一次就足够了吗?那会是什么样子呢?我唯一的其他选择是使用imagemagick对文件进行后处理.有什么想法吗?
I have a compact canvas-to-png download saver function (see code below). 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. Any ideas?
更完全:我想从javascript中添加元数据.我发现此链接 http://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files 详细介绍了这些结构,我也许可以花足够的时间弄清楚.如果有人有经验并且可以为我缩短时间,我将不胜感激.
More completely: I want to add metadata from 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. 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');
}
推荐答案
Base-64表示与内部块无关.只是编码为字符串的[任何]二进制数据,因此可以通过仅字符串协议传输(或在文本上下文中显示).
The Base-64 representation has little to do with the internal chunks. 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:
- 要向PNG添加块,您首先必须将其数据转换为 ArrayBuffer 对于数据URI,使用XHR/获取,或 FileReader ,以防您将PNG命名为 Blob (我建议.请参见
toBlob()
). - 将 DataView 添加到ArrayBuffer
- 转到表示IHDR块起始位置的数组中的位置0x08,读取块的长度( subarray 方法.
- 将新chunk *作为类型化数组并添加到part-array
- 将原始PNG数组的其余部分(不包括第一部分)添加到part数组中,例如
new Uint8Array(arraybuffer,position,length-position);
- 直接使用零件数组作为参数将零件数组转换为Blob(
var newPng = new Blob(partArray,{type:"image/png"})
;).现在,它将包含自定义块.从那里,您可以将Object-URL与它一起使用以将其读回为图像(或使其可供下载).
- 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()
). - Add a DataView to the 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). 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.
- 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, e.g.
new Uint8Array(arraybuffer, 0, position);
- you can also use the subarray method. - Produce the new chunk* as typed array and add to part-array
- Add the remaining part of the original PNG array without the first part to the part-array, e.g.
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"})
;). 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).
*)块:
- 对于
tEXt
,请注意,它仅限于Latin-1字符集,这意味着您必须粉刷要使用的字符串-对iTXt
使用unicode(UTF-8)内容-为简单起见,我们将在此处使用tEXt
. - 关键字和值在
tEXt
块中以NUL字节(0x00)分隔,并且关键字必须完全按照规范. - 以这种方式构建块:
- 从字符串中获取字节大小
- 添加12个字节(用于长度,四个cc和crc-32)
- 以这种方式格式化数组(您也可以在此处使用DataView):
Uint32-块的长度(仅字节数的数据)Uint32-"tEXt"为四cc[...]-数据本身(按字节复制)Uint32-CRC32 *,其中包括FourCC,但不包括长度及其本身.
- 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 - useiTXt
for unicode (UTF-8) content - we'll usetEXt
here for simplicity. - 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. - Build the chunk this way:
- get byte-size from string
- add 12 bytes (for length, four-cc and crc-32)
- format the array this way (you can use a DataView here as well):
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中的所有数据都是大端的.
All data in a PNG is big-endian.
要计算CRC-32,请随时使用我的pngtoy解决方案的这一部分(LUT是
To calculate CRC-32 feel free to use this part of my pngtoy solution (the LUT is built this way). 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 }
这篇关于使用javascript toDataURL保存HTML5画布时,如何插入PNG注释块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!