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

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

  1. iOS 高效添加圆角效果实战讲解

    圆角(RounderCorner)是一种很常见的视图效果,相比于直角,它更加柔和优美,易于接受.但很多人并不清楚如何设置圆角的正确方式和原理.设置圆角会带来一定的性能损耗,如何提高性能是另一个需要重点 ...

  2. iOS 开发--开源图片处理圆角

    概述 开源项目名称:HYBImageCliped 当前版本:2.0.0 项目用途:可给任意继承UIView的控件添加任意多个圆角.可根据颜色生成图片且可带任意个圆角.给UIButton设置不同状态下的 ...

  3. iOS开发——UI进阶篇(十八)核心动画小例子,转盘(裁剪图片、自定义按钮、旋转)图片折叠、音量震动条、倒影、粒子效果

    一.转盘(裁剪图片.自定义按钮.旋转) 1.裁剪图片 将一张大图片裁剪为多张 // CGImageCreateWithImageInRect:用来裁剪图片 // image:需要裁剪的图片 // re ...

  4. IOS 按比例裁剪图片

    拍照或者从图片库中获取图片 操作过程中容易闪退,也总会有内存压力警告,第一步,首先可以考虑裁剪图片,实际上可能不需要那么大的.其次可以考虑把耗时的比如存储过程放进线程. 这里封装裁剪图片的类方法. / ...

  5. iOS 压缩与裁剪图片问题

    我们假设要在截图中的举行图片展示区显示图片,由于原图片的宽高比例与图片显示窗口的宽高比例不一定相同,所以,直接将图片扔进去会改变图片的宽高比例,展示效果不好. 这时你可能想到设置UIImageView ...

  6. Fresco从配置到使用(最高效的图片加载框架)

    Frescoj说明:      facebook开源的针对android应用的图片加载框架,高效和功能齐全. 支持加载网络,本地存储和资源图片: 提供三级缓存(二级memory和一级internal ...

  7. 一些iOS高效开源类库

    因为iOS SDK相对比较底层,所以开发者就得受累多做一些体力活.不过幸运的是,有很多第三方的类库可以用来简化很多不必要的工作.笔者整理了一下在本人学习过程中用到的一些比较有用Objective-C开 ...

  8. 【转】java缩放图片、java裁剪图片代码工具类

    一首先看下效果 二工具类 三测试类 在系统的上传图片功能中,我们无法控制用户上传图片的大小,用户可能会上传大到几十M小到1k的的图片,一方面图片太大占据了太多的空间,另一方面,我们没办法在页面上显示统 ...

  9. jquery photoClip支持手机端,PC端 本地裁剪图片后上传插件

    支持手机,PC最好的是jquery photoClip插件,下载地址&示例:https://github.com/topoadmin/photoClip demo.html 代码: <! ...

随机推荐

  1. asp.net执行顺速

    理解ASP.NET的运行机制(例:通过HttpModule来计算页面执行时间) 一:简要介绍一下asp.net的执行步骤 1.IIS接收到客户请求 2. IIS把请求交给aspnet_isapi.dl ...

  2. LAMP安装教程

    LAMP环境配置安装注意安装步骤及说明事项. Linux + apache+mysql+php 附件: 1. 访问ftp报错 解决: 关闭selinux vi  /etc/selinux/config ...

  3. Android学习笔记(2):build.grandle的常用设置

    1 > java开发中有两个大名鼎鼎的项目构建ANT.Maven. 2 > Google推荐使用的Android Studio是采用Gradle来构建项目的.Gradle是一个非常先进的项 ...

  4. The test form is only available for requests from the local machine

    使用浏览器测试Web服务时出现提示“The test form is only available for requests from the local machine.”的解决办法 在Web服务项 ...

  5. SQL Server 深入解析索引存储(堆)

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/索引体系结构/堆 概述 本篇文章是关于堆的存储结构.堆是不含聚集索引的表(所以只有非聚集索引的表也是堆).堆的 sys.parti ...

  6. Javascript高级编程学习笔记(27)—— BOM(1)window对象1

    ECMAScript是JS的核心 但是对于在浏览器中运行的JS,BOM显然才是真正的核心 我们知道JS是由三个部分组成的 BOM.DOM.ECMAScript 之前的文章我们主要介绍的是ECMAScr ...

  7. Numpy学习四:numpy.power()用法

    numpy.power(n, x) 对数组n的元素分别求x次方.x可以是数字,也可以是数组,但是n和x的列数要相同.

  8. 第59节:Java中的html和css语言

    欢迎到我的简书查看我的文集 前言: HTML 英文: HyperText Markup Language内容 html是超文本标记语言,是网页语言的基础知识,html是通过标签来定义的语言,所有代码都 ...

  9. 小程序开发基础-swiper 滑块视图容器

    小编 / 达叔小生 参考官方文档:https://developers.weixin.qq.com/miniprogram/dev/component/ 小程序开发基础-swiper 滑块视图容器 根 ...

  10. Mybatis框架六:关联查询

    这里搞一个测试场景: 用户和订单,一位用户可以有多个订单,而每个订单只属于一位用户 以用户为中心,相对于订单:一对多 以订单为中心,当对于用户:一对一 两张表结构: 订单表: 用户表: 对应的POJO ...