LoginSignup
6
3

環境

  • Ubuntu 22.04 LTS

埋め込む

draw.io を使うと、png に埋め込みができ、それを再編集できます。どうやっているのかな?

image.png
エクスポート画面

image.png

エクスポートした png を qiita に貼って

pngテスト.drawio.png

上の png をダウンロード、drawio で開く

image.png

数式は、再編集可能です。
image.png

chunk

「Canvas から生成した PNG 画像に独自の情報を埋め込む | GREE Engineering」
https://labs.gree.jp/blog/2013/12/8594/

を読むと、PNG はチャンクとしてデータを管理していて、独自チャンクなどとして自由に情報が格納できることがわかります。

「PNG: Chunk by Chunk — PyPNG 0.0.20 documentation」
https://pypng.readthedocs.io/en/latest/chunk.html
では、定義された18種類のチャンクがリストされています。

先の drawio で作成した png ファイルについて、
「PNG file chunk inspector」
https://www.nayuki.io/page/png-file-chunk-inspector
これでチェックすると、以下のように表示されました。

image.png

オレオレチャンクタイプではなく、tExt チャンクを使っているようです。

「PNG Specification: Chunk Specifications」
https://www.w3.org/TR/PNG-Chunks.html
では、tExt チャンクについて以下のように説明されています。

Textual information that the encoder wishes to record with the image can be stored in tEXt chunks. Each tEXt chunk contains a keyword and a text string, in the format:
Keyword: 1-79 bytes (character string)
Null separator: 1 byte
Text: n bytes (character string)
The keyword and text string are separated by a zero byte (null character). Neither the keyword nor the text string can contain a null character. Note that the text string is not null-terminated (the length of the chunk is sufficient information to locate the ending). The keyword must be at least one character and less than 80 characters long. The text string can be of any length from zero bytes up to the maximum permissible chunk size less the length of the keyword and separator.
Any number of tEXt chunks can appear, and more than one with the same keyword is permissible.

The keyword indicates the type of information represented by the text string. The following keywords are predefined and should be used where appropriate:

PNG Specification: Chunk Specifications

python プログラム でテキストを埋め込む

元にしたもの

「linux - Insert a text chunk into a png image - Stack Overflow」
https://stackoverflow.com/questions/9036152/insert-a-text-chunk-into-a-png-image
こちらに投稿されているサンプルコード

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!')

テスト

上記に以下を足します。

src = r'icon.png'
insert_text_chunk(src, 'just for test!')

pypng モジュールをインストールします。

$ sudo pip install pypng

カレントディレクトリに icon.png を置いて、実行します。

$ python chunkpng.py

チェック

「PNG file chunk inspector」
https://www.nayuki.io/page/png-file-chunk-inspector
こちらでうまくいったかどうか確認してみます。

処理前
image.png
処理後
image.png

埋め込まれているみたいですね!
「Missing null separator」は、キーワードとテキストが分離されていないためのエラーです。

python プログラムでテキストを取り出す

先のプログラムは2番めのチャンクに埋め込んでいました。ここでは固定した場所からテキストを取り出してみます。

import png
def decode_text_chunk(target, 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[1])

src = r'icon.png'
decode_text_chunk(src)

コレを実行すると、以下のように取り出せました。

(b'tEXt', b'just for test!')
6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3