Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
How to take a screenshot on OS X using the Racket FFI
#lang racket
;;; How to take a screenshot on OS X
;;; -- Jens Axel Søgaard
;;; This gist illustrates how to work with OS X
;;; system calls in order to take a screen shot.
(require racket/draw
(import-class NSImage)
; The function CGDisplayCreateImage provided by the Quartz framework,
; will take a screenshot and produce an CGImage.
(define quartz-lib (ffi-lib "/System/Library/Frameworks/Quartz.framework/Versions/Current/Quartz"))
; Each display attached to the computer has a DisplayID.
; We need the id of the display, we want to take a screenshot of.
; In most cases we want a screenshot of the main display.
; An id is represented as an unsigned 32 bit integer.
(define CGMainDisplayID
(get-ffi-obj "CGMainDisplayID" quartz-lib (_fun -> _uint32)
(lambda () (error 'quartz-lib "CGMainDisplayID not found"))))
(define (main-display-id)
; If we need to make screenshots of the other displays,
; we need first to get hold of the ids of the active displays.
(define CGGetActiveDisplayList
(get-ffi-obj "CGGetActiveDisplayList" quartz-lib
(_fun _uint32 (_or-null _pointer) _pointer -> _int32)
(lambda () (error 'quartz-lib "CGGetActiveDisplayList not found"))))
(define (number-of-active-displays)
; passing NULL as activeDspys will store
; the number of active displays in d
(define d (malloc _uint32))
(CGGetActiveDisplayList 0 #f d)
(ptr-ref d _uint32 0))
(define (get-active-display-ids)
; get the number of active displays
(define n (number-of-active-displays))
(define d (malloc _uint32))
; prepreare an array to hold the display ids
(define displays (malloc (* n 4)))
(memset displays 0 (* n 4))
(CGGetActiveDisplayList n displays d)
; return the display ids as a list
(for/list ([i (in-range n)])
(ptr-ref displays _uint32 i)))
; The screenshot function returns a pointer to an CGImage:
; typedef struct CGImage *CGImageRef;
(define _CGImageRef (_cpointer 'CGImageRef))
; The screenshot function:
; CGImageRef CGDisplayCreateImage( CGDirectDisplayID displayID );
(define CGDisplayCreateImage
(get-ffi-obj "CGDisplayCreateImage" quartz-lib
(_fun _uint32 -> _CGImageRef)))
(define (cgimage-screenshot display-id)
; take a screenshot of the display with the given id
(CGDisplayCreateImage display-id))
(define (cgimage->nsimage cgimage)
; convert the CGimage to a NSImage
(tell (tell NSImage alloc)
initWithCGImage: #:type _CGImageRef cgimage
size: #:type _NSSize (make-NSSize 0 0)))
(define (screenshot [display-id (main-display-id)])
; take a screenshot and convert it into a bitmap%

Just out of curiosity, how to capture screenshots in Windows?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment