Saturday, April 20, 2013

Python Script for getting pixel color on screen in OSX

This post on stackoverflow:, and this blog post: describe a pixel-color-grabbing method using python on OSX. Here is a simplified version, which takes command line arguments and is made to only capture a 1x1 pixel region (this makes it faster for just this functionality) (btw, I shall do my best to get this to format correctly for copying and pasting):

import struct
import operator
import Quartz.CoreGraphics as CG
import sys, getopt

def main():
    args = getopt.getopt(sys.argv[1:], '')
    twoArgs = len(args[1]) == 2
    #print args[1]
    #error correction here to check for [correct] arguments
    if twoArgs:
        argx = args[1][0]
        argy = args[1][1]
            global x
            x = int(argx)
            global y
            y = int(argy)
        except ValueError:
            print "Error! Enter two integers as arguments."
            #print x
            #print y
            sp = ScreenPixel()
            print sp.pixel(0, 0)
        print "Error! Script requires two integers as arguments."

class ScreenPixel(object):
    """Captures the screen using CoreGraphics, and provides access to
    the pixel values.
    ... pass two arguments to script (no comma, no nuthin', a la:
    ./ 112 767
    def capture(self):
        """see original version for capturing full screen
        (and lots of other stuff)
        region = CG.CGRectMake(x, y, 1, 1)
        # Create screenshot as CGImage
        image = CG.CGWindowListCreateImage(
        # Intermediate step, get pixel data as CGDataProvider
        prov = CG.CGImageGetDataProvider(image)
        # Copy data out of CGDataProvider, becomes string of bytes
        self._data = CG.CGDataProviderCopyData(prov)
        # Get width/height of image
        self.width = CG.CGImageGetWidth(image)
        self.height = CG.CGImageGetHeight(image)
    def pixel(self, x, y):
        """Get pixel value at given (x,y) screen coordinates
        Must call capture first.

        # Pixel data is unsigned char (8bit unsigned integer),
        # and there are four (blue,green,red,alpha)
        data_format = "BBBB"
        # Calculate offset, based on
        # [crg]: removed this -- unnecessary step, just using zero
        #offset = 4 * ((self.width*int(round(y))) + int(round(x)))
        # Unpack data from string into Python'y integers
        b, g, r, a = struct.unpack_from(data_format, self._data, offset=0)
        # Return BGRA as RGBA
        return (r, g, b)
        #can (used to) return alpha, too, but in this context, unnecessary
if __name__ == '__main__':