Skip to content

Instantly share code, notes, and snippets.

@soegaard
Created December 2, 2012 16:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soegaard/4189510 to your computer and use it in GitHub Desktop.
Save soegaard/4189510 to your computer and use it in GitHub Desktop.
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
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)
@yzgyyang
Copy link

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