25

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.

gcbenison
  • 11,723
  • 4
  • 44
  • 82
  • Next time try submitting similar questions to unix.stackexchange.com, as this isn't programming related. – Mr. Shickadance Jan 27 '12 at 16:14
  • 1
    @mr I'm not seeing how this question is less programming-related than, say, [this one](http://stackoverflow.com/questions/115818/which-format-for-small-website-images-gif-or-png) or [this one](http://stackoverflow.com/questions/182875/free-tool-to-create-edit-png-images). What if I wanted to write a CGI script in bash that inserts text chunks into a collection of images, and for that I'd need the command above? Sounds like a program to me. – gcbenison Jan 28 '12 at 01:17
  • He specifically asked for a command-line tool on Linux. I just figured I'd point out that unix.stackexchange.com exists. – Mr. Shickadance Jan 28 '12 at 16:52
  • Using php (command line): http://stackoverflow.com/questions/8842387/php-add-itxt-comment-to-a-png-image/8856458#8856458 – leonbloy Jan 30 '12 at 13:46
  • @leonbloy Cool, it works... I may continue looking for a more lightweight solution that does not require starting a php process – gcbenison Jan 30 '12 at 17:18

7 Answers7

19

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.

gioele
  • 9,748
  • 5
  • 55
  • 80
15

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.

gcbenison
  • 11,723
  • 4
  • 44
  • 82
  • Thanks for doing that work! I am trying to embed my own metadata into PNGs and saw that tEXt chuncks were the way to do it but I didn't see any tools that supported it. I will be using your utility! – stephenmm Mar 31 '13 at 02:21
  • fwiw, `pnginfo` from the `pngtools` package has the ability to _display_ the text chunks in a png file. Obviously not the same as adding your own (thanks for the code!) but useful for quick stuff sometimes. – arcticmac Mar 03 '16 at 00:37
  • I think that in line 79 of png-text-append should be : char name[5]={'\0'}; // 4 chars and one null terminator See http://stackoverflow.com/questions/15577124/strange-character-after-an-array-of-characters – Adam Jun 12 '16 at 10:21
  • @arcticmac, my `pnginfo` (v0.4-r2) doesn't seem to find any extra (tEXt) field added via `convert -set`... Instead, `exiftool` (v10.25) can do that! – sphakka Nov 02 '16 at 20:26
  • @sphakka yeah, iirc there's a bug in `pnginfo` where it only reads text chunks that come before the image data, and `convert` adds them after or something like that. Good to know about `exiftool` too. – arcticmac Nov 05 '16 at 04:32
6

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()
cfh008
  • 436
  • 5
  • 8
  • This is such a useful example. I didn't see this concept covered in the pypng documentation... perhaps you could submit it to the project docs. – michael_teter Nov 08 '18 at 21:01
  • Good idea, has submitted a issue: https://github.com/drj11/pypng/issues/85. – cfh008 Nov 17 '18 at 07:31
  • With the latest version of Python, I was getting a TypeError in write_chunk(). The solution is to ensure that type_flag is being sent as bytes rather than str: ```type_flag = bytes(TEXT_CHUNK_FLAG, 'utf-8')``` – michael_teter Jan 27 '19 at 10:11
5

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
Susam Pal
  • 32,765
  • 12
  • 81
  • 103
  • 2
    I'm looking for a command to insert a png "text chunk", i.e. embedded comments in the file. But this is a cool way to draw text on an image; I didn't know `convert` could do that. – gcbenison Jan 28 '12 at 14:27
0

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

Bruce_Warrior
  • 1,161
  • 2
  • 14
  • 24
0

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)
Tandera
  • 54
  • 3
0

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

futureman
  • 9
  • 1
  • 1
    I looked into pngcrush a bit, and it can do this; my only issue is that I can't seem to get it to leave the other chunks alone. Also I haven't been able to get it to simply print out the content of the text chunks existing in a png file. – gcbenison Mar 27 '12 at 15:12