代码地址如下:
http://www.demodashi.com/demo/11609.html

人生得意须尽欢,莫使金樽空对月。
   天生我材必有用,千金散尽还复来。

前记

说到UIImage大家都不会感到陌生,最近在研究UIImage,就顺便把之前工作中用到的一些category总结了一下,记录记录。

在这之前先看一下一些简答的效果图

1、简单处理

2、GIF图片加载

3、图片添加文字、图片及图片截屏、擦除

代码分析
1、图片圆角处理

关于图片的圆角处理,这个可能用的比较多点,当然你也可以用给UIIImageView设置圆角来达到目的,但是在性能上特别是用在tableview上的时候,就没那么好了。

在这之前,我们先来看看CGContextRef,这个怎么解释呢?我的理解就是画布,就相当于我们在画画的时候的画板,我们需要画图片、文字、线条都需要在这上面进行。
在了解这个之后,我们就开始看代码

带圆圈的圆图

+ (UIImage*)gl_circleImage:(UIImage*)image withBorder:(CGFloat)border color:(UIColor *)color
{//通过自己创建一个context来绘制,通常用于对图片的处理//在retian屏幕上要使用这个函数,才能保证不失真//该函数会自动创建一个context,并把它push到上下文栈顶,坐标系也经处理和UIKit的坐标系相同UIGraphicsBeginImageContextWithOptions(CGSizeMake(image.size.width, image.size.height), NO, [UIScreen mainScreen].scale);//获取上下文CGContextRef context = UIGraphicsGetCurrentContext();CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);//设置宽度CGContextSetLineWidth(context, 4*border);//设置边框颜色CGContextSetStrokeColorWithColor(context, color.CGColor);//画椭圆 当宽和高一样的时候 为圆 此处设置可视范围CGContextAddEllipseInRect(context, rect);//剪切可视范围CGContextClip(context);//绘制图片[image drawInRect:rect];CGContextAddEllipseInRect(context, rect);// 绘制当前的路径 只描绘边框CGContextStrokePath(context);UIImage *newimg = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return newimg;
}

本想讲点什么,但是代码中已经有注释,就不说什么了,这里需要注意的是UIGraphicsBeginImageContextWithOptions这个函数,最后一个参数--缩放因子,和我们平时用的倍图相关,比如@x,@2x,@3x,在4s上为1,后面的机型中,plus3,其余为2,在这里可以设置为0,这样会自动匹配。

不带圆圈的圆图

/**创建圆形图片@param image 原始图片@return 返回*/
+ (UIImage *)gl_circleImage:(UIImage *)image;

由于和带圆圈的原图代码几乎一致,只是少了边框这部分代码,这里就不在贴出来了,后面会给出demo

2、根据颜色创建图片

这个比较简单,最主要的是靠下面两个函数来进行实现

    //设置填充颜色CGContextSetFillColorWithColor(context, color.CGColor);//直接按rect的范围覆盖CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));

在这里有两个函数,CGContextSetFillColorWithColorCGContextSetStrokeColorWithColor,是相对的两个函数,一个是设置覆盖区域的颜色,一个是设置边框的颜色,在使用的时候应该和其他函数对应一起使用。
下面还是列出代码

+ (UIImage *)gl_imageWithColor:(UIColor *)color size:(CGSize)size{CGSize imageSize = size;//通过自己创建一个context来绘制,通常用于对图片的处理UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale);//获取上下文CGContextRef context = UIGraphicsGetCurrentContext();//设置填充颜色CGContextSetFillColorWithColor(context, color.CGColor);//直接按rect的范围覆盖CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));UIImage *newimg = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return newimg;
}

由于根据颜色来绘制圆形图片代码和上面几乎一致,只是将其中的
CGContextFillRect换成了CGContextAddEllipseInRectCGContextFillPath,这里就不在详细讲解

3、给图片设置圆角

这个可能用的比较多点,比如当美工不给我切图的时候,我们又需要使图片其中的几个角有圆角,那么这时候这个方法就派上用场了。

在这里,主要是通过方法CGContextAddPathUIBezierPath一起来实现,详细看到这里,大家都知道怎么用的了,下面我们就来看源码

+ (UIImage*)gl_cornerImage:(UIImage*)image corner:(CGFloat)corner rectCorner:(UIRectCorner)rectCorner
{CGSize imageSize = image.size;UIGraphicsBeginImageContextWithOptions(imageSize, NO, [UIScreen mainScreen].scale);CGContextRef context = UIGraphicsGetCurrentContext();CGRect rect = CGRectMake(0,0,imageSize.width,imageSize.height);UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rectbyRoundingCorners:rectCornercornerRadii:CGSizeMake(corner,corner)];//添加路径CGContextAddPath(context, [path CGPath]);//剪切可视范围CGContextClip(context);[image drawInRect:rect];UIImage *newimg = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return newimg;
}
4、压缩图片

说到压缩图片,这个应该是用的最多的了,比如有一天突然项目经理给你说,我们上传的这个图片啊,太大了,不仅浪费流量还特别慢,而且服务器压力还不小....你们客户端处理下把,最好在250kb左右,但是又不能裁剪图片,这个时候,这个方法就能大展身手了。
其主要思路是通过一个while循环,不停的去缩小我们所要的图片,当然计算图片的大小,我们用的是UIImageJPEGRepresentation,虽然这个和真实图片的大小还是有那么点误差,但是一般情况下还是没什么问题的,下面我们来看源码

+ (UIImage*)gl_compressImage:(UIImage *)image maxSize:(CGFloat)maxSize maxSizeWithKB:(CGFloat)maxSizeKB
{    if (maxSize <= 0) {return nil;}if (maxSizeKB <= 0) {return nil;}CGSize compressSize = image.size;//获取缩放比 进行比较 CGFloat widthScale = compressSize.width*1.0 / maxSize;CGFloat heightScale = compressSize.height*1.0 / maxSize;if (widthScale > 1 && widthScale > heightScale) {compressSize = CGSizeMake(image.size.width/widthScale, image.size.height/widthScale);}else if (heightScale > 1 && heightScale > widthScale){compressSize = CGSizeMake(image.size.width/heightScale, image.size.height/heightScale);}//创建图片上下文 并获取剪切尺寸后的图片UIGraphicsBeginImageContextWithOptions(compressSize, NO, 1);CGRect rect = {CGPointZero,compressSize};[image drawInRect:rect];UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();//循环缩小图片大小NSData *imageData = UIImageJPEGRepresentation(newImage, 1.0);//获取当前图片的大小CGFloat currentImageSizeOfKB = imageData.length/1024.0;//压缩比例CGFloat compress = 0.9;while (currentImageSizeOfKB > maxSizeKB && compress > 0.1) {imageData = UIImageJPEGRepresentation(newImage, compress);currentImageSizeOfKB = imageData.length/1024.0;compress -= 0.1;}return [UIImage imageWithData:imageData];
}
5、加载GIF图片

说到加载动态图片,需求量虽然不大,但还是偶尔会用到,这里我们有一个很关键的API---+ (nullable UIImage *)animatedImageWithImages:(NSArray<UIImage *> *)images duration:(NSTimeInterval)duration,通过这个函数,我们可以简单的来播放动态图片。下面我们要做的就是怎么得到GIF图片的图片资源和其播放时间duration

关于图片源,在ImageIo中有这么一个类CGImageSource,其中的CGImageSourceRef也就是我们所说的图片源,查看API,我们可以得到三种方式:

1、CGImageSourceCreateWithURL
基于一个URL链接来读取图片信息。这个方法也是苹果推荐的方法,因为有些时候我们想获取照片的信息,但不需要将照片加载到内存中(因为这是没必要的),所以只需要给出照片的URL地址。
2、CGImageSourceCreateWithData
这个方法是基于一个NSData对象来获取照片信息。所以如果想使用此方法,必需将一个UIImage对象转换成NSData对象,例如:

    NSString *filePath = [[NSBundle mainBundle]pathForResource:@"24" ofType:@"jpg"];NSData *data = [NSData dataWithContentsOfFile:filePath];CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);

3、CGImageSourceCreateWithDataProvider
这种方法主要是需要将一个CGImageRef生成一个CGDataProvider。而参数"options"选项是一个字典,用于创建图片源时提供的附加属性,例如是否对图片进行缓存等。

在有了得到图片源的方法后,我们就可以通过图片源来得到其中的相关信息,最主要的是动画时间,具体代码如下

static CGFloat frameDuration(NSInteger index,CGImageSourceRef source)
{//获取每一帧的信息CFDictionaryRef frameProperties = CGImageSourceCopyPropertiesAtIndex(source,index, nil);//转换为dicNSDictionary *framePropertiesDic = (__bridge NSDictionary *)frameProperties;//获取每帧中关于GIF的信息NSDictionary *gifProperties = framePropertiesDic[(__bridge NSString *)kCGImagePropertyGIFDictionary];/*苹果官方文档中的说明kCGImagePropertyGIFDelayTimeThe amount of time, in seconds, to wait before displaying the next image in an animated sequencekCGImagePropertyGIFUnclampedDelayTimeThe amount of time, in seconds, to wait before displaying the next image in an animated sequence. This value may be 0 milliseconds or higher. Unlike the kCGImagePropertyGIFDelayTime property, this value is not clamped at the low end of the range.看了翻译瞬间蒙了 感觉一样 但是kCGImagePropertyGIFDelayTime 可能为0  所以我觉得可以先判断kCGImagePropertyGIFDelayTime*/CGFloat duration = 0.1;NSNumber *unclampedPropdelayTime = gifProperties[(__bridge NSString *)kCGImagePropertyGIFUnclampedDelayTime];NSNumber *delayTime = gifProperties[(__bridge NSString *)kCGImagePropertyGIFDelayTime];if (unclampedPropdelayTime) {duration = unclampedPropdelayTime.floatValue;}else{if (delayTime) {duration = delayTime.floatValue;}}CFRelease(frameProperties);return duration;
}

在有了动态图片时间后,我们来看看后续动态图片的实现

//动态图片处理
static UIImage *animatedImageWithAnimateImageSource(CGImageSourceRef imageSource)
{if (imageSource) {//得到图片资源的数量size_t imageCount = CGImageSourceGetCount(imageSource);//最终图片资源UIImage *resultImage = nil;//动态图片时间NSTimeInterval duration = 0.0;//取图片资源NSMutableArray *images = [NSMutableArray arrayWithCapacity:imageCount];for (size_t i = 0; i < imageCount; i ++) {//此处用到了create  后面记得释放CGImageRef cgImage = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);if (cgImage) {//将图片加入到数组中[images addObject:[UIImage imageWithCGImage:cgImage scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];}duration += frameDuration(i, imageSource);//释放掉 不然会内存泄漏CGImageRelease(cgImage);}if (duration == 0.0) {duration = 0.1 * imageCount;}resultImage = [UIImage animatedImageWithImages:images duration:duration];CFRelease(imageSource);return resultImage;}return nil;
}

这样的话,我们就可以加载我们所需要的动态图片了。在上述代码中,需要注意的几个地方
1、使用了create和copy这样的函数,我们需要手动对其内存进行管理
2、在封装方法的时候,我只封装了用图片url和图片二进制文件以及图片资源地址的方法,需要注意的是,在使用图片二进制文件的时候,需要特别注意二进制文件的转化,不能使用UIImageJPEGRepresentation,亲测不对,不知道gif用此方法为什么不行,建议通过路径的方式来获取data,如NSData *data = [NSData dataWithContentsOfFile:imagePath],上面是核心代码,其他部分,可以参考后面的demo

6、图片添加文字或者图片

这个比较简单,最主要的方法就是通过drawInRect来将文字或者图片画到当前的画布上,这里就只列一个添加文字的代码出来,添加图片的后面可以参考demo

+ (UIImage *)gl_addTitleAboveImage:(UIImage *)image addTitleText:(NSString *)textattributeDic:(NSDictionary *)attributeDic point:(CGPoint)point
{UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);[image drawInRect:imageRect];[text drawAtPoint:point withAttributes:attributeDic];//获取上下文中的新图片UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();return newImage;
}

需要注意的是函数UIGraphicsBeginImageContextWithOptions中的最后一个参数,需要根据当前屏幕来,否则添加的文字和图片可能会出现模糊,如在5S上面,将其设为1

7、图片截屏或者擦除

在这两个功能中,最主要用到的函数是renderInContextCGContextClearRect,第一个主要是用来截屏用的,渲染当前图片,与之接近的还有一个函数drawInContext,当然,我们不能用这个函数,因为这个函数不能渲染图片,只针对layer。而后面的一个函数主要是用来清除该区域的。通过上面两个函数,我们就能够轻松的实现擦除功能,就如橡皮擦功能。
代码如下

+ (UIImage *)gl_wipeImageWithView:(UIView *)view movePoint:(CGPoint)point brushSize:(CGSize)size
{//开启上下文UIGraphicsBeginImageContext(view.bounds.size);CGContextRef context = UIGraphicsGetCurrentContext();//此方法不能渲染图片 只针对layer//[view.layer drawInContext:context];//以point为中心,然后size的一半向两边延伸  坐画笔  橡皮擦CGRect clearRect = CGRectMake(point.x - size.width/2.0, point.y - size.width/2.0, size.width, size.height);//渲染图片[view.layer renderInContext:context];//清除该区域CGContextClearRect(context, clearRect);//得到新图片UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();//避免内存泄漏view.layer.contents = nil;return newImage;
}

移动路径的代码就不在这里贴了,demo中有的,截屏的核心代码也就不贴了,很简单的,可以查看demo

项目文件截图:

写在最后

其实上面的这些都是比较简单的,主要是通过CGContextRef及其中的一些方法进行实习的,真正让人东西的,还是图形的处理,如添加马赛克、图片滤镜等,今天面试就问道了滤镜,当场就蒙了,后面我会努力研究下,希望到时候也能有好的东西分享给大家。iOSQuart2D绘图之UIImage简单使用

代码地址如下:
http://www.demodashi.com/demo/11609.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

iOSQuart2D绘图之UIImage简单使用相关推荐

  1. 编程软件python图片-python Plotly绘图工具的简单使用

    1.plotly库的相关介绍 1)相关说明 plotly是一个基于javascript的绘图库,plotly绘图种类丰富,效果美观: 易于保存与分享plotly的绘图结果,并且可以与Web无缝集成: ...

  2. Android原生绘图进度条+简单自定义属性代码生成器

    零.前言 1.感觉切拼字符串是个很有意思的事,好的拼接方式可以自动生成一些很实用的东西 2.本文自定义控件并不是很高大上的东西,目的在于计录自定义控件的书写规范与行文流程 3.建议大家自定义控件时自定 ...

  3. 【Qt】2D绘图之绘制简单的图形

    00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 绘制图形 04. 画笔和画刷 05. 绘制弧线 06. 附录 01. 概述 Qt中提供了强大的2D绘图系统,可以使用同一A ...

  4. Android绘图机制 Demo(简单完成美图秀秀的滤镜)

    Android绘图机制 Demo(简单完成美图秀秀的滤镜) 1.xml <?xml version="1.0" encoding="utf-8"?> ...

  5. android 简单获取实时天气数据_绘图本身很简单但是获取数据很难

    看到我们生信技能树的教学群有学员提问这样的图如何绘制: 其实我们讲解过,绘图代码本身搜索即可拿到,关键词 ggpubr paired boxplot ,输入到 https://cn.bing.com/ ...

  6. Python 绘图居然如此简单,真是大数据时代的神器

    今天的文章讲解如何利用 Pandas 来绘图,前面写过 matplotlib 相关文章,matplotlib 虽然功能强大,但是 matplotlib 相对而言较为底层,画图时步骤较为繁琐,比较麻烦, ...

  7. flot java_JS绘图Flot应用-简单曲线图

    首先对Flot做简单介绍: flot 是一个基于jquery的开源javascript库,是一个纯粹的 jQuery JavaScript 绘图库,可以在客户端即时生成图形,使用非常简单,支持放大缩小 ...

  8. python 绘图脚本系列简单记录

    简单记录平时画图用到的python 便捷小脚本 1. 从单个文件输入 绘制坐标系图 #!/usr/bin/python # coding: utf-8 import matplotlib.pyplot ...

  9. 双缓冲技术绘图原理及简单的VC实现

    为了增加自己对双缓冲绘图技术的理解,简要做个笔记(以Windows为例): 1.Windows 绘图原理  我们在 Windows 环境下看到各种元素,如菜单.按钮.窗口.图像,从根本上说,都是&qu ...

最新文章

  1. Activiti——流程变量(六)
  2. Windows Server 2008 SVN 配置
  3. log4cxx体系结构
  4. Java基础- super 和 this 解析
  5. 学习笔记6-小项目-走迷宫、推箱子
  6. 克罗谈投资策略05_涨势买入,跌势卖出
  7. 基于FTP4J组件的FTP操作客户端
  8. 【预测模型】基于麻雀算法优化最小二乘支持向量机实现数据分类matlab代码
  9. 哲学家进餐问题解决方法
  10. 【rzxt】笔者支招:电脑的散热大户显卡温度过高如何解决
  11. “元宵”大师带你用Python量化交易
  12. 自己构建iSCSI磁盘阵列
  13. 简简单单做股票读书笔记(4/8)
  14. 虎克哈克环槽铆钉机 铆接回收机振动筛设备 钢结构集装箱铆接机
  15. Nginx 代理本地文件
  16. CellPress | 人工智能在临床试验中的应用
  17. vb的学习和开发笔记-textbox
  18. 湘教云显示服务器异常,湘教云显示服务器异常
  19. UE4 默认天空球导致MaterialInstanceDynamic动态材质一直增加
  20. 释放被系统保留的内存容量

热门文章

  1. 进行java环境设置的原因_java环境变量的设置原因
  2. JAVA EE 6 jar包集合_Java EE6将JSF facelets(xhtml)和ManagedBeans打包成JAR
  3. python简单的编程_简单的Python2.7编程初学经验总结
  4. python生成shell脚本_Python设置在shell脚本中自动补全功能的方法
  5. 2013蓝桥杯java试题_2013年第四届蓝桥杯javaB组 试题 答案 解析
  6. Scala学习笔记06:自定义控制结构
  7. Python案例:破译爬虫项目实践活动日期密码
  8. android 打印流程图,Android实现Activities之间进行数据传递的方法
  9. java怎么实现查找n功能_java 实现微信搜索附近人功能
  10. 2017.10.18 开店 失败总结