iOS:iOS开发系列–打造本身的“美图秀秀”(下)

来源: KenshinCui   html

连接:http://www.cnblogs.com/kenshincui/p/3959951.html程序员

运行效果:算法

 

其余图形上下文编程

前面咱们也说过,Quartz 2D的图形上下方除了能够绘制到层上还能够绘制到位图、PDF等,这里咱们就介绍一下如何利用Quartz 2D绘制图像到位图及PDF中。app

上面的示例中一直都是在drawRect:方法中利用UIGraphicsGetCurrentContext()方法取得上下文,要获得位图或者PDF的上下文能够利用UIGraphicsBeginImageContext(CGSize size)和UIGraphicsBeginPDFPageWithInfo(CGRect bounds, NSDictionary *pageInfo)方法。位图图形上下文和PDF图形上下文UIKit是不会负责建立的,因此须要用户手动建立,而且在使用完后关闭它。在使用UIKit中系统建立的图形上下文的时候,咱们只能在drawRect:方法中使用,因为这两类图形上下文是由咱们手动建立的所以能够放到任何方法中调用。此外,这两个方法开启的图形上下文并无返回值,若是咱们要获得咱们建立的图形上下文只要在建立上下文以后、关闭以前调用UIGraphicsGetCurrentContext()方法,此时取得的上下文便是咱们本身建立的图形上下文。框架

 

绘制到位图ide

下面利用位图图形上下文给一个图片添加水印,在下面的程序中咱们首先建立上下文,而后在上下文中绘制图片、直线和文本,最后从当前位图上下文中取得最终造成的新图片显示到界面。函数

//  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(160, 284);
 
    [self.view addSubview:imageView];
}
 
#pragma mark 利用位图上下文添加水印效果
-(UIImage *)drawImageAtImageContext{
    //得到一个位图图形上下文
    CGSize size=CGSizeMake(300, 188);//画布大小
    UIGraphicsBeginImageContext(size);
 
    UIImage *image=[UIImage imageNamed:@"photo2.png"];
    [image drawInRect:CGRectMake(0, 0, 300, 188)];//注意绘图的位置是相对于画布顶点而言,不是屏幕
 
    //添加水印
    CGContextRef context=UIGraphicsGetCurrentContext();
    CGContextMoveToPoint(context, 200, 178);
    CGContextAddLineToPoint(context, 270, 178);
 
    [[UIColor redColor]setStroke];
    CGContextSetLineWidth(context, 2);
 
    CGContextDrawPath(context, kCGPathStroke);
 
    NSString *str=@"Kenshin Cui";
    [str drawInRect:CGRectMake(200, 158, 100, 30) withAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Marker Felt" size:15],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(26, 20, 300, 50) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:18],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(26, 56, 300, 255) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15],NSForegroundColorAttributeName:[UIColor grayColor],NSParagraphStyleAttributeName:style2}];
 
    UIImage *image=[UIImage imageNamed:@"applecare_folks_tall.png"];
    [image drawInRect:CGRectMake(316, 20, 290, 305)];
 
    UIImage *image2=[UIImage imageNamed:@"applecare_page1.png"];
    [image2 drawInRect:CGRectMake(6, 320, 600, 281)];
 
    //建立新的一页继续绘制其余内容
    UIGraphicsBeginPDFPage();
    UIImage *image3=[UIImage imageNamed:@"applecare_page2.png"];
    [image3 drawInRect:CGRectMake(6, 20, 600, 629)];
 
    //结束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(0, 64, 320, 502)];
    _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(0, 450, 320, 118)];
//    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(10, 10, 60, 25)];
    lbSaturation.text=@"Saturation";
    lbSaturation.font=[UIFont systemFontOfSize:CONSTROLPANEL_FONTSIZE];
    [controlView addSubview:lbSaturation];
    UISlider *sldStaturation=[[UISlider alloc]initWithFrame:CGRectMake(80, 10, 230, 30)];//注意UISlider高度虽然没法调整,不少朋友会说高度设置位0便可,事实上在iOS7中设置为0后是没法拖动的
    [controlView addSubview:sldStaturation];
    sldStaturation.minimumValue=0;
    sldStaturation.maximumValue=2;
    sldStaturation.value=1;
    [sldStaturation addTarget:self action:@selector(changeStaturation:) forControlEvents:UIControlEventValueChanged];
    //亮度(默认为0)
    UILabel *lbBrightness=[[UILabel alloc]initWithFrame:CGRectMake(10, 40, 60, 25)];
    lbBrightness.text=@"Brightness";
    lbBrightness.font=[UIFont systemFontOfSize:CONSTROLPANEL_FONTSIZE];
    [controlView addSubview:lbBrightness];
    UISlider *sldBrightness=[[UISlider alloc]initWithFrame:CGRectMake(80, 40, 230, 30)];
    [controlView addSubview:sldBrightness];
    sldBrightness.minimumValue=-1;
    sldBrightness.maximumValue=1;
    sldBrightness.value=0;
    [sldBrightness addTarget:self action:@selector(changeBrightness:) forControlEvents:UIControlEventValueChanged];
    //对比度(默认为1)
    UILabel *lbContrast=[[UILabel alloc]initWithFrame:CGRectMake(10, 70, 60, 25)];
    lbContrast.text=@"Contrast";
    lbContrast.font=[UIFont systemFontOfSize:CONSTROLPANEL_FONTSIZE];
    [controlView addSubview:lbContrast];
    UISlider *sldContrast=[[UISlider alloc]initWithFrame:CGRectMake(80, 70, 230, 30)];
    [controlView addSubview:sldContrast];
    sldContrast.minimumValue=0;
    sldContrast.maximumValue=2;
    sldContrast.value=1;
    [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类型。

相关文章
相关标签/搜索