iOS高效裁剪圖片圓角演算法

來源:互聯網
上載者:User

標籤:static   intent   info   遍曆   point   etop   graph   top   地方   

項目有個需求:裁剪圖片,針對頭像,下面是要求:

 

大家可以看到這張圖片的圓角已經去除,下面說說我在項目利用了兩種方式實現此裁剪以及查看技術文檔發現更高效裁剪方式,下面一一講解:看下來大約需要15-20分鐘。

在公用類中Util類中建立類方法

1.CGContext裁剪

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

實現該方法:

// 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,再畫圖,就會在裁剪後的 path 中畫    CGContextClip(context);    [img drawInRect:CGRectMake(0, 0, w, h)];       // 畫圖    CGContextDrawPath(context, kCGPathFill);    UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();    UIGraphicsEndImageContext();        return ret;}

在該需要的地方調用如下:

[Util CGContextClip:image cornerRadius:radius];

 

2.UIBezierPath 裁剪

在Util.h類中聲明

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

在Util.m實現方法

//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.空域處理的辦法,寫個裁剪圓角的演算法

對於映像上的一個點(x, y),判斷其在不在圓角矩形內,在的話 alpha 是原值,不在的話 alpha 設為 0 即可

遍曆所有像素,判斷每個像素在不在4個圓的圓內就行了,4個角,每個角有一個四分之一的圓。

一個最佳化就是,我不需要遍曆全部的像素就能裁出圓角,只需要考慮類似左下角三角形的地區就行了,左下,左上,右上,右下,一共4個三角形地區(另外3個圖中沒畫出),for迴圈的時候,就迴圈這個4個三角形地區就行了。

所以對於一幅 w * h 的映像,設圓角大小為 n,n <= min(w, h) / 2,其複雜度為 O(n) = 2(n^2),最壞的情況計算量也不會超過 wh / 2。

對於一個像素點(x, y),判斷其在不在圓內的公式:
如果  (x-cx)^2 + (y-cy)^2 <= r^2  就表示點 (x, y) 在圓內,反之不在。通過測試:此演算法效率可以提高几倍之上(時間)

在Util.h中聲明:

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

在Util.m中實現:

+ (UIImage *)dealImage:(UIImage *)img cornerRadius:(CGFloat)c {    // 1.CGDataProviderRef 把 CGImage 轉 二進位流    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 把 二進位流 轉 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 上處理圖片, 測試用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) 求負片        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;            }        }    }}// 判斷點 (px, py) 在不在圓心 (cx, cy) 半徑 r 的圓內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;}// 其他映像效果可以自己寫函數,然後在 dealImage: 中調用 otherImage 即可void otherImage(UInt32 *const img, int w, int h) {    // 自訂處理}

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

 

iOS高效裁剪圖片圓角演算法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.