Get all pixels of an Image [Wand]
Question: I am using the [Wand Python
Library](https://wand.readthedocs.org/en/0.4.0/index.html), and trying to
solve the [Python Challenge](http://pythonchallenge.com), and my current
problem asks me to get all even/odd pixels.

This is, obviously, a very simple task. However, I found the Wand library
quite slow in loading pixels/copying pixels (Maybe it's because I also change
fill_color to the color of the pixel for each?), and I was wondering if I
could just load them all in at once.

My current solution to loading all pixels is something like this:

    
    
    from wand.image import Image
    img = Image(filename="5808.jpg")
    pixels = []
    for x in range(img.width+1):
        for y in range(img.height+1):
            pixels.append(img[x, y])
    
    print(pixels)
    

I'd prefer something like this:

    
    
    from wand.image import Image
    img = Image(filename="5808.jpg")
    print(img.pixels)
    

Is there anything akin to that? Thanks in advance.


Answer: Without attempting to read the Python Challenge, and just focusing on the
question..

> I'd prefer something like this: `img.pixels`

Iterating over the image size to collect `wand.color.Color` objects would be
slow as this invokes repeated uses of MagickWand's internal pixel iteration &
pixel structure. As said challenge is for Python, and not C buffers, I'd
recommend getting a buffer of pixel data once. After which your freely able to
iterate, compare, evaluate, & etc. without need of ImageMagick resource.

For this example, I'm assuming the images is a 2x2 PNG below _(scaled for
visibility.)_

![Example 2x2 PNG](http://i.stack.imgur.com/818mI.png)

    
    
    from wand.image import Image
    
    # Prototype local variables
    pixels = []
    width, height = 0, 0
    blob = None
    
    # Load image
    with Image(filename='2x2.png') as image:
        # Enforce pixels quantum between 0 & 255
        image.depth = 8
        # Save width & height for later use
        width, height = image.width, image.height
        # Copy raw image data into blob string
        blob = image.make_blob(format='RGB')
    
    # Iterate over blob and collect pixels
    for cursor in range(0, width * height * 3, 3):
        # Save tuple of color values
        pixels.append((blob[cursor],      # Red
                       blob[cursor + 1],  # Green
                       blob[cursor + 2])) # Blue
    print(pixels)
    #=> [(255, 0, 0), (0, 0, 255), (0, 128, 0), (255, 255, 255)]
    

This example is pretty quick, but remember Python does objects very well.
Let's extend the `Image` object, and create the method to satisfy
`img.pixels`.

    
    
    # Lets create a generic pixel class for easy color management
    class MyPixel(object):
        red = 0
        green = 0
        blue = 0
        def __init__(self, red=0, green=0, blue=0):
            self.red = red
            self.green = green
            self.blue = blue
        def __repr__(self):
            return u'#{0.red:02X}{0.green:02X}{0.blue:02X}'.format(self)
    
    # Extend wand.image.Image and add a new `img.pixels` pseudo-attribute
    class MyImage(Image):
        # Repeat above example
        @property
        def pixels(self):
            pixels = []
            self.depth = 8
            blob = self.make_blob(format='RGB')
            for cursor in range(0, self.width * self.height * 3, 3):
                pixel = MyPixel(red=blob[cursor],
                                green=blob[cursor + 1],
                                blue=blob[cursor + 2])
                pixels.append(pixel)
            return pixels
    
    # Call your custom class; which, collects your custom pixels
    with MyImage(filename=filename) as img:
        print(img.pixels)
    #=> [#FF0000, #0000FF, #008000, #FFFFFF]
    

