I find myself often wanting to experiment with images from papers I'm reading. To load the image into matlab properly I should extract it from the pdf, save it in a file and load the file via matlab. Often I skip the first step and just take a screengrab. But I still need to create a dummy file just to load it into matlab.
Here's a mex function to load images directly from the clipboard. It even maintains all color channels (RGB, CMYK, RGBA, etc.)
Save this in a file paste.h
:
#include <cstddef>
// Get image from clipboard as an RGB image
//
// Outputs:
// IM h*w*c list of rgb pixel color values as uint8, running over height,
// then width, then rgb channels
// h height
// w width
// c channels
bool paste(unsigned char *& IM,size_t & h, size_t & w, size_t & c);
and in paste.mm
:
#import "paste.h"
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import <unistd.h>
bool paste(unsigned char *& IM,size_t & h, size_t & w, size_t & c)
{
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSArray *classArray = [NSArray arrayWithObject:[NSImage class]];
NSDictionary *options = [NSDictionary dictionary];
BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options];
if(!ok)
{
//printf("Error: clipboard doesn't seem to contain image...");
return false;
}
NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
NSImage *image = [objectsToPaste objectAtIndex:0];
NSBitmapImageRep* bitmap = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
// http://stackoverflow.com/a/19649616/148668
w = [bitmap pixelsWide];
h = [bitmap pixelsHigh];
size_t rowBytes = [bitmap bytesPerRow];
c = rowBytes/w;
unsigned char* pixels = [bitmap bitmapData];
IM = new unsigned char[w*h*c];
for(size_t y = 0; y < h ; y++)
{
for(size_t x = 0; x < w; x++)
{
for(size_t d = 0;d<c;d++)
{
// For some reason colors are invertex
IM[y+h*(x+d*w)] = pixels[y*rowBytes + x*c + d];
}
}
}
[image release];
return true;
}
and in impaste.cpp
#ifdef MEX
#include <mex.h>
#include "paste.h"
#include <iostream>
void mexFunction(
int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
unsigned char * IM;
size_t h,w,c;
if(!paste(IM,h,w,c))
{
mexErrMsgTxt("Clipboard doesn't contain image.");
}
switch(nlhs)
{
default:
{
mexErrMsgTxt("Too many output parameters.");
}
case 1:
{
size_t dims[] = {h,w,c};
plhs[0] = mxCreateNumericArray(3,dims,mxUINT8_CLASS,mxREAL);
unsigned char * IMp = (unsigned char *)mxGetData(plhs[0]);
std::copy(IM,IM+w*h*c,IMp);
// Fall through
}
case 0: break;
}
}
#endif
Then compile on Mac OS X using something like:
mex -v -largeArrayDims -DMEX CXX='/usr/bin/clang++' LD='/usr/bin/clang++' LDOPTIMFLAGS='-O ' LDFLAGS='\$LDFLAGS -framework Foundation -framework AppKit' -o impaste impaste.cpp paste.mm
Notice, I'm forcing the mex compiler to use clang and include the relevant frameworks.
Then you can call from matlab using something like:
IM = impaste();
or
imshow(impaste());