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, , c);
CGContextAddArcToPoint(context, , , c, , c);
CGContextAddLineToPoint(context, w-c, );
CGContextAddArcToPoint(context, w, , w, c, c);
CGContextAddLineToPoint(context, w, h-c);
CGContextAddArcToPoint(context, w, h, w-c, h, c);
CGContextAddLineToPoint(context, c, h);
CGContextAddArcToPoint(context, , h, , h-c, c);
CGContextAddLineToPoint(context, , c);
CGContextClosePath(context); // 先裁剪 context,再画图,就会在裁剪后的 path 中画
CGContextClip(context);
[img drawInRect:CGRectMake(, , 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(, , 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 * , releaseData);
CGImageRef content = CGImageCreate(width , height, , , * 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=; i<num; i++, cur++) {
UInt8 *p = (UInt8 *)cur;
// RGBA 排列
// f(x) = 255 - g(x) 求负片
p[] = - p[];
p[] = - p[];
p[] = - p[];
p[] = ;
}
}
// 裁剪圆角
void cornerImage(UInt32 *const img, int w, int h, CGFloat cornerRadius) {
CGFloat c = cornerRadius;
CGFloat min = w > h ? h : w;
if (c < ) { c = ; }
if (c > min * 0.5) { c = min * 0.5; }
// 左上 y:[0, c), x:[x, c-y)
for (int y=; y<c; y++) {
for (int x=; x<c-y; x++) {
UInt32 *p = img + y * w + x; // p 32位指针,RGBA排列,各8位
if (isCircle(c, c, c, x, y) == false) {
*p = ;
}
}
}
// 右上 y:[0, c), x:[w-c+y, w)
int tmp = w-c;
for (int y=; 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 = ;
}
}
}
// 左下 y:[h-c, h), x:[0, y-h+c)
tmp = h-c;
for (int y=h-c; y<h; y++) {
for (int x=; x<y-tmp; x++) {
UInt32 *p = img + y * w + x;
if (isCircle(c, h-c, c, x, y) == false) {
*p = ;
}
}
}
// 右下 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 = ;
}
}
}
}
// 判断点 (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高效裁剪图片圆角算法的更多相关文章
- iOS 高效添加圆角效果实战讲解
圆角(RounderCorner)是一种很常见的视图效果,相比于直角,它更加柔和优美,易于接受.但很多人并不清楚如何设置圆角的正确方式和原理.设置圆角会带来一定的性能损耗,如何提高性能是另一个需要重点 ...
- iOS 开发--开源图片处理圆角
概述 开源项目名称:HYBImageCliped 当前版本:2.0.0 项目用途:可给任意继承UIView的控件添加任意多个圆角.可根据颜色生成图片且可带任意个圆角.给UIButton设置不同状态下的 ...
- iOS开发——UI进阶篇(十八)核心动画小例子,转盘(裁剪图片、自定义按钮、旋转)图片折叠、音量震动条、倒影、粒子效果
一.转盘(裁剪图片.自定义按钮.旋转) 1.裁剪图片 将一张大图片裁剪为多张 // CGImageCreateWithImageInRect:用来裁剪图片 // image:需要裁剪的图片 // re ...
- IOS 按比例裁剪图片
拍照或者从图片库中获取图片 操作过程中容易闪退,也总会有内存压力警告,第一步,首先可以考虑裁剪图片,实际上可能不需要那么大的.其次可以考虑把耗时的比如存储过程放进线程. 这里封装裁剪图片的类方法. / ...
- iOS 压缩与裁剪图片问题
我们假设要在截图中的举行图片展示区显示图片,由于原图片的宽高比例与图片显示窗口的宽高比例不一定相同,所以,直接将图片扔进去会改变图片的宽高比例,展示效果不好. 这时你可能想到设置UIImageView ...
- Fresco从配置到使用(最高效的图片加载框架)
Frescoj说明: facebook开源的针对android应用的图片加载框架,高效和功能齐全. 支持加载网络,本地存储和资源图片: 提供三级缓存(二级memory和一级internal ...
- 一些iOS高效开源类库
因为iOS SDK相对比较底层,所以开发者就得受累多做一些体力活.不过幸运的是,有很多第三方的类库可以用来简化很多不必要的工作.笔者整理了一下在本人学习过程中用到的一些比较有用Objective-C开 ...
- 【转】java缩放图片、java裁剪图片代码工具类
一首先看下效果 二工具类 三测试类 在系统的上传图片功能中,我们无法控制用户上传图片的大小,用户可能会上传大到几十M小到1k的的图片,一方面图片太大占据了太多的空间,另一方面,我们没办法在页面上显示统 ...
- jquery photoClip支持手机端,PC端 本地裁剪图片后上传插件
支持手机,PC最好的是jquery photoClip插件,下载地址&示例:https://github.com/topoadmin/photoClip demo.html 代码: <! ...
随机推荐
- ubuntu安装苹果Windows以及微软雅黑consolas字体
ubuntu安装苹果Windows以及微软雅黑consolas字体 ubuntu安装苹果字体 wget http://drive.noobslab.com/data/Mac/macfonts.zip ...
- 基于UML的高校教务管理系统的设计与实现
一.基本信息 标题:基于UML的高校教务管理系统的设计与实现 时间:2018 出版源:南昌航空大学 领域分类:教育信息化:教务管理系统:UML:SSH:Oracle 二.研究背景 问题定义:高校教务管 ...
- 浅谈如何检查Linux中开放端口列表
给大家分享一篇关于如何检查Linux中的开放端口列表的详细介绍,首先如果你想检查远程Linux系统上的端口是否打开请点击链接浏览.如果你想检查多个远程Linux系统上的端口是否打开请点击链接浏览.如果 ...
- day20_雷神_django第三天
django第三天 动态路由,实现统一删除功能 urls url(r'^host_del/(host|user|group)/(\d+)$',views.host_del,name='del'), t ...
- 利用正则+requests爬取猫眼电影信息
import json # from multiprocessing import Pool import requests from requests.exceptions import Reque ...
- 10个经典的Java面试题集合
这里有10个经典的Java面试题,也为大家列出了答案.这是Java开发人员面试经常容易遇到的问题,相信你了解和掌握之后一定会有所提高.让我们一起来看看吧. 1.Java的HashMap是如何工作的? ...
- 一键访问Google和YouTube等国外知名网站
1.首先打开快速安全通道网站,点击注册!网站地址 https://www.faststunnel.xyz/GWx6uy0M 2.注册好之后下载插件 3.将插件下载完后拖到浏览器安装 4.登录插件,即可 ...
- Django项目添加应用路径
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
- PHP删除当前目录及其目录下的所有文件
使用PHP遍历一个目录下的所有目录及文件,并删除该目录及其目录下的所有子目录和文件,本次代码通过递归的方式来实现. 用到的函数: scandir($path) 遍历一个目录下所有文件并返回数组. un ...
- Eclipse 修改自动补全触发器只能输入四个字符为多个字符
如果eclipse中的[auto activation triggers for java]自动补全触发器这个位置的文本框有时候只能输入4个字符, 可以通过修改配置文件的方法实现,具体操作步骤如下: ...