Search code examples
objective-cmacosxcode4core-graphicsscreenshot

Partial screen capture in Objective C


I have been trying to figure out how to create an OS X routine in objective C that:

  • run in the background (separate thread) and

  • repeatedly (timed or when certain criteria are met) captures several defined subsets of a specified window/screen (i.e. without user interaction) and

  • save the images into a specified path.

Similar the output of a "pre-programmed loop of cmd-shift-4 + mouseDown-drag".

Neither SonofGrab nor ScreenSnapshot from Mac Developer Library seem to indicate how this could be done, but I suspect CGImageRef is one/the(?) way to go about it.

  1. Does anyone know how to do it?

  2. Are there other possible ways besides CGImageRef to solve this problem? Could it for example be done via command-line tools and NSTask?

  3. If so, what are the advantages/disadvantages with the different methods in terms of speed and complexity?


Solution

  • Assuming you have the logic required to do a screengrab (which you can see in SonOfGrab), you just use a dispatch queue or a timer to do the job.

    void MyTakeScreengrab();
    
    dispatch_queue_t  queue    = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,  0);
    
    dispatch_source_t timerSrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0,queue);
    
    dispatch_source_set_timer(timerSrc, 
          dispatch_time(DISPATCH_TIME_NOW,0) /* start on */,
          SECONDS_PER_GRAB * NSEC_PER_SEC /* interval */, 
          NSEC_PER_SEC /* leeway */);
    
    dispatch_source_set_event_handler_f(timerSrc, MyTakeScreengrab);
    
    dispatch_resume(timerSrc);
    

    You can use an NSTimer as well.

    -(void)setup {
        _timer = [[NSTimer scheduledTimerWithTimeInterval: (NSTimerInterval)SECONDS_PER_GRAB 
                target: self 
                selector: @selector(takeScreegrabOnBGThread:) 
                userInfo: @{ @"folderPath" : MyFolderPath(), 
                             @"imageSettings" : MYCGImageSettings() }  
                repeats: YES];
        [_timer fire];
    }
    
    -(void)takeScreengrabOnBGThread:(id)userInfo {
        [self performSelectorInBackground:@selector(takeScreengrabBlocking:) 
                withObject:userInfo];
    }
    
    -(void)takeScreengrabBlocking:(id)userInfo {
    
        MyTakeScreengab(userInfo);
    }
    

    To use the terminal to do this, the command you're looking for is screencapture(1).