update: 2012/07/02
reference:
I touchs: Filter4Cam 學習之 Core Image Tutorial
A. 說明:
先檢查專案是否有加入: AssetsLibrary framework, 如果沒有的話就加入
(之前應該有加入了). AssetsLibrary framework 是用來存取被影像應用程式
所管理的照片或影片.
B. 開啟 ViewController.h 檔案, 修改如下:
....
//@add
#import <AVFoundation/AVFoundation.h>
#import <CoreMedia/CoreMedia.h>
#import <CoreVideo/CoreVideo.h>
#import <QuartzCore/QuartzCore.h>
#import <CoreImage/CoreImage.h>
#import <ImageIO/ImageIO.h>
#import <AssetsLibrary/AssetsLibrary.h>
....
@interface ViewController : GLKViewController <AVCaptureVideoDataOutputSampleBufferDelegate, UITableViewDelegate, UITableViewDataSource>
{
//@add
CIContext *coreImageContext;
CIFilter *coreImageFilter;
CIImage *ciImage;
....
BOOL isUsingFrontCamera;
//@add 設備上一次方向是否為水平擺放(向左或向右皆算)
BOOL isPreviousOrientationLandscape;
BOOL applyFilter; // 是否套用濾鏡
....
}
//@add
@property (strong, nonatomic) EAGLContext *glContext;
@property (strong, nonatomic) CIContext *coreImageContext;
@property (strong, nonatomic) CIFilter *coreImageFilter;
@property (strong, nonatomic) CIImage *ciImage;
....
@property (assign) BOOL isUsingFrontCamera;
@property (assign) BOOL isPreviousOrientationLandscape;
@property (assign) BOOL applyFilter;
....
-----------------------------------------------------------------------------
C. 開啟 ViewController.m 檔案, 修改如下:
....
// step 1:
//@add
@synthesize glContext = _glContext;
@synthesize coreImageContext = _coreImageContext;
@synthesize coreImageFilter = _coreImageFilter;
@synthesize ciImage = _ciImage;
....
@synthesize applyFilter = _applyFilter;
// step 2:
....
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//@add
self.applyFilter = NO;
....
}
// step 3:
....
- (CIImage *)filterTest:(CIImage *)sourceImage
{
/*
CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone" keysAndValues:
kCIInputImageKey, sourceImage,
@"inputIntensity", [NSNumber numberWithFloat:0.8], nil];
return [filter outputImage];
*/
//@add
self.applyFilter = YES;
self.coreImageFilter = [CIFilter filterWithName:@"CISepiaTone" keysAndValues:
kCIInputImageKey, sourceImage,
@"inputIntensity", [NSNumber numberWithFloat:0.8], nil];
return [self.coreImageFilter outputImage];
}
....
// step 4:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
// 將取得的 sampleBuffer 轉成 CVPixelBuffer
CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
//@update: comment it
/*
CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
ciImage = [self orientationTransform:ciImage];
[self.coreImageContext drawImage:ciImage atPoint:CGPointZero fromRect:[ciImage extent]];
ciImage = [self filterTest:ciImage];
[self filterOrientationTransform:ciImage];
*/
//@update: use instance var (ciImage)
// 接著, 將 CVPixelBuffer 利用 Core Image 的初始化方法再轉成 CIImage.
self.ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
//@add:方向轉變的調整
self.ciImage = [self orientationTransform:self.ciImage];
// 然後使用 CIContext 物件將其內容畫到 render buffer
[self.coreImageContext drawImage:self.ciImage atPoint:CGPointZero fromRect:[self.ciImage extent]];
// 濾鏡功能測試
self.ciImage = [self filterTest:self.ciImage];
// e.g. [self.coreImageContext drawImage:self.ciImage
// inRect:CGRectMake(23.5, 123.5, 274, 274) fromRect:[self.ciImage extent]];
[self filterOrientationTransform:self.ciImage];
// 最後, 在螢幕上呈現出來.
[self.glContext presentRenderbuffer:GL_RENDERBUFFER];
}
....
// step 5:
- (void)savePhoto
{
//@TODO
//NSLog(@"savePhoto");
// 從 filter 取得 CIImage 的輸出:
// 不需要再作, 因為 self.ciImage 可能有使用過 filter 或是未套用濾鏡的原始影像
// self.ciImage = [self.coreImageFilter outputImage];
// 產生 CGImageRef
CGImageRef cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:[self.ciImage extent]];
// 將 CGImageRef 儲存到相簿裡
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:cgImage
metadata:[self.ciImage properties]
completionBlock:^(NSURL *assetURL, NSError *error) {
// 釋放 CGImage, 這是一個 callback block, 當處理完畢時才會觸發.
CGImageRelease(cgImage);
}];
}
....
-----------------------------------------------------------------------------
D. 編譯並執行:
拍照畫面:拍照結果:
紅框的範圍內才是套用濾鏡的結果, 而不是整個螢幕.
開啟 ViewController.m 檔案, 修改如下:
....
- (void)savePhoto
{
// 從 filter 取得 CIImage 的輸出:
// 不需要再作, 因為 self.ciImage 可能有使用過 filter 或是未套用濾鏡的原始影像
// self.ciImage = [self.coreImageFilter outputImage];
// 產生 CGImageRef
//CGImageRef cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:[self.ciImage extent]];
CGImageRef cgImage = nil;
//@update for only capture filtered scope
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
//@擷取的濾鏡範圍與 filterOrientationTransform: 中
// drawImage:inRect:fromRect: 裡的 fromRect: 相同
//
// 設備垂直擺放
if (orientation == UIDeviceOrientationPortrait)
{
cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(23, -557.5, 274, 274)];
}
// 設備垂直 180 度擺放
else if (orientation == UIDeviceOrientationPortraitUpsideDown)
{
cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(-458.5, 83, 274, 274)];
}
// 設備水平向右擺放
else if (orientation == UIDeviceOrientationLandscapeRight)
{
cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(-517, -457.5, 274, 274)];
}
// 設備水平向左擺放(最穩定)
else if (orientation == UIDeviceOrientationLandscapeLeft)
{
cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(123.5, 23.5, 274, 274)];
}
// 其它 (UIDeviceOrientationFaceUp, UIDeviceOrientationFaceDown,
// UIDeviceOrientationUnknown)
else {
// 上一次設備為水平擺放
if (self.isPreviousOrientationLandscape == YES)
{
cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(123.5, 23.5, 274, 274)];
}
// 上一次設備為垂直擺放
else
{
cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(23.5, 83.5, 274, 274)];
}
}
// 將 CGImageRef 儲存到相簿裡
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:cgImage
metadata:[self.ciImage properties]
completionBlock:^(NSURL *assetURL, NSError *error) {
// 釋放 CGImage, 這是一個 callback block, 當處理完畢時才會觸發.
CGImageRelease(cgImage);
}];
}
....
-----------------------------------------------------------------------------
F. 編譯並執行
拍照結果:
拍照結果:
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。