Created
October 8, 2014 18:55
-
-
Save jonathan-beebe/42309ac638466c73ba24 to your computer and use it in GitHub Desktop.
UIImage category for inverting the image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Retina-ready version of this StackOverflow answer | |
// http://stackoverflow.com/a/6672628/123781 | |
#import <UIKit/UIKit.h> | |
@interface UIImage (NegativeImage) | |
- (UIImage *)negativeImage; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Retina-ready version of this StackOverflow answer | |
// http://stackoverflow.com/a/6672628/123781 | |
#import "UIImage+NegativeImage.h" | |
@implementation UIImage (NegativeImage) | |
- (UIImage *)negativeImage | |
{ | |
// get width and height as integers, since we'll be using them as | |
// array subscripts, etc, and this'll save a whole lot of casting | |
CGSize size = self.size; | |
int width = size.width * self.scale; | |
int height = size.height * self.scale; | |
// Create a suitable RGB+alpha bitmap context in BGRA colour space | |
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); | |
unsigned char *memoryPool = (unsigned char *)calloc(width*height*4, 1); | |
CGContextRef context = CGBitmapContextCreate(memoryPool, width, height, 8, width * 4, colourSpace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast); | |
CGColorSpaceRelease(colourSpace); | |
// draw the current image to the newly created context | |
CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]); | |
// run through every pixel, a scan line at a time... | |
for(int y = 0; y < height; y++) | |
{ | |
// get a pointer to the start of this scan line | |
unsigned char *linePointer = &memoryPool[y * width * 4]; | |
// step through the pixels one by one... | |
for(int x = 0; x < width; x++) | |
{ | |
// get RGB values. We're dealing with premultiplied alpha | |
// here, so we need to divide by the alpha channel (if it | |
// isn't zero, of course) to get uninflected RGB. We | |
// multiply by 255 to keep precision while still using | |
// integers | |
int r, g, b; | |
if(linePointer[3]) | |
{ | |
r = linePointer[0] * 255 / linePointer[3]; | |
g = linePointer[1] * 255 / linePointer[3]; | |
b = linePointer[2] * 255 / linePointer[3]; | |
} | |
else | |
{ | |
r = g = b = 0; | |
} | |
// perform the colour inversion | |
r = 255 - r; | |
g = 255 - g; | |
b = 255 - b; | |
// multiply by alpha again, divide by 255 to undo the | |
// scaling before, store the new values and advance | |
// the pointer we're reading pixel data from | |
linePointer[0] = r * linePointer[3] / 255; | |
linePointer[1] = g * linePointer[3] / 255; | |
linePointer[2] = b * linePointer[3] / 255; | |
linePointer += 4; | |
} | |
} | |
// get a CG image from the context, wrap that into a | |
// UIImage | |
CGImageRef cgImage = CGBitmapContextCreateImage(context); | |
UIImage *returnImage = [UIImage imageWithCGImage:cgImage scale:self.scale orientation:self.imageOrientation]; | |
// clean up | |
CGImageRelease(cgImage); | |
CGContextRelease(context); | |
free(memoryPool); | |
// and return | |
return returnImage; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment