Skip to content

Instantly share code, notes, and snippets.

@robertmryan
Last active May 24, 2021 08:28
Show Gist options
  • Save robertmryan/b89cf29a4b4e69abb02fcfd6640bef51 to your computer and use it in GitHub Desktop.
Save robertmryan/b89cf29a4b4e69abb02fcfd6640bef51 to your computer and use it in GitHub Desktop.
Objective-C rendition of pixel processing found in http://stackoverflow.com/a/31661519/1271826
- (void)viewDidLoad {
[super viewDidLoad];
UIImage *image = [UIImage imageNamed:@"test.png"];
self.imageView.image = [self blackAndWhiteFromImage:image];
}
- (UIImage * _Nullable)makeBlackPixelsRedInImage:(UIImage *)image {
UInt32 black = [self pixelFromRed:0 green:0 blue:0 alpha:255];
UInt32 red = [self pixelFromRed:255 green:0 blue:0 alpha:255];
return [self processPixelsInImage:image processor:^(UInt32 pixel) {
return pixel == black ? red : pixel;
}];
}
- (UIImage * _Nullable)blackAndWhiteFromImage:(UIImage *)image {
return [self processPixelsInImage:image processor:^(UInt32 pixel) {
UInt8 red = [self redFromPixel:pixel];
UInt8 green = [self greenFromPixel:pixel];
UInt8 blue = [self blueFromPixel:pixel];
UInt8 alpha = [self alphaFromPixel:pixel];
UInt8 luminance = (UInt8)(0.2126 * red + 0.7152 * green + 0.0722 * blue);
return [self pixelFromRed:luminance green:luminance blue:luminance alpha:alpha];
}];
}
- (UIImage * _Nullable)processPixelsInImage:(UIImage *)inputImage processor:(UInt32 (^)(UInt32))processor {
CGImageRef inputCGImage = inputImage.CGImage;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
size_t width = CGImageGetWidth(inputCGImage);
size_t height = CGImageGetHeight(inputCGImage);
NSInteger bytesPerPixel = 4;
NSInteger bitsPerComponent = 8;
NSInteger bytesPerRow = bytesPerPixel * width;
uint32_t bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Little;
CGContextRef context = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
if (context == nil) {
return nil;
}
CGContextDrawImage(context, CGRectMake(0, 0, width, height), inputCGImage);
UInt32 *pixelBuffer = CGBitmapContextGetData(context);
for (NSInteger row = 0; row < height; row++) {
for (NSInteger col = 0; col < width; col++) {
pixelBuffer[row * width + col] = processor(pixelBuffer[row * width + col]);
}
}
CGImageRef outputCGImage = CGBitmapContextCreateImage(context);
UIImage *outputImage = [UIImage imageWithCGImage:outputCGImage scale:inputImage.scale orientation:inputImage.imageOrientation];
CGImageRelease(outputCGImage);
CGContextRelease(context);
return outputImage;
}
- (UInt8)redFromPixel:(UInt32)pixel {
return (UInt8)((pixel >> 24) & 255);
}
- (UInt8)greenFromPixel:(UInt32)pixel {
return (UInt8)((pixel >> 16) & 255);
}
- (UInt8)blueFromPixel:(UInt32)pixel {
return (UInt8)((pixel >> 8) & 255);
}
- (UInt8)alphaFromPixel:(UInt32)pixel {
return (UInt8)(pixel & 255);
}
- (UInt32)pixelFromRed:(UInt8)red green:(UInt8)green blue:(UInt8)blue alpha:(UInt8)alpha {
return ((UInt32)red << 24) | ((UInt32)green << 16) | ((UInt32)blue << 8) | ((UInt32)alpha << 0);
}
@end
@Rj707
Copy link

Rj707 commented May 24, 2021

@robertmryan it does take some time due to the nested loop over rows and columns or width and height. I am posting the android code here playing with Bitmap, which is working fine with only one loop, and is fast as well.

@Rj707
Copy link

Rj707 commented May 24, 2021

`fun replaceColor(backgroundImage: Bitmap?, foregroundImage: Bitmap?, fromColor: Int, targetColor: Int): Bitmap?
{
if (backgroundImage == null || foregroundImage == null)
{
return null
}
// Source image size
var width = backgroundImage.width
var height = backgroundImage.height

    var destWidth = foregroundImage.width
    var destHeight = foregroundImage.height

    var destPixels = IntArray(destWidth * destHeight)
    var pixels = IntArray(width * height)
    //get pixels
    backgroundImage.getPixels(pixels, 0, width, 0, 0, width, height)
    foregroundImage.getPixels(destPixels, 0, destWidth, 0, 0, destWidth, destHeight)

    for (x in pixels.indices)
    {
        destPixels[x] = if (pixels[x] == fromColor) targetColor else destPixels[x]
    }
    // create result bitmap output
    var result = Bitmap.createBitmap(destWidth, destHeight, foregroundImage.config)
    //set pixels
    result.setPixels(destPixels, 0, destWidth, 0, 0, destWidth, destHeight)
    return result
}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment