來源: 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類型。