Create a PNG with text segments

This is an example of a program using libpng to create a PNG file with various text segments, including a compressed one, an uncompressed one, and a compressed and uncompressed international text segment. The PNG image itself is just a greyscale of random bytes. I've also removed all the error handling from this, for the sake of brevity. Please see Write a PNG file using C and libpng for error handling.

One strange thing I found about libpng while making this is that if the addition of a text segment fails, for example if the key is null (the specification requires it to be between 1 and 79 bytes long), no error is reported, and the text segment is simply not added.

#include <png.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
/* Write "bitmap" to a PNG file specified by "path"; returns 0 on
   success, non-zero on error. */

void save_png_to_file (const char *path)
    FILE * fp;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    size_t x, y;
    png_byte ** row_pointers = NULL;
    int pixel_size = 1;
    int depth = 8;
    int height = 100;
    int width = 100;

#define NTEXT 4

    png_text text_ptr[NTEXT];

    /* Error handling is omitted. See for error
       handling. */
    fp = fopen (path, "wb");
    png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    info_ptr = png_create_info_struct (png_ptr);

    text_ptr[0].key = "Title";
    text_ptr[0].text = "Mona Lisa";
    text_ptr[0].compression = PNG_TEXT_COMPRESSION_zTXt;
    text_ptr[1].key = "Author";
    text_ptr[1].text = "Leonardo DaVinci";
    text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
    text_ptr[2].key = "Detective";
    text_ptr[2].lang_key = "探偵";
    text_ptr[2].text = "工藤俊作";
    text_ptr[2].compression = PNG_ITXT_COMPRESSION_NONE;
    text_ptr[2].itxt_length = 12;
    text_ptr[2].lang = "Japanese";
    text_ptr[3].key = "Actor";
    text_ptr[3].lang_key = "俳優";
    text_ptr[3].text = "松田優作";
    text_ptr[3].compression = PNG_ITXT_COMPRESSION_zTXt;
    text_ptr[3].itxt_length = 12;
    text_ptr[3].lang = "Japanese";

    png_set_text (png_ptr, info_ptr, text_ptr, NTEXT);

    png_set_IHDR (png_ptr,
    /* Initialize rows of PNG. */

    row_pointers = png_malloc (png_ptr, height * sizeof (png_byte *));
    for (y = 0; y < height; y++) {
        png_byte *row = 
            png_malloc (png_ptr, sizeof (uint8_t) * width * pixel_size);
        row_pointers[y] = row;

        /* Fill the image with random data. */

        for (x = 0; x < width; x++) {
            *row++ = random () % 256;
    /* Write the image data to "fp". */

    png_init_io (png_ptr, fp);
    png_set_rows (png_ptr, info_ptr, row_pointers);
    png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);

    for (y = 0; y < height; y++) {
        png_free (png_ptr, row_pointers[y]);
    png_free (png_ptr, row_pointers);
    png_destroy_write_struct (&png_ptr, &info_ptr);
    fclose (fp);

int main ()
    save_png_to_file ("fruit.png");
    return 0;

Copyright © Ben Bullock 2009-2021. All rights reserved. For comments, questions, and corrections, please email Ben Bullock ( or use the discussion group at Google Groups. News about the site. / Privacy / Disclaimer