3

Python PIL library has Image.getdata() method, which return raw image data, writing:

list(im.convert("1").getdata())

will return an array of bits. Each bit corresponds to one image pixel - pixel can only be black or white because of "1" mode.

I would like to have an array which size is 8 times smaller. Each array element contains one byte.

My questions are:

  • 1. Can I get such an array of bytes directly from PIL?
  • 2. If not, how to convert array of bits returned by PIL to smaller array of bytes?

2 Answers 2

3

I don't know a thing about PIL and I haven't used Python for some time, but here is my take at this bits to bytes conversion problem.

import itertools
# assuming that `bits` is your array of bits (0 or 1)
# ordered from LSB to MSB in consecutive bytes they represent
# e.g. bits = [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1] will give you bytes = [128,255]
bytes = [sum([byte[b] << b for b in range(0,8)])
            for byte in zip(*(iter(bits),) * 8)
        ]
# warning! if len(bits) % 8 != 0, then these last bits will be lost

This code should be mostly self-explanatory.

Sign up to request clarification or add additional context in comments.

2 Comments

In case of bits array that uses values different than 0 and 1, fix byte[b] accordingly, e.g. use [0,1][byte[b]>0] instead.
This is what you get, when you become dormant language user... The whole zip(*[itertools.islice(bits, i, None, 8) for i in range(0,8)]) can be obviously simplified into zip(*(iter(bits),) * 8). I'll fix it in the answer too.
0

PIL's ImagingCore can easily be converted to bytes:

from PIL import Image


img = Image.open("python.jpg", "r")
data = img.convert("1").getdata()
bytes = bytearray(data)

This gives you a bytearray() list of bytes which can then be manipulated or written to a file. You could write this to a file by doing:

with open("filename", "w") as f:
    f.write(b"".join(map(bytes, data)))

I hope this helps!

It's probably worth noting too that Python in fact does not have a data type for bits. And that list(data) returns a list of int(s) and not "bits" as you thought?

Example:

>>> list(data)[:10]
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
>>> set(list(data))
set([0, 255])
>>> set(map(type, list(data)))
set([<type 'int'>])

So in reality you are not saving any data by doing this.

See: http://docs.python.org/2/library/stdtypes.html for Python data types and operations. You can perform "bit" operations, but there is no "bit" data type.

8 Comments

No it doesn't help at all. You just didn't understand the question. Note: len(list(img.convert("1").getdata())) == len(bytearray(img.convert("1").getdata()))
I beg your pardon? That expression evaluates to True. What exactly is your point?
Exactly - that expression evaluates to True. That's the problem. I want to get an array such as len(theArray) = len(bytearray(img.convert("1").getdata())) / 8. I want an array of bytes - what getdata gives me is an array of bits. They can be packed.
I'm sorry I do not see that. You get an array (more precisely: a list of ints) not "bits".
A list of int(s) is not an array of "bits".
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.