http://blog.csdn.net/sqc3375177/article/details/8501564
今天重新看了一个巨人李海峰写的滤镜demo感觉非常的清晰易懂。
首先需要了解一下滤镜的原理:“用Core Graphic的API,把图片解析成RGBA四通道的位图放入内存,然后内存中有一个数组,数组中的每四个元素都是图像上的一个像素点的RGBA的数值(0-255),你只要改变RGB的数值,再写回去重新生成就可以了。简单的变化RGB很好改的,变为黑白照片就是把每个像素点的RGB的值相加求平均值,再回写回去。例如:R=B=G=100,就是灰色的,你只要写个for循环,把每个像素点的RGB都改成各自的平均值,照片就变为黑白色了。如果图像变为怀旧照片,就是底色发黄的,就是RG的比值调高,B保持不变,因为红绿相配就是黄色。”
第一步打开位图的像素数组
- // 返回一个使用RGBA通道的位图上下文
- static CGContextRef CreateRGBABitmapContext (CGImageRef inImage)
- {
- CGContextRef context = NULL;
- CGColorSpaceRef colorSpace;
- void *bitmapData; //内存空间的指针,该内存空间的大小等于图像使用RGB通道所占用的字节数。
- int bitmapByteCount;
- int bitmapBytesPerRow;
- size_t pixelsWide = CGImageGetWidth(inImage); //获取横向的像素点的个数
- size_t pixelsHigh = CGImageGetHeight(inImage);
- bitmapBytesPerRow = (pixelsWide * 4); //每一行的像素点占用的字节数,每个像素点的ARGB四个通道各占8个bit(0-255)的空间
- bitmapByteCount = (bitmapBytesPerRow * pixelsHigh); //计算整张图占用的字节数
- colorSpace = CGColorSpaceCreateDeviceRGB();//创建依赖于设备的RGB通道
- //分配足够容纳图片字节数的内存空间
- bitmapData = malloc( bitmapByteCount );
- //创建CoreGraphic的图形上下文,该上下文描述了bitmaData指向的内存空间需要绘制的图像的一些绘制参数
- context = CGBitmapContextCreate (bitmapData,
- pixelsWide,
- pixelsHigh,
- 8,
- bitmapBytesPerRow,
- colorSpace,
- kCGImageAlphaPremultipliedLast);
- //Core Foundation中通过含有Create、Alloc的方法名字创建的指针,需要使用CFRelease()函数释放
- CGColorSpaceRelease( colorSpace );
- return context;
- }
- // 返回一个指针,该指针指向一个数组,数组中的每四个元素都是图像上的一个像素点的RGBA的数值(0-255),用无符号的char是因为它正好的取值范围就是0-255
- static unsigned char *RequestImagePixelData(UIImage *inImage)
- {
- CGImageRef img = [inImage CGImage];
- CGSize size = [inImage size];
- //使用上面的函数创建上下文
- CGContextRef cgctx = CreateRGBABitmapContext(img);
- CGRect rect = {{0,0},{size.width, size.height}};
- //将目标图像绘制到指定的上下文,实际为上下文内的bitmapData。
- CGContextDrawImage(cgctx, rect, img);
- unsigned char *data = CGBitmapContextGetData (cgctx);
- //释放上面的函数创建的上下文
- CGContextRelease(cgctx);
- return data;
- }
获得以像素为单位的长和宽,开始处理位图中每个像素的值,生成指定效果
- CGImageRef inImageRef = [inImage CGImage];
- GLuint w = CGImageGetWidth(inImageRef);
- GLuint h = CGImageGetHeight(inImageRef);
- int wOff = 0;
- int pixOff = 0;
- //双层循环按照长宽的像素个数迭代每个像素点
- for(GLuint y = 0;y< h;y++)
- {
- pixOff = wOff;
- for (GLuint x = 0; x<w; x++)
- {
- int red = (unsigned char)imgPixel[pixOff];
- int green = (unsigned char)imgPixel[pixOff+1];
- int blue = (unsigned char)imgPixel[pixOff+2];
- int alpha=(unsigned char)imgPixel[pixOff+3];
- //NSLog(@"1------r=%d,g=%d,b=%d,a=%d,",red,green,blue,alpha);
- changeRGBA(&red, &green, &blue, &alpha, f);
- //NSLog(@"2------r=%d,g=%d,b=%d,a=%d,",red,green,blue,alpha);
- //NSLog(@"--------------------------------------");
- //回写数据
- imgPixel[pixOff] = red;
- imgPixel[pixOff+1] = green;
- imgPixel[pixOff+2] = blue;
- imgPixel[pixOff+3] = alpha;
- //将数组的索引指向下四个元素
- pixOff += 4;
- }
- wOff += w * 4;
- }
- NSInteger dataLength = w*h* 4;
创建生成image所需的参数
- //下面的代码创建要输出的图像的相关参数
- CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, imgPixel, dataLength, NULL);
- if (!provider) {
- failedBlock(@"创建输出图像的相关参数失败!");
- }else{
- // prep the ingredients
- int bitsPerComponent = 8;
- int bitsPerPixel = 32;
- int bytesPerRow = 4 * w;
- CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
- CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
- CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
- //创建要输出的图像
- CGImageRef imageRef = CGImageCreate(w, h,
- bitsPerComponent,
- bitsPerPixel,
- bytesPerRow,
- colorSpaceRef,
- bitmapInfo,
- provider,
- NULL, NO, renderingIntent);
- if (!imageRef) {
- failedBlock(@"创建输出图像失败!");
- }else{
- UIImage *my_Image = [UIImage imageWithCGImage:imageRef];
- CFRelease(imageRef);
- CGColorSpaceRelease(colorSpaceRef);
- CGDataProviderRelease(provider);
- succeedBlock(my_Image);
- }
下面附上几组原作者李海峰写的颜色矩阵的数值
- //ColorMatrix From Android
- //lomo
- const float colormatrix_lomo[] = {
- 1.7f, 0.1f, 0.1f, 0, -73.1f,
- 0, 1.7f, 0.1f, 0, -73.1f,
- 0, 0.1f, 1.6f, 0, -73.1f,
- 0, 0, 0, 1.0f, 0 };
- //黑白
- const float colormatrix_heibai[] = {
- 0.8f, 1.6f, 0.2f, 0, -163.9f,
- 0.8f, 1.6f, 0.2f, 0, -163.9f,
- 0.8f, 1.6f, 0.2f, 0, -163.9f,
- 0, 0, 0, 1.0f, 0 };
- //旧化
- const float colormatrix_huajiu[] = {
- 0.2f,0.5f, 0.1f, 0, 40.8f,
- 0.2f, 0.5f, 0.1f, 0, 40.8f,
- 0.2f,0.5f, 0.1f, 0, 40.8f,
- 0, 0, 0, 1, 0 };
- //哥特
- const float colormatrix_gete[] = {
- 1.9f,-0.3f, -0.2f, 0,-87.0f,
- -0.2f, 1.7f, -0.1f, 0, -87.0f,
- -0.1f,-0.6f, 2.0f, 0, -87.0f,
- 0, 0, 0, 1.0f, 0 };
- //锐色
- const float colormatrix_ruise[] = {
- 4.8f,-1.0f, -0.1f, 0,-388.4f,
- -0.5f,4.4f, -0.1f, 0,-388.4f,
- -0.5f,-1.0f, 5.2f, 0,-388.4f,
- 0, 0, 0, 1.0f, 0 };
- //淡雅
- const float colormatrix_danya[] = {
- 0.6f,0.3f, 0.1f, 0,73.3f,
- 0.2f,0.7f, 0.1f, 0,73.3f,
- 0.2f,0.3f, 0.4f, 0,73.3f,
- 0, 0, 0, 1.0f, 0 };
- //酒红
- const float colormatrix_jiuhong[] = {
- 1.2f,0.0f, 0.0f, 0.0f,0.0f,
- 0.0f,0.9f, 0.0f, 0.0f,0.0f,
- 0.0f,0.0f, 0.8f, 0.0f,0.0f,
- 0, 0, 0, 1.0f, 0 };
- //清宁
- const float colormatrix_qingning[] = {
- 0.9f, 0, 0, 0, 0,
- 0, 1.1f,0, 0, 0,
- 0, 0, 0.9f, 0, 0,
- 0, 0, 0, 1.0f, 0 };
- //浪漫
- const float colormatrix_langman[] = {
- 0.9f, 0, 0, 0, 63.0f,
- 0, 0.9f,0, 0, 63.0f,
- 0, 0, 0.9f, 0, 63.0f,
- 0, 0, 0, 1.0f, 0 };
- //光晕
- const float colormatrix_guangyun[] = {
- 0.9f, 0, 0, 0, 64.9f,
- 0, 0.9f,0, 0, 64.9f,
- 0, 0, 0.9f, 0, 64.9f,
- 0, 0, 0, 1.0f, 0 };
- //蓝调
- const float colormatrix_landiao[] = {
- 2.1f, -1.4f, 0.6f, 0.0f, -31.0f,
- -0.3f, 2.0f, -0.3f, 0.0f, -31.0f,
- -1.1f, -0.2f, 2.6f, 0.0f, -31.0f,
- 0.0f, 0.0f, 0.0f, 1.0f, 0.0f
- };
- //梦幻
- const float colormatrix_menghuan[] = {
- 0.8f, 0.3f, 0.1f, 0.0f, 46.5f,
- 0.1f, 0.9f, 0.0f, 0.0f, 46.5f,
- 0.1f, 0.3f, 0.7f, 0.0f, 46.5f,
- 0.0f, 0.0f, 0.0f, 1.0f, 0.0f
- };
- //夜色
- const float colormatrix_yese[] = {
- 1.0f, 0.0f, 0.0f, 0.0f, -66.6f,
- 0.0f, 1.1f, 0.0f, 0.0f, -66.6f,
- 0.0f, 0.0f, 1.0f, 0.0f, -66.6f,
- 0.0f, 0.0f, 0.0f, 1.0f, 0.0f
- };