Yes, I feel this ought to be possible. You could use the Image.tobytes() then somehow frombytes(). However I tried for a long time to improve the efficiency of pi3d and ended up using numpy. Let me know if you figure out a way.

EDIT. OK seems to be as easy as

Code: Select all

```
im = Image.open(PATH + 'lenna_l.png')
img = im.tobytes()
atklib.atk(im.size[0], im.size[1],
ctypes.c_char_p(img))
Image.frombytes('L', im.size, img).save('lenna2_bw.png')
```

I will check out speed comparison.

PPS no difference in speed - presumably they're doing the same thing behind the scenes

... later still ...

Just for completeness I tried the cython route too, and it turned out to marginally faster (but the .so file was fifteen times bigger!). It was quite tedious figuring out the best way to pass the data and in the end I had to go back to numpy array. If anyone decides they need to roll their own external functionality then there is a lot to be said for using cython. Here is a record of what I did. This was the atk_mod_a.pyx file

Code: Select all

```
from __future__ import division
import numpy as np
cimport numpy as np
cdef inline np.uint8_t adderror(np.uint8_t b, int e):
return min(max(b + e, 0x00), 0xFF)
def atk(np.ndarray[np.uint8_t, ndim=2] pixels):
cdef:
int x, y, off, err
int threshold = 127
np.uint8_t old, new
int h = pixels.shape[0]
int w = pixels.shape[1]
for y in range(h):
for x in range(w):
old = pixels[y, x]
if old > threshold:
new = 0xFF
else:
new = 0x00
err = (old - new) >> 3; # divide by 8
pixels[y, x] = new
# now distribute the error...
if (x+1) < w: # x+1, y
pixels[y, x + 1] = adderror(pixels[y, x + 1], err)
if (x+2) < w: # x+2, y
pixels[y, x + 2] = adderror(pixels[y, x + 2], err)
if x > 0 and (y+1) < h: # x-1, y+1
pixels[y + 1, x - 1] = adderror(pixels[y + 1, x - 1], err)
if (y+1) < h: # x, y+1
pixels[y + 1, x] = adderror(pixels[y + 1, x], err)
if (x+1) < w and (y+1) < h: # x+1, y+1
pixels[y + 1, x + 1] = adderror(pixels[y + 1, x + 1], err)
if (y+2) < h: # x, y+2
pixels[y + 2, x] = adderror(pixels[y + 2, x], err)
```

and this was the setup.py file

Code: Select all

```
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("atk_mod_a.pyx")
)
```

built on the command line with

Code: Select all

`python3 setup.py build_ext --inplace`

and used from normal python

Code: Select all

```
from PIL import Image
import numpy as np
from atk_mod_a import atk
PATH = '/home/pi/atkinson/'
img = np.array(Image.open(PATH + 'lenna_l.png'))
atk(img)
Image.fromarray(img).save('lenna_bw.png')
```