轉載:http://talentwsc.blog.163.com/blog/static/68743076201231322844508/
在ios開發中,肯定會碰到需要截取部分圖片的情況。
最終的效果類似這樣:
先看最原始的示例,顯示完整的圖片
寫了個最簡單的讀取圖片並顯示的代碼,打算以此為開始,逐漸實現截取部分圖片的功能。
代碼主要是,在控制器代碼中:
- (void)loadView {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlid e];
UIImage *image=[UIImage imageNamed:@"1.jpg"];
UIImageView *contentView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[contentView setImage:image];
self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.view addSubview:contentView];
}
另外,應該有一個名為1.jpg的768×1024的圖片(我這里是iPad)。
截取整個圖片
可以認為截取整個圖片是截取部分圖片的一個特例。對ios不熟嘛,因此打算很謹慎的推進。截取整個圖片可以減少中間的復雜性。
根據API,摸索着寫了一個示例,效果出乎意料:
代碼:
- (void)loadView {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlid e];
UIImage *image=[UIImage imageNamed:@"1.jpg"];
UIImageView *contentView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
//[contentView setImage:image];
CGRect rect = CGRectMake(0, 0, 768, 1024);//創建矩形框
UIGraphicsBeginImageCont ext(rect.size);//根據size大小創建一個基於位圖的圖形上下文
CGContextRef currentContext = UIGraphicsGetCurrentCont ext();//獲取當前quartz 2d繪圖環境
CGContextClipToRect( currentContext, rect);//設置當前繪圖環境到矩形框
CGContextDrawImage(currentContext, rect, image.CGImage);//繪圖
UIImage *cropped = UIGraphicsGetImageFromCu rrentImageContext();//獲得圖片
UIGraphicsEndImageContex t();//從當前堆棧中刪除quartz 2d繪圖環境
contentView.image=cropped;
self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.view addSubview:contentView];
[cropped release];
}
這個代碼說明了兩點:
- 好的方面:說明我的代碼起作用了,確實截取了所需的圖形
- 壞的方面:圖形是顛倒的,而且是鏡像的。
問題應該出在坐標系上。下面畫了一個quartz 2d的坐標系,坐標原點在左下角:
因此以這個坐標系取圖形,就會有轉向180°的效果。
其實如果是對圖片的縮放,而不是剪切部分圖片內容,這樣寫就可以了:
- (void)loadView {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlid e];
UIImage *image=[UIImage imageNamed:@"1.jpg"];
//[contentView setImage:image];
CGRect rect = CGRectMake(0, 0, 384, 512);//創建矩形框
UIGraphicsBeginImageCont ext(rect.size);//根據size大小創建一個基於位圖的圖形上下文
CGContextRef currentContext = UIGraphicsGetCurrentCont ext();//獲取當前quartz 2d繪圖環境
CGContextClipToRect(currentContext, rect);//設置當前繪圖環境到矩形框
//CGContextRotateCTM(currentContext, 50);
//CGContextDrawImage(currentContext, rect, image.CGImage);//繪圖
[image drawInRect:rect];
UIImage *cropped = UIGraphicsGetImageFromCu rrentImageContext();//獲得圖片
UIGraphicsEndImageContex t();//從當前堆棧中刪除quartz 2d繪圖環境
UIImageView *contentView = [[UIImageView alloc] initWithFrame:rect];
contentView.image=cropped;
self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.view addSubview:contentView];
[cropped release];
}
效果類似這樣:
這個方法可以幫助我們在后續開發中實現縮略圖。但是不符合現在的需求。
於是想了下面的基本思路:
這樣,需要一個能旋轉和向下移動的API。ios提供了C++界面的函數調用:
- CGContextRotateCTM,實現角度的轉換
- CGContextTranslateCTM,可以重新設置坐標系原點,平移坐標系和移動圖片是等效的
代碼:
- (void)loadView {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlid e];
UIImage *image=[UIImage imageNamed:@"1.jpg"];
//[contentView setImage:image];
CGRect rect = CGRectMake(0, 0, 384, 512);//創建矩形框
UIGraphicsBeginImageCont ext(rect.size);//根據size大小創建一個基於位圖的圖形上下文
CGContextRef currentContext = UIGraphicsGetCurrentCont ext();//獲取當前quartz 2d繪圖環境
CGContextClipToRect(currentContext, rect);//設置當前繪圖環境到矩形框
CGContextRotateCTM(currentContext, M_PI);
CGContextTranslateCTM(currentContext, -rect.size.width, -rect.size.height);
CGContextDrawImage(currentContext, rect, image.CGImage);//繪圖
//[image drawInRect:rect];
UIImage *cropped = UIGraphicsGetImageFromCu rrentImageContext();//獲得圖片
UIGraphicsEndImageContex t();//從當前堆棧中刪除quartz 2d繪圖環境
UIImageView *contentView = [[UIImageView alloc] initWithFrame:rect];
contentView.image=cropped;
self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.view addSubview:contentView];
[cropped release];
}
這個結果還有缺陷,可以看到圖片是正立的了,但是圖片反轉了,是個鏡像。
解決辦法也有,不過不是操作圖片了,而是操作圖片所在的視圖。思路是把視圖看作一個位圖的矩陣,對它做矩陣變換運算,使視圖做鏡像反轉。寫法很簡單:
- (void)loadView {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlid e];
UIImage *image=[UIImage imageNamed:@"1.jpg"];
//[contentView setImage:image];
CGRect rect = CGRectMake(0, 0, 384, 512);//創建矩形框
UIGraphicsBeginImageCont ext(rect.size);//根據size大小創建一個基於位圖的圖形上下文
CGContextRef currentContext = UIGraphicsGetCurrentCont ext();//獲取當前quartz 2d繪圖環境
CGContextClipToRect(currentContext, rect);//設置當前繪圖環境到矩形框
CGContextRotateCTM(currentContext, M_PI);
CGContextTranslateCTM(currentContext, -rect.size.width, -rect.size.height);
//CGContextTranslateCTM(currentContext,0.0,200.0);
CGContextDrawImage(currentContext, rect, image.CGImage);//繪圖
//[image drawInRect:rect];
UIImage *cropped = UIGraphicsGetImageFromCu rrentImageContext();//獲得圖片
UIGraphicsEndImageContex t();//從當前堆棧中刪除quartz 2d繪圖環境
UIImageView *contentView = [[UIImageView alloc] initWithFrame:rect];
contentView.image=cropped;
contentView.transform = CGAffineTransformIdentit y;
contentView.transform = CGAffineTransformMakeSca le(-1.0, 1.0);
self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.view addSubview:contentView];
[cropped release];
}
這里的轉換因子,一個是針對x軸的,一個是針對y軸的。終於可以產生這樣的效果了:
這里參考了這個文檔:
雖然是很古老的文章了,但是說的很清楚。另外,方法名稱已經發生變化,需要注意。
截取部分圖片
截取部分圖片,比如:
截取左邊人像部分。
實現后的代碼,效果是這樣的:
如何實現的呢,這時候才發現,其實根本不需要上面那些轉換,如果不使用quartz 2d的話,截取部分圖片這么簡單:
- (void)loadView {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation: UIStatusBarAnimationSlid e];
UIImage *image=[UIImage imageNamed:@"1.jpg"];
CGRect rect = CGRectMake(60, 80, 331, 353);//創建矩形框
UIImageView *contentView = [[UIImageView alloc] initWithFrame:rect];
contentView.image=[UIImage imageWithCGImage:CGImageCreateWithImageIn Rect([image CGImage], rect)];
self.view=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.view addSubview:contentView];
[image release];
}
雖然編寫代碼的過程是曲折的,但是摸到很多有用的東西,都是以后要用到的。