Turning binary string into an image with PIL

17,944

Solution 1

You could use img.putdata:

import Image

value = "0110100001100101011011000110110001101111"

cmap = {'0': (255,255,255),
        '1': (0,0,0)}

data = [cmap[letter] for letter in value]
img = Image.new('RGB', (8, len(value)//8), "white")
img.putdata(data)
img.show()        

enter image description here


If you have NumPy, you could instead use Image.fromarray:

import Image
import numpy as np

value = "0110100001100101011011000110110001101111"

carr = np.array([(255,255,255), (0,0,0)], dtype='uint8')
data = carr[np.array(map(int, list(value)))].reshape(-1, 8, 3)
img = Image.fromarray(data, 'RGB')
img.save('/tmp/out.png', 'PNG')

but this timeit test suggests using putdata is faster:

value = "0110100001100101011011000110110001101111"*10**5

def using_fromarray():
    carr = np.array([(255,255,255), (0,0,0)], dtype='uint8')
    data = carr[np.array(map(int, list(value)))].reshape(-1, 8, 3)
    img = Image.fromarray(data, 'RGB')
    return img

def using_putdata():
    cmap = {'0': (255,255,255),
            '1': (0,0,0)}

    data = [cmap[letter] for letter in value]
    img = Image.new('RGB', (8, len(value)//8), "white")
    img.putdata(data)
    return img

In [79]: %timeit using_fromarray()
1 loops, best of 3: 1.67 s per loop

In [80]: %timeit using_putdata()
1 loops, best of 3: 632 ms per loop

Solution 2

And for 1bit/pixel images :

im = Image.new('1', (image_width, image_height), "black")

cmap = {'0': 0,
        '1': 1}

data = [cmap[letter] for letter in data_bin]
im.putdata(data)
Share:
17,944
Peaser
Author by

Peaser

Updated on June 14, 2022

Comments

  • Peaser
    Peaser almost 2 years

    So, what I'm trying to do is have PIL create an image based on a string of binary. Some backstory:

    from PIL import Image
    
    value = "0110100001100101011011000110110001101111"
    vdiv = [value[i:i+8] for i in range(0, len(value), 8)]
    

    ^This creates a list of bytes from the binary string. ['01101000', '01100101',.....]

    def diff(inp):
        if inp == '1':
            return (0,0,0)
        if inp == '0':
            return (255,255,255)
        else:
            pass
    

    ^This returns a color tuple for each corresponding bit, and if I call:

    for i in vdiv:
        for i2 in i:
            print diff(i2)
    

    It will print every color tuple for each bit in the bytes listed. (0,0,0) (0,0,0) (255,255,255)...

    What I want to know is, How can I get PIL to create an image where the pixels match the binary string?

    Here is what it should look like.: screenshot

    What I have so far for PIL:

    img = Image.new( 'RGB', (8,len(vdiv)), "white")
    pixels = img.load()
    
    ##
    for x in range(img.size[0]):
        for y in range(img.size[1]):
            for i in vdiv:
                for i2 in i:
                    pixels[x,y] = diff(i2) #Creates a black image. What do?
    ##
    
    img.show()
    

    It is the for x in range bit that gets me. I am lost.