iOS 簡(jiǎn)單圖片濾鏡效果

目前好多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è)圖理解下:


buffer

二爪幻、濾鏡效果

實(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凯正,一起剝皮案震驚了整個(gè)濱河市毙玻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌廊散,老刑警劉巖桑滩,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異允睹,居然都是意外死亡运准,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門缭受,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)胁澳,“玉大人,你說(shuō)我怎么就攤上這事米者【禄” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蔓搞,是天一觀的道長(zhǎng)胰丁。 經(jīng)常有香客問我,道長(zhǎng)喂分,這世上最難降的妖魔是什么锦庸? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮蒲祈,結(jié)果婚禮上甘萧,老公的妹妹穿的比我還像新娘。我一直安慰自己讳嘱,他們只是感情好幔嗦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沥潭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嬉挡。 梳的紋絲不亂的頭發(fā)上钝鸽,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天汇恤,我揣著相機(jī)與錄音,去河邊找鬼拔恰。 笑死因谎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的颜懊。 我是一名探鬼主播财岔,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼河爹!你這毒婦竟也來(lái)了匠璧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤咸这,失蹤者是張志新(化名)和其女友劉穎夷恍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體媳维,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酿雪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了侄刽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片指黎。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖州丹,靈堂內(nèi)的尸體忽然破棺而出袋励,到底是詐尸還是另有隱情,我是刑警寧澤当叭,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布茬故,位于F島的核電站,受9級(jí)特大地震影響蚁鳖,放射性物質(zhì)發(fā)生泄漏磺芭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一醉箕、第九天 我趴在偏房一處隱蔽的房頂上張望钾腺。 院中可真熱鬧,春花似錦讥裤、人聲如沸放棒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)间螟。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間厢破,已是汗流浹背荣瑟。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摩泪,地道東北人笆焰。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像见坑,于是被迫代替她去往敵國(guó)和親嚷掠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)荞驴、插件不皆、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,103評(píng)論 4 62
  • --繪圖與濾鏡全面解析 概述 在iOS中可以很容易的開發(fā)出絢麗的界面效果,一方面得益于成功系統(tǒng)的設(shè)計(jì)戴尸,另一方面得益...
    韓七夏閱讀 2,727評(píng)論 2 10
  • 寫在前面的話 上一篇文章對(duì)簡(jiǎn)單濾鏡實(shí)現(xiàn)有一定的講解粟焊,那么這一篇?jiǎng)t是對(duì)圖像處理更加深層次的說(shuō)明,對(duì)于一張圖片怎么處理...
    前世小書童閱讀 5,409評(píng)論 8 32
  • 今天我讀了《哈佛家訓(xùn)》孙蒙,其中“裝滿小屋的東西”项棠,讓我明白了一個(gè)小小的真理。 一位睿智的父親挎峦,為了考驗(yàn)3個(gè)兒子的...
    山石木杉閱讀 226評(píng)論 2 0