d3pd
d3pd

Reputation: 8315

How can I create a PNG image file from a list of pixel values in Python?

I can generate a list of pixel values from an existing image file using a procedure like the following:

from PIL import Image
image = Image.open("test.png")
pixels = list(image.getdata())
width, height = image.size
pixels = [pixels[i * width:(i + 1) * width] for i in xrange(height)]

How could I convert this list of pixel values back to an image file?

Upvotes: 5

Views: 15342

Answers (2)

rjonnal
rjonnal

Reputation: 1207

Quick fix

First, you need to have your pixel tuples in a single un-nested list:

pixels_out = []
for row in pixels:
    for tup in row:
        pixels_out.append(tup)

Next, make a new image object, using properties of the input image, and put the data into it:

image_out = Image.new(image.mode,image.size)
image_out.putdata(pixels_out)

Finally, save it:

image_out.save('test_out.png')

Fundamental issue

Your list comprehension generates a list of lists, the latter being generated by the slicing (i*width:(i+1)*width). Your comprehension can be much easier: pixels = [pixel for pixel in pixels]. Obviously this outputs the same list, pixels, but you can use the idea to perform an operation on the pixels, e.g. pixels = [operation(pixel) for pixel in pixels].

Really, you overthought it. You don't have to manage the image dimensions. Getting the pixels in a list, and then putting them into an equal-sized image with putdata keeps the in order because they are linearized the same way by PIL.

In short, this is what your original snippet should have been:

from PIL import Image
image = Image.open("test.png")
image_out = Image.new(image.mode,image.size)

pixels = list(image.getdata())
image_out.putdata(pixels)
image_out.save('test_out.png')

Upvotes: 8

Alex Ivanov
Alex Ivanov

Reputation: 823

You can you cairo. Pretty easy.

#!/usr/bin/python

# Extracting pixels from an image ------
from PIL import Image
image = Image.open("test.png")
pixels = list(image.getdata())
width, height = image.size
pixels = [pixels[i * width:(i + 1) * width] for i in xrange(height)]


# Putting pixels back to an image ------

import cairo

Width=len(pixels[0])
Height=len(pixels)

surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, Width, Height)
context = cairo.Context (surface)

y=0
for row in pixels:
    x=0
    for rgb in row:
        r=rgb[0] /255.0
        g=rgb[1] /255.0
        b=rgb[2] /255.0
        context.set_source_rgb(r, g, b)
        context.rectangle(x, y, 1, 1)
        context.fill()
        x+=1
    y+=1

surface.write_to_png ("out.png") # Output to PNG

Upvotes: 0

Related Questions