将文本块插入到 png 图像中

发布于 2024-12-29 18:35:04 字数 380 浏览 0 评论 0 原文

我正在寻找一个简单的命令行工具(在 Linux 上)将文本块(例如版权)插入到 png 文件中,从而生成一个新的 png 文件:

> png-insert-text-chunk "here's my text chunk" < in.png > out.png

注意:“插入文本块”并不是指“插入文本块” “在图像上绘制一些文字”。我的意思是:将文本作为块插入到 png 文件中,位于 技术意义。例如,这可用于插入实际图像上未显示的版权消息。

I'm looking for a simple command-line tool (on Linux) to insert a text chunk (e.g. copyright) into a png file, resulting in a new png file:

> png-insert-text-chunk "here's my text chunk" < in.png > out.png

Note: by "insert a text chunk", I do not mean "draw some text on the image". I mean: insert the text into the png file as a chunk, in the technical sense. This can be used, for example, to insert a copyright message that isn't displayed on the actual image.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

一世旳自豪 2025-01-05 18:35:04

使用 ImageMagick 的 convert-set 选项:

convert IN.png \
        -set 'Copyright' 'CC-BY-SA 4.0' \
        -set 'Title' 'A wonderful day' \
        -set comment 'Photo taken while running' \
        OUT.png

-set 选项用于设置元数据元素。对于 PNG 来说,这些通常会分成 tEXt 块。

Use ImageMagick's convert and the -set option:

convert IN.png \
        -set 'Copyright' 'CC-BY-SA 4.0' \
        -set 'Title' 'A wonderful day' \
        -set comment 'Photo taken while running' \
        OUT.png

The -set option is used to set metadata elements. In the case of PNG these often go into tEXt chunks.

注定孤独终老 2025-01-05 18:35:04

我已经四处寻找实用程序来执行此操作,但尚未找到任何真正符合我想做的事情。所以我决定构建我自己的,事实证明这并不太难。实用程序 png-text-dump 显示 PNG 图像中的所有文本块。它仅取决于 libpng。实用程序 png-text-append 将文本块插入到 PNG 图像中。它仅依赖于标准 C 库 - 我最初尝试使用 libpng 来实现此功能,但实际上发现仅使用 PNG 规范从头开始工作更容易。

I have searched around for utilities to do this, and not yet found anything that really matches what I want to do. So I decided to build my own, which it turns out is not too hard. The utility png-text-dump displays all text chunks in a PNG image. It depends only on libpng. The utility png-text-append inserts text chunks into a PNG image. It depends only on the standard C library - I had initially tried to implement this using libpng, but actually found it easier to work from scratch using only the PNG specification.

沉溺在你眼里的海 2025-01-05 18:35:04

这可以使用 python pypng 模块实现。 python3示例代码如下:

import png

TEXT_CHUNK_FLAG = b'tEXt'


def generate_chunk_tuple(type_flag, content):
    return tuple([type_flag, content])


def generate_text_chunk_tuple(str_info):
    type_flag = TEXT_CHUNK_FLAG
    return generate_chunk_tuple(type_flag, bytes(str_info, 'utf-8'))


def insert_text_chunk(target, text, index=1):
    if index < 0:
        raise Exception('The index value {} less than 0!'.format(index))

    reader = png.Reader(filename=target)
    chunks = reader.chunks()
    chunk_list = list(chunks)
    print(chunk_list[0])
    print(chunk_list[1])
    print(chunk_list[2])
    chunk_item = generate_text_chunk_tuple(text)
    chunk_list.insert(index, chunk_item)

    with open(target, 'wb') as dst_file:
        png.write_chunks(dst_file, chunk_list)


def _insert_text_chunk_to_png_test():
    src = r'E:\temp\png\register_05.png'
    insert_text_chunk(src, 'just for test!')


if __name__ == '__main__':
    _insert_text_chunk_to_png_test()

This can be implemented with python pypng module. The python3 example code is below:

import png

TEXT_CHUNK_FLAG = b'tEXt'


def generate_chunk_tuple(type_flag, content):
    return tuple([type_flag, content])


def generate_text_chunk_tuple(str_info):
    type_flag = TEXT_CHUNK_FLAG
    return generate_chunk_tuple(type_flag, bytes(str_info, 'utf-8'))


def insert_text_chunk(target, text, index=1):
    if index < 0:
        raise Exception('The index value {} less than 0!'.format(index))

    reader = png.Reader(filename=target)
    chunks = reader.chunks()
    chunk_list = list(chunks)
    print(chunk_list[0])
    print(chunk_list[1])
    print(chunk_list[2])
    chunk_item = generate_text_chunk_tuple(text)
    chunk_list.insert(index, chunk_item)

    with open(target, 'wb') as dst_file:
        png.write_chunks(dst_file, chunk_list)


def _insert_text_chunk_to_png_test():
    src = r'E:\temp\png\register_05.png'
    insert_text_chunk(src, 'just for test!')


if __name__ == '__main__':
    _insert_text_chunk_to_png_test()
留一抹残留的笑 2025-01-05 18:35:04

注意:此答案是对问题原始修订版的回应,其中不清楚文本是否必须写入图像上,或者文本是否必须作为元数据嵌入到图像二进制文件中。这个答案假设是前者。然而,该问题经过编辑以澄清这意味着后者。这个答案保持不变,以防有人正在寻找前者的解决方案。


convert -draw "text 20,20 'hello, world'" input.png output.png

上面示例中的 20,20 是我想要放置文本的坐标。

您需要使用 imagemagick 包来获取此命令。

在 Ubuntu 或 Debian 上,可以使用以下命令安装:apt-get install imagemagick

下面是该命令的更详细的用法:

convert -font Helvetica -pointsize 20 -draw "text 20,20 'hello, world'" input.png output.png

Note: This answer was a response to the original revision of the question where it was not clear if the text had to be written on the image or if the text had to be embedded within the image binary file as metadata. This answer assumed the former. However the question was edited to clarify that it meant the latter. This answer is left intact, in case someone is looking for a solution to the former.


convert -draw "text 20,20 'hello, world'" input.png output.png

The 20,20 in the above example is the co-ordinate where I want to place the text.

You need to use the imagemagick package to get this command.

On Ubuntu or Debian, it can be installed with the command: apt-get install imagemagick.

Here is a slightly more elaborate usage of the command:

convert -font Helvetica -pointsize 20 -draw "text 20,20 'hello, world'" input.png output.png
好多鱼好多余 2025-01-05 18:35:04

我相信pngcrush有这个能力: http://pwet.fr/man/linux/commandes/pngcrush

I believe that pngcrush has this ability: http://pwet.fr/man/linux/commandes/pngcrush

浪推晚风 2025-01-05 18:35:04

添加到 @susam-pal 所做的评论,要更改颜色,请使用选项

-fill color

此选项接受颜色名称、十六进制颜色或数字 RGB, RGBA、HSL、HSLA、CMYK 或 CMYKA 规范。有关如何正确指定颜色参数的说明,请参阅颜色名称。

将颜色规范括在引号中,以防止 shell 解释“#”或括号。
例如,

-fill blue

-fill "#ddddff"

-fill "rgb(255,255,255)"


链接

Adding to the comment made by @susam-pal, to change color use the option

-fill color

This option accepts a color name, a hex color, or a numerical RGB, RGBA, HSL, HSLA, CMYK, or CMYKA specification. See Color Names for a description of how to properly specify the color argument.

Enclose the color specification in quotation marks to prevent the "#" or the parentheses from being interpreted by your shell.
For example,

-fill blue

-fill "#ddddff"

-fill "rgb(255,255,255)"


Obtained from link

怪我鬧 2025-01-05 18:35:04

您可以在 Python 中使用 pypng 库:

#!/bin/python3

import png

reader = png.Reader(filename='input.png')
chunks = list(reader.chunks())

chunk_field = (b"tEXt", b"Profile\x00Profile Content Here")
chunks.insert(1, chunk_field)

file = open('output.png', 'wb')
png.write_chunks(file, chunks)

You can use the pypng library in Python:

#!/bin/python3

import png

reader = png.Reader(filename='input.png')
chunks = list(reader.chunks())

chunk_field = (b"tEXt", b"Profile\x00Profile Content Here")
chunks.insert(1, chunk_field)

file = open('output.png', 'wb')
png.write_chunks(file, chunks)
妄想挽回 2025-01-05 18:35:04

我从pypng中提取了读写png-text-chunk的核心算法。这是最简单的例子。它比原始 pypng 实现快 10 倍

import struct
import zlib
from typing import Union


def write_text_chunk(img_bytes: bytes, data: Union[str, bytes]) -> bytes:
    assert img_bytes[:8] == b'\x89PNG\r\n\x1a\n'
    if isinstance(data, str):
        data = data.encode()
    start_idx = end_idx = img_bytes.find(b'tEXt') - 4
    if b'tEXt' in img_bytes:
        existed_data_len = struct.unpack("!I", img_bytes[start_idx: start_idx + 4])[0]
        end_idx += 12 + existed_data_len
    out_arr = img_bytes[:start_idx] + \
              struct.pack("!I", len(data)) + \
              b'tEXt' + data + \
              struct.pack("!I", zlib.crc32(data, zlib.crc32(b'tEXt')) & 2 ** 32 - 1) + \
              img_bytes[end_idx:]
    return out_arr


def read_text_chunk(img_bytes: bytes) -> bytes:
    assert img_bytes[:8] == b'\x89PNG\r\n\x1a\n'
    idx = img_bytes.find(b'tEXt')
    data_len = struct.unpack("!I", img_bytes[idx - 4: idx])[0]
    return img_bytes[idx + 4: idx + 4 + data_len]


if __name__ == '__main__':
    import time
    src = '打倒帝国主义.png'
    img_bytes = open(src, 'rb').read()
    t1 = time.time()
    embed_data = '中华人民共和国万岁!世界人民大团结万岁!'.encode() * 1
    out = write_text_chunk(img_bytes, embed_data)
    t2 = time.time()
    open('test.png', 'wb').write(out)

    t3 = time.time()
    read_embed_data = read_text_chunk(out)
    t4 = time.time()
    print(embed_data == read_embed_data, read_embed_data.decode())
    print('WRITE', t2 - t1)
    print('READ', t4 - t3)

I extracted the core algorithm of reading and writing png-text-chunk from pypng. This is the simplest example. And it's 10x faster than original pypng implementation

import struct
import zlib
from typing import Union


def write_text_chunk(img_bytes: bytes, data: Union[str, bytes]) -> bytes:
    assert img_bytes[:8] == b'\x89PNG\r\n\x1a\n'
    if isinstance(data, str):
        data = data.encode()
    start_idx = end_idx = img_bytes.find(b'tEXt') - 4
    if b'tEXt' in img_bytes:
        existed_data_len = struct.unpack("!I", img_bytes[start_idx: start_idx + 4])[0]
        end_idx += 12 + existed_data_len
    out_arr = img_bytes[:start_idx] + \
              struct.pack("!I", len(data)) + \
              b'tEXt' + data + \
              struct.pack("!I", zlib.crc32(data, zlib.crc32(b'tEXt')) & 2 ** 32 - 1) + \
              img_bytes[end_idx:]
    return out_arr


def read_text_chunk(img_bytes: bytes) -> bytes:
    assert img_bytes[:8] == b'\x89PNG\r\n\x1a\n'
    idx = img_bytes.find(b'tEXt')
    data_len = struct.unpack("!I", img_bytes[idx - 4: idx])[0]
    return img_bytes[idx + 4: idx + 4 + data_len]


if __name__ == '__main__':
    import time
    src = '打倒帝国主义.png'
    img_bytes = open(src, 'rb').read()
    t1 = time.time()
    embed_data = '中华人民共和国万岁!世界人民大团结万岁!'.encode() * 1
    out = write_text_chunk(img_bytes, embed_data)
    t2 = time.time()
    open('test.png', 'wb').write(out)

    t3 = time.time()
    read_embed_data = read_text_chunk(out)
    t4 = time.time()
    print(embed_data == read_embed_data, read_embed_data.decode())
    print('WRITE', t2 - t1)
    print('READ', t4 - t3)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文