UIImage categories (part 2 of 4)

Here is the second category, where I take the UIImage with the clear background and crop it down. The algorithm is a bit brute force, but it seems to work fine.

- (UIImage *)imageByTrimmingTransparentPixels
{
	int rows = self.size.height;
	int cols = self.size.width;
	int bytesPerRow = cols*sizeof(uint8_t);
 
	if ( rows < 2 || cols < 2 ) {
		return self;
	}
 
	//allocate array to hold alpha channel
	uint8_t *bitmapData = calloc(rows*cols, sizeof(uint8_t));
 
	//create alpha-only bitmap context
	CGContextRef contextRef = CGBitmapContextCreate(bitmapData, cols, rows, 8, bytesPerRow, NULL, kCGImageAlphaOnly);
 
	//draw our image on that context
	CGImageRef cgImage = self.CGImage;
	CGRect rect = CGRectMake(0, 0, cols, rows);
	CGContextDrawImage(contextRef, rect, cgImage);
 
	//summ all non-transparent pixels in every row and every column
	uint16_t *rowSum = calloc(rows, sizeof(uint16_t));
	uint16_t *colSum = calloc(cols, sizeof(uint16_t));
 
	//enumerate through all pixels
	for ( int row = 0; row < rows; row++) {
		for ( int col = 0; col < cols; col++)
		{
			if ( bitmapData[row*bytesPerRow + col] ) { //found non-transparent pixel
				rowSum[row]++;
				colSum[col]++;
			}
		}
	}
 
	//initialize crop insets and enumerate cols/rows arrays until we find non-empty columns or row
	UIEdgeInsets crop = UIEdgeInsetsMake(0, 0, 0, 0);
 
	for ( int i = 0; i<rows; i++ ) { 		//top
		if ( rowSum[i] > 0 ) {
			crop.top = i; break;
		}
	}
 
	for ( int i = rows; i >= 0; i-- ) {		//bottom
		if ( rowSum[i] > 0 ) {
			crop.bottom = MAX(0, rows-i-1); break;
		}
	}
 
	for ( int i = 0; i<cols; i++ ) {		//left
		if ( colSum[i] > 0 ) {
			crop.left = i; break;
		}
	}
 
	for ( int i = cols; i >= 0; i-- ) {		//right
		if ( colSum[i] > 0 ) {
			crop.right = MAX(0, cols-i-1); break;
		}
	}
 
	free(bitmapData);
	free(colSum);
	free(rowSum);
 
	if ( crop.top == 0 && crop.bottom == 0 && crop.left == 0 && crop.right == 0 ) {
		//no cropping needed
		return self;
	}
	else {
		//calculate new crop bounds
		rect.origin.x += crop.left;
		rect.origin.y += crop.top;
		rect.size.width -= crop.left + crop.right;
		rect.size.height -= crop.top + crop.bottom;
 
		//crop it
		CGImageRef newImage = CGImageCreateWithImageInRect(cgImage, rect);
 
		//convert back to UIImage
		return [UIImage imageWithCGImage:newImage];
	}
}

Again, I would attribute this code if I could, but one of my former co-workers found this for me on some pastebin. If anyone knows where this code originally came from, please let me know and I will make the necessary attribution.

BTW, Happy Birthday today to Mr. T. (Yes, May 21 is slim pickings for birthdays, deaths, events, and holidays.)

Leave a Reply