public
Last active

How to take a screenshot on OS X using the Racket FFI

  • Download Gist
screenshot.rkt
Racket
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
#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
ffi/unsafe
ffi/unsafe/objc
ffi/unsafe/atomic
mred/private/wx/cocoa/image
mred/private/wx/cocoa/types)
 
(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)
(CGMainDisplayID))
 
; 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%
(image->bitmap
(cgimage->nsimage
(cgimage-screenshot
(main-display-id)))))
 
(screenshot)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.