Creating a PNG file in Python Creating a PNG file in Python python python

Creating a PNG file in Python


Simple PNG files can be generated quite easily from pure Python code - all you need is the standard zlib module and some bytes-encoding to write the chunks. Here is a complete example that the casual reader may use as a starter for their own png generator:

#! /usr/bin/python""" Converts a list of list into gray-scale PNG image. """__copyright__ = "Copyright (C) 2014 Guido Draheim"__licence__ = "Public Domain"import zlibimport structdef makeGrayPNG(data, height = None, width = None):    def I1(value):        return struct.pack("!B", value & (2**8-1))    def I4(value):        return struct.pack("!I", value & (2**32-1))    # compute width&height from data if not explicit    if height is None:        height = len(data) # rows    if width is None:        width = 0        for row in data:            if width < len(row):                width = len(row)    # generate these chunks depending on image type    makeIHDR = True    makeIDAT = True    makeIEND = True    png = b"\x89" + "PNG\r\n\x1A\n".encode('ascii')    if makeIHDR:        colortype = 0 # true gray image (no palette)        bitdepth = 8 # with one byte per pixel (0..255)        compression = 0 # zlib (no choice here)        filtertype = 0 # adaptive (each scanline seperately)        interlaced = 0 # no        IHDR = I4(width) + I4(height) + I1(bitdepth)        IHDR += I1(colortype) + I1(compression)        IHDR += I1(filtertype) + I1(interlaced)        block = "IHDR".encode('ascii') + IHDR        png += I4(len(IHDR)) + block + I4(zlib.crc32(block))    if makeIDAT:        raw = b""        for y in xrange(height):            raw += b"\0" # no filter for this scanline            for x in xrange(width):                c = b"\0" # default black pixel                if y < len(data) and x < len(data[y]):                    c = I1(data[y][x])                raw += c        compressor = zlib.compressobj()        compressed = compressor.compress(raw)        compressed += compressor.flush() #!!        block = "IDAT".encode('ascii') + compressed        png += I4(len(compressed)) + block + I4(zlib.crc32(block))    if makeIEND:        block = "IEND".encode('ascii')        png += I4(0) + block + I4(zlib.crc32(block))    return pngdef _example():    with open("cross3x3.png","wb") as f:        f.write(makeGrayPNG([[0,255,0],[255,255,255],[0,255,0]]))


Here's a Python3 example:

import pngwidth = 255height = 255img = []for y in range(height):    row = ()    for x in range(width):        row = row + (x, max(0, 255 - x - y), y)    img.append(row)with open('gradient.png', 'wb') as f:    w = png.Writer(width, height, greyscale=False)    w.write(f, img)


Is there some other library that would be better for this?

The png package would be a reasonable common choice.

Here's the project description:

PyPNG allows PNG image files to be read and written using pure Python.