Showing posts with label Quartz.CoreGraphics. Show all posts
Showing posts with label Quartz.CoreGraphics. Show all posts

Saturday, April 20, 2013

Python Script for getting pixel color on screen in OSX

This post on stackoverflow: http://stackoverflow.com/questions/12978846/python-get-screen-pixel-value-in-os-x, and this blog post: http://neverfear.org/blog/view/156/OS_X_Screen_capture_from_Python_PyObjC 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):

#!/usr/bin/python
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]
        try:
            global x
            x = int(argx)
            global y
            y = int(argy)
        except ValueError:
            print "Error! Enter two integers as arguments."
            #print x
            #print y
        else:
            sp = ScreenPixel()
            sp.capture()
            print sp.pixel(0, 0)
    else:
        print "Error! Script requires two integers as arguments."

class ScreenPixel(object):
    """Captures the screen using CoreGraphics, and provides access to
    the pixel values.
    [crg:]
    ... pass two arguments to script (no comma, no nuthin', a la:
    ./thisScript.py 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(
            region,
            CG.kCGWindowListOptionOnScreenOnly,
            CG.kCGNullWindowID,
            CG.kCGWindowImageDefault)
 
        # 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
        # http://www.markj.net/iphone-uiimage-pixel-color/
        
        # [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__':
    main()