最近在稍微做一些整理,翻起这部分的代码,发现是两个多月前的了。
这里讨论的是基于RGBA模型下的图像处理,即将变换作用在每个像素上。
代码是以UIImage的category形式存在的:
typedef struct _singleRGBA { unsigned char red; unsigned char green; unsigned char blue; unsigned char alpha; } RGBA; @interface UIImage (ImageFilter)
- (UIImage*)applyFilter:(FilterFunction)filter context:(void*)context { CGImageRef inImage = self.CGImage; CFDataRef m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage)); UInt8 *m_PixelBuf = (UInt8 *)CFDataGetBytePtr(m_DataRef); int length = CFDataGetLength(m_DataRef); for (int i=0; i<length; i+=4) { filter(m_PixelBuf, i, context); } CGContextRef ctx = CGBitmapContextCreate(m_PixelBuf, CGImageGetWidth(inImage), CGImageGetHeight(inImage), CGImageGetBitsPerComponent(inImage), CGImageGetBytesPerRow(inImage), CGImageGetColorSpace(inImage), CGImageGetBitmapInfo(inImage) ); CGImageRef imageRef = CGBitmapContextCreateImage(ctx); CGContextRelease(ctx); UIImage *finalImage = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); CFRelease(m_DataRef); return finalImage; }
typedef void (*FilterFunction)(UInt8 *pixelBuf, UInt32 offset, void *context);
在此基础上,我们可以把每个变换操作独立出来,比如调整亮度、对比度、色调、透明度等:
void filterOpacity(UInt8 *pixelBuf, UInt32 offset, void *context) { double val = *((double*)context); int a = offset+3; int alpha = pixelBuf[a]; pixelBuf[a] = SAFECOLOR(alpha * val); } void filterBrightness(UInt8 *pixelBuf, UInt32 offset, void *context) { double t = *((double*)context); int r = offset; int g = offset+1; int b = offset+2; int red = pixelBuf[r]; int green = pixelBuf[g]; int blue = pixelBuf[b]; pixelBuf[r] = SAFECOLOR(red * t); pixelBuf[g] = SAFECOLOR(green * t); pixelBuf[b] = SAFECOLOR(blue * t); } void filterSaturation(UInt8 *pixelBuf, UInt32 offset, void *context) { double t = *((double*)context); // t (- [0, 2] int r = offset; int g = offset+1; int b = offset+2; int red = pixelBuf[r]; int green = pixelBuf[g]; int blue = pixelBuf[b]; red = red * (0.3086 * (1-t) + t) + green * (0.6094 * (1-t)) + blue * (0.0820 * (1-t)); green = red * (0.3086 * (1-t)) + green * ((0.6094 * (1-t)) + t) + blue * (0.0820 * (1-t)); blue = red * (0.3086 * (1-t)) + green * (0.6094 * (1-t)) + blue * ((0.0820 * (1-t)) + t); pixelBuf[r] = SAFECOLOR(red); pixelBuf[g] = SAFECOLOR(green); pixelBuf[b] = SAFECOLOR(blue); } void filterContrast(UInt8 *pixelBuf, UInt32 offset, void *context) { double t = *((double*)context); // t (- [0, 10] int r = offset; int g = offset+1; int b = offset+2; int red = pixelBuf[r]; int green = pixelBuf[g]; int blue = pixelBuf[b]; red = red * t + 128 * (1-t); green = green * t + 128 * (1-t); blue = blue * t + 128 * (1-t); pixelBuf[r] = SAFECOLOR(red); pixelBuf[g] = SAFECOLOR(green); pixelBuf[b] = SAFECOLOR(blue); } void filterPosterize(UInt8 *pixelBuf, UInt32 offset, void *context) { double levels = *((double*)context); if (levels == 0) levels = 1; // avoid divide by zero int step = 255 / levels; int r = offset; int g = offset+1; int b = offset+2; int red = pixelBuf[r]; int green = pixelBuf[g]; int blue = pixelBuf[b]; pixelBuf[r] = SAFECOLOR((red / step) * step); pixelBuf[g] = SAFECOLOR((green / step) * step); pixelBuf[b] = SAFECOLOR((blue / step) * step); } void filterDesaturate(UInt8 *pixelBuf, UInt32 offset, void *context) { int r = offset; int g = offset+1; int b = offset+2; int red = pixelBuf[r]; int green = pixelBuf[g]; int blue = pixelBuf[b]; red = red * 0.3086 + green * 0.6094 + blue * 0.0820; green = red * 0.3086 + green * 0.6094 + blue * 0.0820; blue = red * 0.3086 + green * 0.6094 + blue * 0.0820; pixelBuf[r] = SAFECOLOR(red); pixelBuf[g] = SAFECOLOR(green); pixelBuf[b] = SAFECOLOR(blue); } void filterInvert(UInt8 *pixelBuf, UInt32 offset, void *context) { int r = offset; int g = offset+1; int b = offset+2; int red = pixelBuf[r]; int green = pixelBuf[g]; int blue = pixelBuf[b]; pixelBuf[r] = SAFECOLOR(255-red); pixelBuf[g] = SAFECOLOR(255-green); pixelBuf[b] = SAFECOLOR(255-blue); } void filterTint(UInt8 *pixelBuf, UInt32 offset, void *context) { RGBA *rgbaArray = (RGBA*)context; RGBA maxRGBA = rgbaArray[0]; RGBA minRGBA = rgbaArray[1]; int r = offset; int g = offset+1; int b = offset+2; int red = pixelBuf[r]; int green = pixelBuf[g]; int blue = pixelBuf[b]; pixelBuf[r] = SAFECOLOR((red - minRGBA.red) * (255.0 / (maxRGBA.red - minRGBA.red))); pixelBuf[g] = SAFECOLOR((green - minRGBA.green) * (255.0 / (maxRGBA.green - minRGBA.green))); pixelBuf[b] = SAFECOLOR((blue - minRGBA.blue) * (255.0 / (maxRGBA.blue - minRGBA.blue))); }
其中SAFECOLOR宏如下:
#define SAFECOLOR(color) MIN(255,MAX(0,color))
最后,拿一张帅气的Andy照片来实践下,希望没有侵犯到肖像权。
原图如下:
通过以下四种变换,可以分别得到四张处理过的图片:
return [originImage changeOpacityByFactor:0.5];
return [originImage changeBrightnessByFactor:1.2];
return [originImage changeSaturationByFactor:2.0];
return [originImage tintWithMaxRGBA:(RGBA){190, 190, 230} minRGBA:(RGBA){50, 35, 10}];