目前好多APP都具備濾鏡美顏效果功能,作為iOS開發(fā)者色查,多少也要懂一點(diǎn)圖片的處理效果薯演,本文章只是簡(jiǎn)單介紹基本的濾鏡效果:
一、圖片儲(chǔ)存原理
要對(duì)圖片進(jìn)行修改秧了,那首先就要了解他的儲(chǔ)存原理跨扮,在iOS開發(fā)中接觸最多的主要的圖片格式:jpg、png验毡、webp衡创,不管是什么格式的圖片,可以看成是一個(gè)個(gè)像素點(diǎn)構(gòu)成米罚,這一個(gè)個(gè)點(diǎn)就是RGBA(jpg格式?jīng)]有A通道)钧汹。當(dāng)我們儲(chǔ)存圖片時(shí)丈探,系統(tǒng)都會(huì)有對(duì)應(yīng)的一個(gè)緩沖池(buffer)進(jìn)行存儲(chǔ)录择,buffer裝載的信息大致可以分為兩個(gè)部分:
一個(gè)是Info,這個(gè)是圖片的描述信息碗降,
另外一個(gè)就是Data隘竭,這里面就是圖片數(shù)據(jù)信息,但是這不是最原始的RGB數(shù)據(jù)讼渊,而是經(jīng)過壓縮編碼后的數(shù)據(jù)动看,我們要修改的也是這個(gè)數(shù)據(jù)。
簡(jiǎn)單畫個(gè)圖理解下:
二爪幻、濾鏡效果
實(shí)現(xiàn)濾鏡效果的步驟:
1菱皆、將UIImage轉(zhuǎn)化為Data數(shù)據(jù)
2须误、Data數(shù)據(jù)進(jìn)行灰度、色彩仇轻、美白等處理
3京痢、將處理后的Data數(shù)據(jù)載轉(zhuǎn)化回UIImage
根據(jù)以上三步,做如下操作:
1篷店、將UIImage轉(zhuǎn)化為Data數(shù)據(jù)
這里需要介紹一個(gè)方法祭椰,參數(shù)說(shuō)明詳見
//Bitmap上下文(位圖結(jié)構(gòu))
CGBitmapContextCreate(<#void * _Nullable data#>, <#size_t width#>, <#size_t height#>, <#size_t bitsPerComponent#>, <#size_t bytesPerRow#>, <#CGColorSpaceRef _Nullable space#>, <#uint32_t bitmapInfo#>)
//image ---> data
- (unsigned char*)p_imageToData:(UIImage *)image {
//使用的是框架是CoreGraphics,所以要把image ——> CGImage
CGImageRef imageRef = [image CGImage];
CGSize imageSize = image.size;
//顏色空間
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
//分配bit級(jí)空間大小疲陕,一個(gè)像素點(diǎn)分為 R G B A 為4byte方淤,像素點(diǎn)個(gè)數(shù) = 寬*高
void *data = malloc(4*imageSize.width*imageSize.height);
//Bitmap上下文
//kCGImageAlphaPremultipliedLast 當(dāng)前顏色的排列順序
//kCGBitmapByteOrder32Big 位數(shù) 4*8
CGContextRef context = CGBitmapContextCreate(data, imageSize.width, imageSize.height, 8, 4*imageSize.width, colorSpaceRef, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast);
//渲染
//參數(shù)1:bitmap上下文
//參數(shù)2:需要渲染的空間大小
//參數(shù)3:原始圖片
CGContextDrawImage(context, CGRectMake(0, 0, imageSize.width, imageSize.height), imageRef);
//釋放
CGColorSpaceRelease(colorSpaceRef);
CGContextRelease(context);
return (unsigned char*)data;
}
2、Data數(shù)據(jù)進(jìn)行灰度蹄殃、色彩携茂、美白等處理
a、灰度處理
上面幾組顏色诅岩,他們的RGB值就是顯示的對(duì)應(yīng)的值邑蒋,可見當(dāng)RGB值都相等時(shí),表現(xiàn)出來(lái)的都是灰色按厘,只是程度不同而已医吊。灰度處理也是這個(gè)原理逮京,將像素點(diǎn)的RGB設(shè)置成相等的卿堂,這里提供一個(gè)灰度處理公式:
Gray = 0.299*Red +0.587*Green +0.114*Blue
- (unsigned char*)p_grayDataWithData:(unsigned char*)imageData imageSize:(CGSize)imageSize {
unsigned char* data = malloc(4*sizeof(unsigned char)*imageSize.width*imageSize.height);
//初始化data 內(nèi)存
//參數(shù)1:內(nèi)存地址
//參數(shù)2:填充的值
//參數(shù)3:需要填充的內(nèi)存空間大小
memset(data, 0, 4*imageSize.width*imageSize.height);
for (int h = 0; h < imageSize.height; h++) {
for (int w = 0; w < imageSize.width; w++) {
//當(dāng)前像素點(diǎn)的位置
unsigned int index = h*imageSize.width+w;
//取出原始的RGBA
//imageData+index*4: imageData地址加上偏移量(每個(gè)像素4byte)
unsigned char red = *(imageData+index*4);
unsigned char green = *(imageData+index*4+1);
unsigned char blue = *(imageData+index*4+2);
//灰度處理
unsigned int newRGB = red*0.299+green*0.587+blue*0.114;
//可能算出來(lái)的值大于255
newRGB = newRGB > 255? 255:newRGB;
memset(data+index*4, newRGB, 1);
memset(data+index*4+1, newRGB, 1);
memset(data+index*4+2, newRGB, 1);
}
}
return data;
}
上面代碼提到的有關(guān)內(nèi)存的,畫了個(gè)簡(jiǎn)單的圖幫助理解:
b懒棉、簡(jiǎn)單美白處理
本文采用映射表的方法處理美白效果草描,0-255之間有256個(gè)點(diǎn),按每組32個(gè)策严,分8組穗慕,節(jié)點(diǎn)為55,110妻导,155逛绵,185,225倔韭,240术浪,250,255寿酌,然后再將段按照32等分分割胰苏,畫個(gè)圖說(shuō)明下:
- (unsigned char*)p_skinWhiteWithData:(unsigned char*)imageData imageSize:(CGSize)imageSize {
void *data = malloc(4*imageSize.width*imageSize.height);
memset(data, 0, imageSize.width*imageSize.height);
NSArray *array = @[@"55",@"110",@"155",@"185",@"225",@"240",@"250",@"255"];
NSMutableArray *colorArray = [[NSMutableArray alloc] init];
int last = 0;//記錄前一次的值,一開始為 0
for (int i = 0; i < 8; i++) {
int num = [array[i] intValue];
float step = (num - last)/32.0;//步長(zhǎng)醇疼,每次增加多少
for (int j = 0; j < 32; j++) {
float newNum = last+step*j;//上一次的值加上步長(zhǎng)*j 得到對(duì)應(yīng)位置的值
NSString *newNumStr = [NSString stringWithFormat:@"%lf",newNum];
[colorArray addObject:newNumStr];
}
last = num;
}
for (int h = 0; h < imageSize.height; h++) {
for (int w = 0; w < imageSize.width; w++) {
unsigned int index = h*imageSize.width+w;
//取出原始的RGBA
unsigned int red = *(imageData+index*4);
unsigned int green = *(imageData+index*4+1);
unsigned int blue = *(imageData+index*4+2);
//美白處理
unsigned int newRed = [colorArray[red] floatValue];
unsigned int newGreen = [colorArray[green] floatValue];
unsigned int newBlue = [colorArray[blue] floatValue];
memset(data+index*4, newRed, 1);
memset(data+index*4+1, newGreen, 1);
memset(data+index*4+2, newBlue, 1);
}
}
return data;
}
c硕并、彩色底版處理
同樣給出一個(gè)處理彩色底版的算法:
newValue = 255 - oldValue
- (unsigned char*)p_colorDataWithData:(unsigned char*)imageData imageSize:(CGSize)imageSize {
unsigned char* data = malloc(4*sizeof(unsigned char)*imageSize.width*imageSize.height);
//初始化data 內(nèi)存法焰, 1:內(nèi)存地址 2:填充的值 3:需要填充的內(nèi)存空間大小
memset(data, 0, 4*imageSize.width*imageSize.height);
for (int h = 0; h < imageSize.height; h++) {
for (int w = 0; w < imageSize.width; w++) {
unsigned int index = h*imageSize.width+w;
//取出原始的RGBA
unsigned char red = *(imageData+index*4);
unsigned char green = *(imageData+index*4+1);
unsigned char blue = *(imageData+index*4+2);
//彩色處理
unsigned int newRed = 255-red;
unsigned int newGreen = 255-green;
unsigned int newBlue = 255-blue;
memset(data+index*4, newRed, 1);
memset(data+index*4+1, newGreen, 1);
memset(data+index*4+2, newBlue, 1);
}
}
return data;
}
3、將處理后的Data數(shù)據(jù)載轉(zhuǎn)化回UIImage
- (UIImage *)p_dataToImage:(unsigned char*)imageData imageSize:(CGSize)imageSize {
//原始數(shù)據(jù) 4*imageSize.width*imageSize.height 數(shù)據(jù)空間大小
CGDataProviderRef dataProRef = CGDataProviderCreateWithData(NULL, imageData, 4*imageSize.width*imageSize.height, NULL);
CGImageRef imageRef = CGImageCreate(imageSize.width, imageSize.height, 8, 32, 4*imageSize.width, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault, dataProRef, NULL, NO, kCGRenderingIntentDefault);
UIImage *imageNew = [UIImage imageWithCGImage:imageRef];
//釋放
CFRelease(imageRef);
CGDataProviderRelease(dataProRef);
return imageNew;
}
四倔毙、結(jié)果
直接上效果圖:
五壶栋、總結(jié)
以上是簡(jiǎn)單的處理效果,如果想要多樣的處理效果就是計(jì)算新的RGB值的算法優(yōu)化問題了普监,你們也可以隨便改贵试,會(huì)出現(xiàn)不同的效果呦。最后送上本Demo的鏈接地址:https://github.com/xyzcwb/ImageDemo