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 代码: <! ...
随机推荐
- nginx的锁
一.原理 nginx的锁是基于共享内存实现的,这点跟redis中利用一个存储(也就是一个键值对)来实现锁的原理是一致的,每一项操作通过检查锁对象的lock域是否为0,来判断能否获取锁并尝试获取锁. 二 ...
- cordova 开发
这个挺好用的, 确实 把一个 Android 和 IOS 的App 给生成了. html为前端, js调用 Java 或 object -C的代码. 加快了开发的进度 在不使用插件的基础上 ,基本实现 ...
- Postgresql 数据库错误修复v0.1
PS. 查询\nebula_boh\logs\BOHInterfaceLog.log 日志, 一般数据库文件损坏的日志 有 “UncategorizedSQLException” 或 “zero pa ...
- shell 命令 创建/删除 软连接 ln -s
软链接的作用是, 1. 节省复制造成的空间浪费 2. 保证两个文件的内容同时修改 所以,可以把软连接理解为给文件/文件夹创建了别名,当访问别名时,实际访问的是链接的文件/文件夹 软链文件 ln -s ...
- Java中main方法参数String[ ] args的使用。
我们刚开始学习java时都会被要求记住主方法(main)的写法,就像这样: public static void main(String[] args){ } public static void m ...
- [转] KVM storage performance and cache settings on Red Hat Enterprise Linux 6.2
Almost one year ago, I checked how different cache settings affected KVM storage subsystem performan ...
- 面试官问我,使用Dubbo有没有遇到一些坑?我笑了。
前言 17年的时候,因为一时冲动没把持住(当然最近也有粉丝叫我再冲动一把再更新一波),结合面试题写了一个系列的Dubbo源码解析.目前公众号大部分粉丝都是之前的粉丝,这里不过多介绍. 根据我的面试经验 ...
- MySQL 优化实战记录
阅读本文大概需要 2 分钟. 背景 本次SQL优化是针对javaweb中的表格查询做的. 部分网络架构图 业务简单说明 N个机台将业务数据发送至服务器,服务器程序将数据入库至MySQL数据库.服务器中 ...
- springmvc的Controller里实现转发的同时弹出提示对话框
以前写servlet时就用到这个,但是现在学了springMVC+hibernate后就不知道怎么实现了,后来在网上找了好多,看了好多,最后经过自己实践成功的如下: 1.首先是Controller控制 ...
- Python - Fabric简介
1 - Fabric Fabric是一个Python的库,提供了丰富的同SSH交互的接口,可以用来在本地或远程机器上自动化.流水化地执行Shell命令. 非常适合用来做应用的远程部署及系统维护.简单易 ...