我使用python的psd-tools包尝试创建unicode编码中文层名,但是执行create_pixel_layer时报错
1 | |
和chatgpt探讨时得知因为原始的层名是采用macroman编码,不支持中文编码。解决方案是使用luni tagged block。
在PSD规范里,整个文件都是大端序存储的,而luni(Unicode Layer Name) tagged block的内容是UTF‑16BE的Unicode字符串,以及前面再带一个4字节的大端序列的“长度”(utf-16的code unit个数,每16b一个,即每2B一个),可以通过编码为大端序utf-16后获取其字节个数除2得到。
以下是PSD标准中相关表述
All values defined as Unicode string consist of:
A 4-byte length field, representing the number of UTF-16 code units in the string (not bytes).
The string of Unicode values, two bytes per character and a two byte null for the end of the string.
例如,当字符串包含非BMP字符(码点>U+FFFF,比如很多emoji)时,如😀,len("😀") == 1(一个码点),"😀".encode("utf-16be")会是4字节,为2个16位的code unit,应该写入的长度为2。
因此,为了实现创建中文层名,在psd-tools中,需要这么做:
使用
macroman可编码字符作为真正的层名1
2layer = psd.create_pixel_layer(transparent_image, name=f"layer_{i}")对这个层附加
luni tagged block信息储存中文名1
2
3
4
5
6n_encoded = n.encode("utf-16be")
len_chars = len(n_encoded) // 2
layer._record.tagged_blocks[b"luni"] = TaggedBlock(
key=b"luni",
data=struct.pack(">I", len_chars) + n_encoded + b"\x00\x00",
)
这样生成的psd文件在各种支持的文件中打开就会显示中文名了,甚至某些情况下还能显示emoji。
另外末尾的两字节空字符可能是非必要的,我发现很多工具都能正常识别,但是为了更符合标准,我还是加上了。