I have created a function in C on OSX in Xcode which captures the screen, adds the mouse pointer to the image, rescales the image to fit a certain width X height requirement, and puts the rescaled image in a "bounding box", and finally converts the image from RGBA to RGB.
Is there a kind and experienced OSX developer out there who could review the code and tell me what I should change to make it execute faster?
But most importantly, I'm interested in hearing if I overlooked something and calling the function is generating memory leaks.
The code is here:
void screenCapture(void)
{
int rc;
NSRect e;
int H;
int W;
CGRect rect;
CGImageRef image;
float screenshotWidth;
float screenshotHeight;
float requestedWidth;
float requestedHeight;
NSPoint mouseLoc;
NSImage *overlay;
NSPoint offset;
int x;
int y;
int w;
int h;
int org_x;
int org_y;
size_t height;
size_t width;
size_t bytesPerRow;
unsigned int * imgData;
CGRect bgBoundingBox;
CGContextRef context;
CGImageRef imageWithMousePointer;
CGImageRef imageWithMousePointerRescaled;
CGImageRef imageWithMousePointerRescaledInBox;
CFDataRef rawData;
float wscale;
float hscale;
float scale;
float newWidth;
float newHeight;
float rescaledWidth;
float rescaledHeight;
float origX;
float origY;
size_t boundingBoxWidth;
size_t boundingBoxHeight;
float imageWidth;
float imageHeight;
UInt8* buf;
unsigned long byteLen;
unsigned long bmpIdx;
void* bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
int n_width;
int n_height;
CGColorSpaceRef colorspace;
rc = 1;
e = [[NSScreen mainScreen] frame];
H = (int)e.size.height;
W = (int)e.size.width;
screenshotWidth = (float) W;
screenshotHeight = (float) H;
rect.size.height = H;
rect.size.width = W;
rect.origin.x = 0;
rect.origin.y = 0;
requestedWidth = 1280.0f;
requestedHeight = 720.0f;
/***************************** Screenshot *************************************/
image = CGWindowListCreateImage(rect, kCGWindowListOptionIncludingWindow|kCGWindowListOptionOnScreenBelowWindow, 0, kCGWindowImageDefault);
/***************************** Render cursor *************************************/
mouseLoc = [NSEvent mouseLocation];
overlay = [[[NSCursor arrowCursor] image] copy];
offset = [[NSCursor arrowCursor] hotSpot];
x = (int)mouseLoc.x;
y = (int)mouseLoc.y;
w = (int)[overlay size].width;
h = (int)[overlay size].height;
org_x = (x - w/2) - offset.x;
org_y = (y - h/2) - offset.y;
height = CGImageGetHeight(image);
width = CGImageGetWidth(image);
bytesPerRow = CGImageGetBytesPerRow(image);
imgData = (unsigned int*)malloc(height*bytesPerRow);
bgBoundingBox = CGRectMake (0, 0, width,height);
context = CGBitmapContextCreate(imgData, width, height, 8, bytesPerRow, CGImageGetColorSpace(image), CGImageGetBitmapInfo(image));
CGContextDrawImage(context,bgBoundingBox,image);
CGContextDrawImage(context,CGRectMake(0, 0, width,height),image);
CGContextDrawImage(context,CGRectMake(org_x, org_y, w,h),[overlay CGImageForProposedRect: NULL context: NULL hints: NULL] );
imageWithMousePointer = CGBitmapContextCreateImage(context);
CGContextRelease(context);
free(imgData);
/***************************** Rescale *************************************/
wscale = requestedWidth / screenshotWidth;
hscale = requestedHeight / screenshotHeight;
scale = hscale;
if (wscale < hscale) scale = wscale;
newWidth = ((float) CGImageGetWidth(imageWithMousePointer)) * scale;
newHeight = ((float) CGImageGetHeight(imageWithMousePointer)) * scale;
n_width = CGImageGetWidth(imageWithMousePointer) * scale;
n_height = CGImageGetHeight(imageWithMousePointer) * scale;
bitmapBytesPerRow = (n_width * 4);
bitmapByteCount = (bitmapBytesPerRow * n_height);
bitmapData = malloc( bitmapByteCount );
colorspace = CGImageGetColorSpace(imageWithMousePointer);
context = CGBitmapContextCreate (bitmapData,n_width,n_height,8,bitmapBytesPerRow, colorspace,kCGImageAlphaNoneSkipFirst);
//CGColorSpaceRelease(colorspace);
CGContextDrawImage(context, CGRectMake(0,0,n_width, n_height), imageWithMousePointer);
imageWithMousePointerRescaled = CGBitmapContextCreateImage(context);
CGContextRelease(context);
free(bitmapData);
origX = (requestedWidth - newWidth) / 2.0f;
origY = (requestedHeight - newHeight) / 2.0f;
/************** Insert in box ********************************/
boundingBoxWidth = (size_t) requestedWidth;
boundingBoxHeight = (size_t) requestedHeight;
bytesPerRow = boundingBoxWidth * (8 + 8 + 8 + 8) / 8;
imgData = (unsigned int*)malloc(boundingBoxHeight*bytesPerRow);
imageWidth = (float) CGImageGetWidth(imageWithMousePointerRescaled);
imageHeight = (float) CGImageGetHeight(imageWithMousePointerRescaled);
memset(imgData, 0, boundingBoxHeight*bytesPerRow);
context = CGBitmapContextCreate(imgData, boundingBoxWidth, boundingBoxHeight, 8, bytesPerRow, CGImageGetColorSpace(imageWithMousePointerRescaled), CGImageGetBitmapInfo(imageWithMousePointerRescaled));
CGContextDrawImage(context, CGRectMake(origX,origY,imageWidth, imageHeight), imageWithMousePointerRescaled);
imageWithMousePointerRescaledInBox = CGBitmapContextCreateImage(context);
CGContextRelease(context);
free(imgData);
/*********** Convert from RGBA to RGB **********/
rawData = CGDataProviderCopyData(CGImageGetDataProvider(imageWithMousePointerRescaledInBox));
buf = (UInt8*) CFDataGetBytePtr(rawData);
for (int x = 0; x < 1280; x++)
{
for (int v = 0; v < 720; v++)
{
int pixelStartIndex = (x + (v * 1280)) * 4;
int newPixelStartIndex = (x + (v * 1280)) * 3;
UInt8 R = buf[pixelStartIndex + 1];
UInt8 G = buf[pixelStartIndex + 2];
UInt8 B = buf[pixelStartIndex + 3];
bmpimg[newPixelStartIndex] = R;
bmpimg[newPixelStartIndex + 1] = G;
bmpimg[newPixelStartIndex + 2] = B;
}
}
}