最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS實(shí)現(xiàn)高效裁剪圖片圓角算法教程

 更新時(shí)間:2018年06月16日 13:58:57   作者:國(guó)孩  
經(jīng)常看到各種高效裁剪圓角的文章,正好之前做過(guò)一點(diǎn)數(shù)字圖像處理,所以寫(xiě)個(gè)裁剪圓角的算法,下面這篇文章主要給大家介紹了關(guān)于iOS實(shí)現(xiàn)高效裁剪圖片圓角算法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

項(xiàng)目有個(gè)需求:裁剪圖片,針對(duì)頭像,下面是要求:

 

大家可以看到這張圖片的圓角已經(jīng)去除,下面說(shuō)說(shuō)我在項(xiàng)目利用了兩種方式實(shí)現(xiàn)此裁剪以及查看技術(shù)文檔發(fā)現(xiàn)更高效裁剪方式,下面一一講解:看下來(lái)大約需要15-20分鐘。

在公共類(lèi)中Util類(lèi)中創(chuàng)建類(lèi)方法

1.CGContext裁剪

//CGContext裁剪
+ (UIImage *)CGContextClip:(UIImage *)img cornerRadius:(CGFloat)c;

實(shí)現(xiàn)該方法:

// CGContext 裁剪
+ (UIImage *)CGContextClip:(UIImage *)img cornerRadius:(CGFloat)c{
 int w = img.size.width * img.scale;
 int h = img.size.height * img.scale;
 UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), false, 1.0);
 CGContextRef context = UIGraphicsGetCurrentContext();
 CGContextMoveToPoint(context, 0, c);
 CGContextAddArcToPoint(context, 0, 0, c, 0, c);
 CGContextAddLineToPoint(context, w-c, 0);
 CGContextAddArcToPoint(context, w, 0, w, c, c);
 CGContextAddLineToPoint(context, w, h-c);
 CGContextAddArcToPoint(context, w, h, w-c, h, c);
 CGContextAddLineToPoint(context, c, h);
 CGContextAddArcToPoint(context, 0, h, 0, h-c, c);
 CGContextAddLineToPoint(context, 0, c);
 CGContextClosePath(context);
 
 // 先裁剪 context,再畫(huà)圖,就會(huì)在裁剪后的 path 中畫(huà)
 CGContextClip(context);
 [img drawInRect:CGRectMake(0, 0, w, h)]; // 畫(huà)圖
 CGContextDrawPath(context, kCGPathFill);
 UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();
 
 return ret;
}

在該需要的地方調(diào)用如下:

[Util CGContextClip:image cornerRadius:radius];

2.UIBezierPath 裁剪

在Util.h類(lèi)中聲明

//UIBezierPath 裁剪
+ (UIImage *)UIBezierPathClip:(UIImage *)img cornerRadius:(CGFloat)c;

在Util.m實(shí)現(xiàn)方法

//UIBezierPath 裁剪
+ (UIImage *)UIBezierPathClip:(UIImage *)img cornerRadius:(CGFloat)c{
 int w = img.size.width * img.scale;
 int h = img.size.height * img.scale;
 CGRect rect = CGRectMake(0, 0, w, h);
 UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), false, 1.0);
 [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:c] addClip];
 [img drawInRect:rect];
 
 UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();
 return ret;
}

3.空域處理的辦法,寫(xiě)個(gè)裁剪圓角的算法

對(duì)于圖像上的一個(gè)點(diǎn)(x, y),判斷其在不在圓角矩形內(nèi),在的話(huà) alpha 是原值,不在的話(huà) alpha 設(shè)為 0 即可

 

遍歷所有像素,判斷每個(gè)像素在不在4個(gè)圓的圓內(nèi)就行了,4個(gè)角,每個(gè)角有一個(gè)四分之一的圓。

一個(gè)優(yōu)化就是,我不需要遍歷全部的像素就能裁出圓角,只需要考慮類(lèi)似左下角三角形的區(qū)域就行了,左下,左上,右上,右下,一共4個(gè)三角形區(qū)域(另外3個(gè)圖中沒(méi)畫(huà)出),for循環(huán)的時(shí)候,就循環(huán)這個(gè)4個(gè)三角形區(qū)域就行了。

所以對(duì)于一幅 w * h 的圖像,設(shè)圓角大小為 n,n <= min(w, h) / 2,其復(fù)雜度為 O(n) = 2(n^2),最壞的情況計(jì)算量也不會(huì)超過(guò) wh / 2。

對(duì)于一個(gè)像素點(diǎn)(x, y),判斷其在不在圓內(nèi)的公式:
如果  (x-cx)^2 + (y-cy)^2 <= r^2  就表示點(diǎn) (x, y) 在圓內(nèi),反之不在。通過(guò)測(cè)試:此算法效率可以提高幾倍之上(時(shí)間)

在Util.h中聲明:

+ (UIImage *)dealImage:(UIImage *)img cornerRadius:(CGFloat)c

在Util.m中實(shí)現(xiàn):

+ (UIImage *)dealImage:(UIImage *)img cornerRadius:(CGFloat)c {
 // 1.CGDataProviderRef 把 CGImage 轉(zhuǎn) 二進(jìn)制流
 CGDataProviderRef provider = CGImageGetDataProvider(img.CGImage);
 void *imgData = (void *)CFDataGetBytePtr(CGDataProviderCopyData(provider));
 int width = img.size.width * img.scale;
 int height = img.size.height * img.scale;
 
 // 2.處理 imgData
// dealImage(imgData, width, height);
 cornerImage(imgData, width, height, c);
 
 // 3.CGDataProviderRef 把 二進(jìn)制流 轉(zhuǎn) CGImage
 CGDataProviderRef pv = CGDataProviderCreateWithData(NULL, imgData, width * height * 4, releaseData);
 CGImageRef content = CGImageCreate(width , height, 8, 32, 4 * width, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast, pv, NULL, true, kCGRenderingIntentDefault);
 UIImage *result = [UIImage imageWithCGImage:content];
 CGDataProviderRelease(pv); // 釋放空間
 CGImageRelease(content);
 
 return result;
}

void releaseData(void *info, const void *data, size_t size) {
 free((void *)data);
}

// 在 img 上處理圖片, 測(cè)試用
void dealImage(UInt32 *img, int w, int h) {
 int num = w * h;
 UInt32 *cur = img;
 for (int i=0; i<num; i++, cur++) {
 UInt8 *p = (UInt8 *)cur;
 // RGBA 排列
 // f(x) = 255 - g(x) 求負(fù)片
 p[0] = 255 - p[0];
 p[1] = 255 - p[1];
 p[2] = 255 - p[2];
 p[3] = 255;
 }
}

// 裁剪圓角
void cornerImage(UInt32 *const img, int w, int h, CGFloat cornerRadius) {
 CGFloat c = cornerRadius;
 CGFloat min = w > h ? h : w;
 
 if (c < 0) { c = 0; }
 if (c > min * 0.5) { c = min * 0.5; }
 
 // 左上 y:[0, c), x:[x, c-y)
 for (int y=0; y<c; y++) {
 for (int x=0; x<c-y; x++) {
  UInt32 *p = img + y * w + x; // p 32位指針,RGBA排列,各8位
  if (isCircle(c, c, c, x, y) == false) {
  *p = 0;
  }
 }
 }
 // 右上 y:[0, c), x:[w-c+y, w)
 int tmp = w-c;
 for (int y=0; y<c; y++) {
 for (int x=tmp+y; x<w; x++) {
  UInt32 *p = img + y * w + x;
  if (isCircle(w-c, c, c, x, y) == false) {
  *p = 0;
  }
 }
 }
 // 左下 y:[h-c, h), x:[0, y-h+c)
 tmp = h-c;
 for (int y=h-c; y<h; y++) {
 for (int x=0; x<y-tmp; x++) {
  UInt32 *p = img + y * w + x;
  if (isCircle(c, h-c, c, x, y) == false) {
  *p = 0;
  }
 }
 }
 // 右下 y~[h-c, h), x~[w-c+h-y, w)
 tmp = w-c+h;
 for (int y=h-c; y<h; y++) {
 for (int x=tmp-y; x<w; x++) {
  UInt32 *p = img + y * w + x;
  if (isCircle(w-c, h-c, c, x, y) == false) {
  *p = 0;
  }
 }
 }
}

// 判斷點(diǎn) (px, py) 在不在圓心 (cx, cy) 半徑 r 的圓內(nèi)
static inline bool isCircle(float cx, float cy, float r, float px, float py) {
 if ((px-cx) * (px-cx) + (py-cy) * (py-cy) > r * r) {
 return false;
 }
 return true;
}

// 其他圖像效果可以自己寫(xiě)函數(shù),然后在 dealImage: 中調(diào)用 otherImage 即可
void otherImage(UInt32 *const img, int w, int h) {
 // 自定義處理
}

上面是三種方式,可以解決圖片裁剪的需求,

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • MAC中顯示隱藏文件和不顯示隱藏文件的方法(超簡(jiǎn)單)

    MAC中顯示隱藏文件和不顯示隱藏文件的方法(超簡(jiǎn)單)

    下面小編就為大家分享一篇MAC中顯示隱藏文件和不顯示隱藏文件的方法(超簡(jiǎn)單),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • iOS閱讀器與直播的控件重疊滑動(dòng)交互詳解

    iOS閱讀器與直播的控件重疊滑動(dòng)交互詳解

    這篇文章主要介紹了iOS閱讀器與直播的控件發(fā)生重疊時(shí)滑動(dòng)交互受到影響的問(wèn)題,開(kāi)發(fā)中某個(gè)控件出現(xiàn)在其它控件上方是和你常見(jiàn)的情況,但是如果影響到正常的交互這就會(huì)成為大問(wèn)題,下面我們來(lái)了解一下
    2022-08-08
  • Stack?View自定義間隙減少約束的數(shù)量

    Stack?View自定義間隙減少約束的數(shù)量

    這篇文章主要為大家介紹了Stack?View自定義間隙減少約束的數(shù)量示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • IOS多線程實(shí)現(xiàn)多圖片下載(二)

    IOS多線程實(shí)現(xiàn)多圖片下載(二)

    這篇文章主要介紹了IOS多線程實(shí)現(xiàn)多圖片下載(二)的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • IOS檢測(cè)指定路徑的文件是否存在

    IOS檢測(cè)指定路徑的文件是否存在

    本文給大家分享的是在IOS開(kāi)發(fā)中檢測(cè)指定文件是否存在的方法,給大家匯總了4種,十分實(shí)用,小伙伴們根據(jù)自己的需求自由選擇吧。
    2015-05-05
  • iOS中將個(gè)別頁(yè)面強(qiáng)制橫屏其他頁(yè)面豎屏

    iOS中將個(gè)別頁(yè)面強(qiáng)制橫屏其他頁(yè)面豎屏

    這篇文章主要介紹了iOS中將個(gè)別頁(yè)面強(qiáng)制橫屏其他頁(yè)面豎屏的實(shí)現(xiàn)思路,需要的朋友參考下吧
    2016-12-12
  • 僅需幾行代碼實(shí)現(xiàn)方便易用的狀態(tài)欄指示器

    僅需幾行代碼實(shí)現(xiàn)方便易用的狀態(tài)欄指示器

    本文通過(guò)僅僅數(shù)行代碼實(shí)現(xiàn)了非常方便易用的狀態(tài)欄指示器,比如微博項(xiàng)目的微博數(shù)提醒框,需要的朋友可以參考下
    2015-08-08
  • iOS實(shí)現(xiàn)帶有縮放效果的自動(dòng)輪播圖

    iOS實(shí)現(xiàn)帶有縮放效果的自動(dòng)輪播圖

    這篇文章主要為大家詳細(xì)介紹了iOS帶有縮放效果的自動(dòng)輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • iOS 指紋解鎖驗(yàn)證TouchID功能

    iOS 指紋解鎖驗(yàn)證TouchID功能

    這篇文章主要介紹了iOS 指紋解鎖驗(yàn)證TouchID功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03
  • 詳解IOS WebRTC的實(shí)現(xiàn)原理

    詳解IOS WebRTC的實(shí)現(xiàn)原理

    WebRTC,源自網(wǎng)頁(yè)實(shí)時(shí)通信(Web Real-Time Communication)縮寫(xiě),它是支持網(wǎng)頁(yè)瀏覽器進(jìn)行實(shí)時(shí)語(yǔ)音對(duì)話(huà)或視頻對(duì)話(huà)的技術(shù)。它為我們提供了視頻會(huì)議的核心技術(shù),包括音視頻的采集、編解碼、網(wǎng)絡(luò)傳輸、顯示等功能,并且還支持跨平臺(tái):windows,linux,mac,android,ios。
    2021-06-06

最新評(píng)論

正定县| 深圳市| 丁青县| 五常市| 贵德县| 濮阳市| 陕西省| 突泉县| 从江县| 福清市| 廉江市| 清河县| 泰顺县| 孝感市| 巩留县| 宝山区| 广宁县| 扎囊县| 原阳县| 广西| 满洲里市| 通河县| 临漳县| 克山县| 化德县| 蒲城县| 安西县| 连山| 惠州市| 溧水县| 紫云| 蕉岭县| 平谷区| 沁源县| 长白| 司法| 榆林市| 龙里县| 潢川县| 神农架林区| 灵璧县|