手机裁剪圆角图片_iOS高效裁剪图片圆角算法

项目有个需求:裁剪图片,针对头像,下面是要求:

大家可以看到这张图片的圆角已经去除,下面说说我在项目利用了两种方式实现此裁剪以及查看技术文档发现更高效裁剪方式,下面一一讲解:看下来大约需要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();returnret;

}

在该需要的地方调用如下:

[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();returnret;

}

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);returnresult;

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

free((void *)data);

}//在 img 上处理图片, 测试用

void dealImage(UInt32 *img, int w, inth) {int num = w *h;

UInt32*cur =img;for (int i=0; i

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, inth, 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

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

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

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

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, floatpy) {if ((px-cx) * (px-cx) + (py-cy) * (py-cy) > r *r) {return false;

}return true;

}//其他图像效果可以自己写函数,然后在 dealImage: 中调用 otherImage 即可

void otherImage(UInt32 *const img, int w, inth) {//自定义处理

}

上面是三种方式,可以解决图片裁剪的需求,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值