Skip to content

Instantly share code, notes, and snippets.

@fjolnir
Last active December 20, 2015 19:19
Show Gist options
  • Save fjolnir/6182728 to your computer and use it in GitHub Desktop.
Save fjolnir/6182728 to your computer and use it in GitHub Desktop.

output (Please click the image to see it unscaled)

@implementation UIImage (CYDithering)
struct _Pixel {
uint8_t b, g, r, a;
};
#define Pixel struct _Pixel
#define PixelAt(x,y) ((Pixel *)(pixels + 4*(width*(y) + (x))))
// Assumes grayscale
#define AddToNeighbour(xOfs, yOfs, val) do { \
Pixel * const px = PixelAt(CLAMP(x+(xOfs), 0, width-1), \
CLAMP(y+(yOfs), 0, height-1)); \
memset(px, CLAMP(px->r + (val), 0, 255), 3); \
} while(0)
- (UIImage *)imageByConvertingToBlackAndWhite
{
CGSize const size = CGSizeApplyAffineTransform(self.size, CGAffineTransformMakeScale(self.scale, self.scale));
UIGraphicsBeginImageContextWithOptions(size, YES, 1);
CGContextRef const ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -size.height);
CGContextDrawImage(ctx, (CGRect){ CGPointZero, size }, self.CGImage);
CGContextRestoreGState(ctx);
uint8_t * const pixels = CGBitmapContextGetData(ctx);
size_t const width = size.width;
size_t const height = size.height;
// Start by converting the image to grayscale
for(uint32_t y = 0; y < size.height; ++y) {
for(uint32_t x = 0; x < size.width; ++x) {
Pixel * const px = PixelAt(x,y);
memset(px, MIN(1.25f * (0.3f*px->r + 0.59f*px->g + 0.11f*px->b), 255), 3);
px->a = 255;
}
}
// Convert to black&white while applying dithering
for(uint32_t y = 0; y < size.height; ++y) {
for(uint32_t x = 0; x < size.width; ++x) {
uint8_t const luma = PixelAt(x, y)->r; // All comps are now the same
uint8_t const mono = luma > 127 ? 255 : 0;
int8_t const error = (luma - mono) / 8;
AddToNeighbour( 1, 0, error);
AddToNeighbour( 2, 0, error);
AddToNeighbour(-1, 1, error);
AddToNeighbour( 0, 1, error);
AddToNeighbour( 1, 1, error);
AddToNeighbour( 0, 2, error);
memset(PixelAt(x, y), mono, 3);
}
}
UIImage * const result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
#undef Pixel
#undef PixelAt
#undef AddToNeighbour
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment