Creating a PNG file in Python

After doing some searching, I found this site: https://www.daniweb.com/programming/software-development/code/454765/save-a-pygame-drawing. It just uses good old pygame.

Line 37 saves whatever is drawn on the pygame surface as a file.

EDIT

Here is the actual code:

    """pg_draw_circle_save101.py
    draw a blue solid circle on a white background
    save the drawing to an image file
    for result see http://prntscr.com/156wxi
    tested with Python 2.7 and PyGame 1.9.2 by vegaseat  16may2013
    """

    import pygame as pg

    # pygame uses (r, g, b) color tuples
    white = (255, 255, 255)
    blue = (0, 0, 255)

    width = 300
    height = 300

    # create the display window
    win = pg.display.set_mode((width, height))
    # optional title bar caption
    pg.display.set_caption("Pygame draw circle and save")
    # default background is black, so make it white
    win.fill(white)

    # draw a blue circle
    # center coordinates (x, y)
    center = (width//2, height//2)
    radius = min(center)
    # width of 0 (default) fills the circle
    # otherwise it is thickness of outline
    width = 0
    # draw.circle(Surface, color, pos, radius, width)
    pg.draw.circle(win, blue, center, radius, width)

    # now save the drawing
    # can save as .bmp .tga .png or .jpg
    fname = "circle_blue.png"
    pg.image.save(win, fname)
    print("file {} has been saved".format(fname))

    # update the display window to show the drawing
    pg.display.flip()

    
    # (press escape key or click window title bar x to exit)
    while True:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            # most reliable exit on x click
            pg.quit()
            raise SystemExit
        elif event.type == pg.KEYDOWN:
            # optional exit with escape key
            if event.key == pg.K_ESCAPE:
                pg.quit()
                raise SystemExit

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 zlib
import struct

def 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 png

def _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 png

width = 255
height = 255
img = []
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.

Tags:

Python

Image

Png