Skip to content

Instantly share code, notes, and snippets.

@randomsequence
Created April 24, 2014 13:57
Show Gist options
  • Save randomsequence/11255547 to your computer and use it in GitHub Desktop.
Save randomsequence/11255547 to your computer and use it in GitHub Desktop.
UIImage - Mirror every other row & every other column. This produces an image with the same histogram as the source.
//
// UIImage+Scramble.m
//
// Created by Johnnie Walker on 24/04/2014.
//
#import "UIImage+Scramble.h"
@import Accelerate;
typedef u_int8_t Quantum;
typedef struct {
Quantum opacity, red, green, blue;
} PixelPacket;
CGContextRef bitmapContextFromImage(UIImage *image) {
CGSize size = CGSizeApplyAffineTransform(image.size, CGAffineTransformMakeScale(image.scale, image.scale));
size_t width = (size_t) ceil(size.width);
size_t height = (size_t) ceil(size.height);
size_t rowBytes = (size_t) ceil(size.width) * 4 * sizeof(uint8_t);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL,
width,
height,
8,
rowBytes,
colorSpace,
(CGBitmapInfo) kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), image.CGImage);
return context;
}
typedef void (^PixelProcessor)(void *inputPixels, void *outputPixels, size_t width, size_t height, size_t rowBytes);
@implementation UIImage (Scramble)
- (UIImage *)processWithBlocks:(NSArray *)pixelProcessors {
CGContextRef inputContext = bitmapContextFromImage(self);
CGContextRef outputContext = bitmapContextFromImage(self);
size_t width = CGBitmapContextGetWidth(inputContext);
size_t height = CGBitmapContextGetHeight(inputContext);
size_t rowBytes = CGBitmapContextGetBytesPerRow(inputContext);
for (PixelProcessor pixelProcessor in pixelProcessors) {
CGContextRef tmp = inputContext;
inputContext = outputContext;
outputContext = tmp;
void *inputPixels = CGBitmapContextGetData(inputContext);
void *outputPixels = CGBitmapContextGetData(outputContext);
memcpy(outputPixels, inputPixels, height*rowBytes);
pixelProcessor(inputPixels, outputPixels, width, height, rowBytes);
}
CGContextRelease(inputContext);
CGImageRef imageRef = CGBitmapContextCreateImage(outputContext);
UIImage *processed = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
CGImageRelease(imageRef);
CGContextRelease(outputContext);
return processed;
}
- (PixelProcessor)horizontalReflectProcessor:(size_t)lineSpacing {
NSParameterAssert(lineSpacing > 0);
PixelProcessor pixelProcessor = ^(void *inputPixels, void *outputPixels, size_t width, size_t height, size_t rowBytes) {
vImage_Buffer src;
src.width = width;
src.height = 1;
src.rowBytes = rowBytes;
vImage_Buffer dest;
dest.width = width;
dest.height = 1;
dest.rowBytes = rowBytes;
for (size_t y = 0; y < height; y += lineSpacing) {
src.data = inputPixels + (rowBytes * y);
dest.data = outputPixels + (rowBytes * y);
vImageHorizontalReflect_ARGB8888(&src, &dest, 0);
}
};
return [pixelProcessor copy];
}
- (PixelProcessor)verticalReflectProcessor:(size_t)columnSpacing {
NSParameterAssert(columnSpacing > 0);
PixelProcessor pixelProcessor = ^(void *inputPixels, void *outputPixels, size_t width, size_t height, size_t rowBytes) {
vImage_Buffer src;
src.width = 1;
src.height = height;
src.rowBytes = rowBytes;
vImage_Buffer dest;
dest.width = 1;
dest.height = height;
dest.rowBytes = rowBytes;
for (size_t x = 0; x < width; x += columnSpacing) {
src.data = inputPixels + (x * 4);
dest.data = outputPixels + (x * 4);
vImageVerticalReflect_ARGB8888(&src, &dest, 0);
}
};
return [pixelProcessor copy];
}
- (UIImage *)scrambledImage {
return [self processWithBlocks:@[
[self horizontalReflectProcessor:2],
[self verticalReflectProcessor:2],
]];
}
- (UIImage *)unscrambledImage {
return [self processWithBlocks:@[
[self verticalReflectProcessor:2],
[self horizontalReflectProcessor:2],
]];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment