iOS:iOS开发系列–打造自己的“美图秀秀”(下)
来源: KenshinCui
链接:http://www.cnblogs.com/kenshincui/p/3959951.html
运行效果:
其他图形上下文
前面我们也说过,Quartz 2D的图形上下方除了可以绘制到层上还可以绘制到位图、PDF等,这里我们就介绍一下如何利用Quartz 2D绘制图像到位图及PDF中。
上面的示例中一直都是在drawRect:方法中利用UIGraphicsGetCurrentContext()方法取得上下文,要得到位图或者PDF的上下文可以利用UIGraphicsBeginImageContext(CGSize size)和UIGraphicsBeginPDFPageWithInfo(CGRect bounds, NSDictionary *pageInfo)方法。位图图形上下文和PDF图形上下文UIKit是不会负责创建的,所以需要用户手动创建,并且在使用完后关闭它。在使用UIKit中系统创建的图形上下文的时候,我们只能在drawRect:方法中使用,由于这两类图形上下文是由我们手动创建的因此可以放到任何方法中调用。此外,这两个方法开启的图形上下文并没有返回值,如果我们要得到我们创建的图形上下文只要在创建上下文之后、关闭之前调用UIGraphicsGetCurrentContext()方法,此时取得的上下文即是我们自己创建的图形上下文。
绘制到位图
下面利用位图图形上下文给一个图片添加水印,在下面的程序中我们首先创建上下文,然后在上下文中绘制图片、直线和文本,最后从当前位图上下文中取得最终形成的新图片显示到界面。
- // KCMainViewController.m
- // Quartz2D
- //
- // Created by Kenshin Cui on 14-3-17.
- // Copyright (c) 2014年 Kenshin Cui. All rights reserved.
- //
- #import <CoreText/CoreText.h>
- #import "KCMainViewController.h"
- #import "KCView.h"
- #import "KCView2.h"
- #import "KCView3.h"
- @interface KCMainViewController ()
- @end
- @implementation KCMainViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- UIImage *image=[self drawImageAtImageContext];
- UIImageView *imageView=[[UIImageView alloc]initWithImage:image];
- imageView.center=CGPointMake(, );
- [self.view addSubview:imageView];
- }
- #pragma mark 利用位图上下文添加水印效果
- -(UIImage *)drawImageAtImageContext{
- //获得一个位图图形上下文
- CGSize size=CGSizeMake(, );//画布大小
- UIGraphicsBeginImageContext(size);
- UIImage *image=[UIImage imageNamed:@"photo2.png"];
- [image drawInRect:CGRectMake(, , , )];//注意绘图的位置是相对于画布顶点而言,不是屏幕
- //添加水印
- CGContextRef context=UIGraphicsGetCurrentContext();
- CGContextMoveToPoint(context, , );
- CGContextAddLineToPoint(context, , );
- [[UIColor redColor]setStroke];
- CGContextSetLineWidth(context, );
- CGContextDrawPath(context, kCGPathStroke);
- NSString *str=@"Kenshin Cui";
- [str drawInRect:CGRectMake(, , , ) withAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Marker Felt" size:],NSForegroundColorAttributeName:[UIColor redColor]}];
- //返回绘制的新图形
- UIImage *newImage=UIGraphicsGetImageFromCurrentImageContext();
- //最后一定不要忘记关闭对应的上下文
- UIGraphicsEndImageContext();
- //保存图片
- // NSData *data= UIImagePNGRepresentation(newImage);
- // [data writeToFile:@"/Users/kenshincui/Desktop/myPic.png" atomically:YES];
- return newImage;
- }
- @end
运行效果:
注意:上面这种方式绘制的图像除了可以显示在界面上还可以调用对应方法进行保存(代码注释中已经包含保存方法);除此之外这种方法相比在drawRect:方法中绘制图形效率更高,它不用每次展示时都调用所有图形绘制方法。
绘制到PDF
绘制到PDF则要启用pdf图形上下文,PDF图形上下文的创建使用方式跟位图图形上下文是类似的,需要注意的一点就是绘制内容到PDF时需要创建分页,每页内容的开始都要调用一次IGraphicsBeginPDFPage();方法。下面的示例演示了文本绘制和图片绘制(其他图形绘制也是类似的):
- // KCMainViewController.m
- // Quartz2D
- //
- // Created by Kenshin Cui on 14-3-17.
- // Copyright (c) 2014年 Kenshin Cui. All rights reserved.
- //
- #import <CoreText/CoreText.h>
- #import "KCMainViewController.h"
- #import "KCView.h"
- #import "KCView2.h"
- @interface KCMainViewController ()
- @end
- @implementation KCMainViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- [self drawContentToPdfContext];
- }
- #pragma mark 利用pdf图形上下文绘制内容到pdf文档
- -(void)drawContentToPdfContext{
- //沙盒路径(也就是我们应用程序文件运行的路径)
- NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSString *path=[[paths firstObject] stringByAppendingPathComponent:@"myPDF.pdf"];
- NSLog(@"%@",path);
- //启用pdf图形上下文
- /**
- path:保存路径
- bounds:pdf文档大小,如果设置为CGRectZero则使用默认值:612*792
- pageInfo:页面设置,为nil则不设置任何信息
- */
- UIGraphicsBeginPDFContextToFile(path,CGRectZero,[NSDictionary dictionaryWithObjectsAndKeys:@"Kenshin Cui",kCGPDFContextAuthor, nil]);
- //由于pdf文档是分页的,所以首先要创建一页画布供我们绘制
- UIGraphicsBeginPDFPage();
- NSString *title=@"Welcome to Apple Support";
- NSMutableParagraphStyle *style=[[NSMutableParagraphStyle alloc]init];
- NSTextAlignment align=NSTextAlignmentCenter;
- style.alignment=align;
- [title drawInRect:CGRectMake(, , , ) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:],NSParagraphStyleAttributeName:style}];
- NSString *content=@"Learn about Apple products, view online manuals, get the latest downloads, and more. Connect with other Apple users, or get service, support, and professional advice from Apple.";
- NSMutableParagraphStyle *style2=[[NSMutableParagraphStyle alloc]init];
- style2.alignment=NSTextAlignmentLeft;
- // style2.firstLineHeadIndent=20;
- [content drawInRect:CGRectMake(, , , ) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:],NSForegroundColorAttributeName:[UIColor grayColor],NSParagraphStyleAttributeName:style2}];
- UIImage *image=[UIImage imageNamed:@"applecare_folks_tall.png"];
- [image drawInRect:CGRectMake(, , , )];
- UIImage *image2=[UIImage imageNamed:@"applecare_page1.png"];
- [image2 drawInRect:CGRectMake(, , , )];
- //创建新的一页继续绘制其他内容
- UIGraphicsBeginPDFPage();
- UIImage *image3=[UIImage imageNamed:@"applecare_page2.png"];
- [image3 drawInRect:CGRectMake(, , , )];
- //结束pdf上下文
- UIGraphicsEndPDFContext();
- }
- @end
知识补充
1.Core Graphics是基于C语言的一套框架,开发时无法像使用Obj-C一样调用;
2.在Quartz 2D中凡是使用带有“Create”或者“Copy”关键字方法创建的对象,在使用后一定要使用对应的方法释放(由于这个框架基于C语言编写无法自动释放内存);
3.Quartz 2D是跨平台的,因此其中的方法中不能使用UIKit中的对象(UIKit只有iOS可用),例如用到的颜色只能用CGColorRef而不能用UIColor,但是UIKit中提供了对应的转换方法;
4.在C语言中枚举一般以“k”开头,由于Quartz 2D基于C语言开发,所以它也不例外(参数中很多枚举都是k开头的);
5.由于Quartz 2D是Core Graphics的一部分,所以API多数以CG开头;
6.在使用Quartz 2D绘图API中所有以“Ref”结尾对象,在声明时都不必声明为指针类型;
7.在使用Quartz 2D绘图API时,凡是“UI”开头的相关绘图函数,都是UIKit对Core Graphics的封装(主要为了简化绘图操作);
Core Image
利用Quartz 2D我们可以绘制各类图形、图像,功能确实强大。用过photoshop的朋友都知道,使用photoshop可以制作各种滤镜特效,那么在iOS中能否实现滤镜呢?在iOS5.0之前这些算法基本全部要靠程序员编程实现,实现过程相当复杂。从iOS5.0开始苹果官方已经提供了Core Image框架来帮助开发者进行特效制作。
先来看一下滤镜使用过程中常用的基类对象:
CIContext:图像上下文,用于管理整个图片处理过程,不同的图形上下文将利用不同的图像处理硬件进行图像处理(在iOS中可以通过不同的方式创建图像上下文,例如可以创建基于CPU的图像上下方、创建基于GPU的图像上下方以及创建OpenGL优化过的图像上下文)。
CIFilter:图像处理滤镜,每种滤镜有不同的参数设置。
CIImage:Core Image框架中的图像类型,主要用于输入和输出图像。
在使用滤镜之前我们先要弄清平台主要支持哪些滤镜,以及这些滤镜的方法和参数如何设置,此时不妨使用下面的方法进行打印查看:
- #pragma mark 查看所有内置滤镜
- -(void)showAllFilters{
- NSArray *filterNames=[CIFilter filterNamesInCategory:kCICategoryBuiltIn];
- for (NSString *filterName in filterNames) {
- CIFilter *filter=[CIFilter filterWithName:filterName];
- NSLog(@"rfilter:%@rattributes:%@",filterName,[filter attributes]);
- }
- }
在iOS7中打印会发现有127种滤镜,如果我们把每种滤镜都介绍一遍恐怕用几章内容也很难介绍详细,事实上也没有这个必要。这些滤镜使用方法是类似的,只是参数设置有所区别。在iOS文档中可以搜索“core image filter reference”一节的内容,里面有每种滤镜的详细介绍和图片使用效果。
使用Core Image框架创建滤镜效果一般分为以下几步:
1.创建图像上下文CIContext
2.创建滤镜CIFilter
3.创建过滤原图片CIImage
4.调用CIFilter的setValue: forKey:方法为滤镜指定源图片
5.设置滤镜参数【可选】
6.取得输出图片显示或保存
大家都知道在美图秀秀中有一个“增强”功能,利用它可以调整照片的饱和度、亮度、对比度,其实在Core Image中也有这样一款滤镜,下面就以颜色滤镜来演示一下Core Image中滤镜的使用。
- // KCMainViewController.m
- // CoreImage
- //
- // Created by Kenshin Cui on 14-3-17.
- // Copyright (c) 2014年 Kenshin Cui. All rights reserved.
- //
- #import "KCMainViewController.h"
- #define CONSTROLPANEL_FONTSIZE 12
- @interface KCMainViewController (){
- UIImagePickerController *_imagePickerController;//系统照片选择控制器
- UIImageView *_imageView;//图片显示控件
- CIContext *_context;//Core Image上下文
- CIImage *_image;//我们要编辑的图像
- CIImage *_outputImage;//处理后的图像
- CIFilter *_colorControlsFilter;//色彩滤镜
- }
- @end
- @implementation KCMainViewController
- - (void)viewDidLoad {
- [super viewDidLoad];
- [self initLayout];
- }
- #pragma mark 初始化布局
- -(void)initLayout{
- //初始化图片选择器
- _imagePickerController=[[UIImagePickerController alloc]init];
- _imagePickerController.delegate =self;
- //创建图片显示控件
- _imageView=[[UIImageView alloc]initWithFrame:CGRectMake(, , , )];
- _imageView.contentMode=UIViewContentModeScaleAspectFit;
- [self.view addSubview:_imageView];
- //上方导航按钮
- self.navigationItem.title=@"Enhance";
- self.navigationItem.leftBarButtonItem=[[UIBarButtonItem alloc]initWithTitle:@"Open" style:UIBarButtonItemStyleDone target:self action:@selector(openPhoto:)];
- self.navigationItem.rightBarButtonItem=[[UIBarButtonItem alloc]initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(savePhoto:)];
- //下方控制面板
- UIView *controlView=[[UIView alloc]initWithFrame:CGRectMake(, , , )];
- // controlView.alpha=0.2;
- // controlView.backgroundColor=[UIColor colorWithRed:46.0/255.0 green:178.0/255.0 blue:235.0/255.0 alpha:1];
- [self.view addSubview:controlView];
- //饱和度(默认为1,大于饱和度增加小于1则降低)
- UILabel *lbSaturation=[[UILabel alloc]initWithFrame:CGRectMake(, , , )];
- lbSaturation.text=@"Saturation";
- lbSaturation.font=[UIFont systemFontOfSize:CONSTROLPANEL_FONTSIZE];
- [controlView addSubview:lbSaturation];
- UISlider *sldStaturation=[[UISlider alloc]initWithFrame:CGRectMake(, , , )];//注意UISlider高度虽然无法调整,很多朋友会说高度设置位0即可,事实上在iOS7中设置为0后是无法拖动的
- [controlView addSubview:sldStaturation];
- sldStaturation.minimumValue=;
- sldStaturation.maximumValue=;
- sldStaturation.value=;
- [sldStaturation addTarget:self action:@selector(changeStaturation:) forControlEvents:UIControlEventValueChanged];
- //亮度(默认为0)
- UILabel *lbBrightness=[[UILabel alloc]initWithFrame:CGRectMake(, , , )];
- lbBrightness.text=@"Brightness";
- lbBrightness.font=[UIFont systemFontOfSize:CONSTROLPANEL_FONTSIZE];
- [controlView addSubview:lbBrightness];
- UISlider *sldBrightness=[[UISlider alloc]initWithFrame:CGRectMake(, , , )];
- [controlView addSubview:sldBrightness];
- sldBrightness.minimumValue=-;
- sldBrightness.maximumValue=;
- sldBrightness.value=;
- [sldBrightness addTarget:self action:@selector(changeBrightness:) forControlEvents:UIControlEventValueChanged];
- //对比度(默认为1)
- UILabel *lbContrast=[[UILabel alloc]initWithFrame:CGRectMake(, , , )];
- lbContrast.text=@"Contrast";
- lbContrast.font=[UIFont systemFontOfSize:CONSTROLPANEL_FONTSIZE];
- [controlView addSubview:lbContrast];
- UISlider *sldContrast=[[UISlider alloc]initWithFrame:CGRectMake(, , , )];
- [controlView addSubview:sldContrast];
- sldContrast.minimumValue=;
- sldContrast.maximumValue=;
- sldContrast.value=;
- [sldContrast addTarget:self action:@selector(changeContrast:) forControlEvents:UIControlEventValueChanged];
- //初始化CIContext
- //创建基于CPU的图像上下文
- // NSNumber *number=[NSNumber numberWithBool:YES];
- // NSDictionary *option=[NSDictionary dictionaryWithObject:number forKey:kCIContextUseSoftwareRenderer];
- // _context=[CIContext contextWithOptions:option];
- _context=[CIContext contextWithOptions:nil];//使用GPU渲染,推荐,但注意GPU的CIContext无法跨应用访问,例如直接在UIImagePickerController的完成方法中调用上下文处理就会自动降级为CPU渲染,所以推荐现在完成方法中保存图像,然后在主程序中调用
- // EAGLContext *eaglContext=[[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES1];
- // _context=[CIContext contextWithEAGLContext:eaglContext];//OpenGL优化过的图像上下文
- //取得滤镜
- _colorControlsFilter=[CIFilter filterWithName:@"CIColorControls"];
- }
- #pragma mark 打开图片选择器
- -(void)openPhoto:(UIBarButtonItem *)btn{
- //打开图片选择器
- [self presentViewController:_imagePickerController animated:YES completion:nil];
- }
- #pragma mark 保存图片
- -(void)savePhoto:(UIBarButtonItem *)btn{
- //保存照片到相册
- UIImageWriteToSavedPhotosAlbum(_imageView.image, nil, nil, nil);
- UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Sytem Info" message:@"Save Success!" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
- [alert show];
- }
- #pragma mark 图片选择器选择图片代理方法
- -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
- //关闭图片选择器
- [self dismissViewControllerAnimated:YES completion:nil];
- //取得选择图片
- UIImage *selectedImage=[info objectForKey:UIImagePickerControllerOriginalImage];
- _imageView.image=selectedImage;
- //初始化CIImage源图像
- _image=[CIImage imageWithCGImage:selectedImage.CGImage];
- [_colorControlsFilter setValue:_image forKey:@"inputImage"];//设置滤镜的输入图片
- }
- #pragma mark 将输出图片设置到UIImageView
- -(void)setImage{
- CIImage *outputImage= [_colorControlsFilter outputImage];//取得输出图像
- CGImageRef temp=[_context createCGImage:outputImage fromRect:[outputImage extent]];
- _imageView.image=[UIImage imageWithCGImage:temp];//转化为CGImage显示在界面中
- CGImageRelease(temp);//释放CGImage对象
- }
- #pragma mark 调整饱和度
- -(void)changeStaturation:(UISlider *)slider{
- [_colorControlsFilter setValue:[NSNumber numberWithFloat:slider.value] forKey:@"inputSaturation"];//设置滤镜参数
- [self setImage];
- }
- #pragma mark 调整亮度
- -(void)changeBrightness:(UISlider *)slider{
- [_colorControlsFilter setValue:[NSNumber numberWithFloat:slider.value] forKey:@"inputBrightness"];
- [self setImage];
- }
- #pragma mark 调整对比度
- -(void)changeContrast:(UISlider *)slider{
- [_colorControlsFilter setValue:[NSNumber numberWithFloat:slider.value] forKey:@"inputContrast"];
- [self setImage];
- }
- @end
次给大家强调一下:
在上面的代码中除了使用了基于GPU的图像上下文(推荐方式),也创建了其他图像上下文,尽管已经被注释大家还是需要熟悉。
Core Image允许你一次给图像或视频帧叠加多种效果,同时Core Image还能保证强大的处理效率。
和在使用Core Graphics绘图一样,UIKit中也封装了一些方法直接转换为Core Image中的对象,例如UIImage对象可以直接调用CIImage属性转换为CIImage类型。
iOS:iOS开发系列–打造自己的“美图秀秀”(下)的更多相关文章
- iOS开发系列--打造自己的“美图秀秀”
--绘图与滤镜全面解析 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz ...
- iOS开发系列--打造自己的“美图秀秀”
概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz 2D绘制2D图形和Co ...
- iOS:iOS开发系列–打造自己的“美图秀秀”(中)
来源: KenshinCui 链接:http://www.cnblogs.com/kenshincui/p/3959951.html 其他状态设置 常用的图形上下文状态设置上面基本都用到了,我们不再一 ...
- iOS:iOS开发系列–打造自己的“美图秀秀”(上)
来源: KenshinCui 链接:http://www.cnblogs.com/kenshincui/p/3959951.html 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功 ...
- 移动开发在路上-- IOS移动开发系列 多线程二
最近太忙没太多的时间,忙碌的码农生活空下来一点时间,都会挤出来看一些技术或者咨询的文章,废话不多说,直奔主题. 接着上一次的继续说. 定时器在多线程的使用 NSRunLoop 是线程相关的基础框架的一 ...
- Android 快速开发系列 打造万能的ListView GridView 适配器
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38902805 ,本文出自[张鸿洋的博客] 1.概述 相信做Android开发的写 ...
- iOS 图片部分模糊,类似于美图秀秀
代码地址如下:http://www.demodashi.com/demo/14277.html 演示效果 演示效果 代码结构 项目结构截图如下: 该模块的核心源码部分为 MBPartBlurView, ...
- 美图秀秀 web开发图片编辑器
美图秀秀web开发平台 http://open.web.meitu.com/wiki/ 1.环境配置 1.1.设置crossdomain.xml 下载crossdomain.xml文件,把解压出来的c ...
- 利用Photos 框架搭建美图秀秀相册选择器
简介:Photos框架是iOS8.0后推出的一个新的用于对系统相册进行相关操作的,在iOS8.0之前,开发中只能使用AssetsLibrary框架来访问移动设备的图片库.本文中不再对AssetsLib ...
随机推荐
- python中的map、reduce、filter、sorted函数
map.reduce.filter.sorted函数,这些函数都支持函数作为参数. map函数 map() 函数语法:map(function, iterable, ...) function -- ...
- ActiveMQ基于JMS的pub/sub传播机制
原文地址:[ActiveMQ实战]基于JMS的pub/sub传播机制 发布订阅模型 就像订阅报纸,我们可以选择一份或者多份报纸.比如:北京日报.人民日报.这些报纸就相当于发布订阅模型中的topic.如 ...
- 微信小程序 - "锚点"功能的实现
“锚点”功能在实际应用设计的好,可以提高用户体验.今天碰到一个类似下面功能: 由于页面数据比较多,除了做些上拉加载,下拉刷新等优化.还可以进行进行分类,如上图.功能要求:点击导航的菜单,相应页面的分类 ...
- cssBase.css你应该有一个
@charset "utf-8"; /*! * @名称:base.css * @功能:1.重设浏览器默认样式 * 2.设置通用原子类 */ /* 防止用户自定义背景颜色对网页的影响 ...
- Appscan的第一个测试请求就是提交MAC地址
GET /AppScan_fingerprint/MAC_ADDRESS_真实的MAC地址.html HTTP/1.0 还好都是合法测试,否则情何以堪...
- JSTL <c:if test=“eq ne lt..”></if> 用法
类别 运算符 算术运算符 + . - . * . / (或 div )和 % (或 mod ) 关系运算符 == (或 eq ). != (或 ne ). < (或 lt ). > (或 ...
- centos6.5 安装scrapy
1. 安装Twisted, 下载安装包 python setup.py install 2. yum install libffi-devel python-devel 3 pip install s ...
- python之IO model
一.事件驱动模型 在介绍协程时,遇到IO操作就切换,但什么时候切换回来,怎么确定IO操作结束? 很多人可能会考虑使用“线程池”或“连接池”.“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的 ...
- js跨域请求实现
js代码 var url = zfba2url + "/fzyw/xzfy/smcl/autoUpdateByWS.action"; var data = { "writ ...
- ExtJs之列表(grid)
--renderers渲染器 可以格式化该列显示的数据格式或者按照你自定义的脚本显示最终数据样子 先看下renderer: function()里的参数 renderer:function(value ...