2014年7月19日 星期六

GPUImage 滿漢大餐:序



這次是 GPUImage 的全套教學,
我會想這麼做的原因是,最近我有在用 GPUImage 開發一個 app,
但是在開發的過程中發現 GPUImage 的中文資源貧乏,並且它自己的說明文件也不齊全,
所以就想說我自己來做這一整套的教學了,不過這個教學是沒有截止的期限 XDD,
因此最好祈禱我不要中途而費。

什麼是 GPUImage?

GPUImage 是一個第三方的 API,
它整合了 OpenGL 與 AVFoundation,
並且支援 iOS 與 Mac 雙平台,
為了做到 Apple 一直不想做的濾鏡 (Filter) 的功能,

為什麼做是 Apple 不想做了?
因為根據 CoreImage 的 Framework 所提供的 CIFilter 只能做到一些陽春的濾鏡效果,
並且可修改的參數一大堆,導致開發者要一次又一次的測試,才能做出一個滿意的濾鏡較果,
這中間需要消耗大量個時間去做測試,這不是任何一位開發者願意看到的結果。

而 GPUImage 做到了,它提供更容易使用的環境,
並且結合了 AVFoundation 的相機、影像播放等功能、
讓開發者能做出一個相機的 app 並且能同時使用濾鏡做即時預覽的功能,
這是它強大之處。

章節

首先我先大概說明 GPUImage 的章節內容,
GPUImage 分為靜態圖像與動態影片兩個部分,
所以大章節就用這兩個做區分。

  1. 基礎上手篇:
    1. 下載 GPUImage
    2. 編譯成 Framework 來使用
  2. 相機篇:
    1. 做一個你自己的相機,用 GPUImage
    2. 用濾鏡處理你的相片
  3. 錄影篇:
    1. 來個即時濾鏡的攝影機,並且錄下你的生活
    2. 將你的生活影片染上不同的顏色與效果吧

目前是打算這麼做,
未來這一篇文章將會成為後續文章的索引,
當有後續文章出來之後我會將它加上連結,
方便大家使用。

2014年6月16日 星期一

Block in Swift

第一次學習 Block 就上手中教了在 Objective-C 的 Block 作法,
不過在 Swift 裡的作法又變了一個,所以才做了這個教學,
其實 Swift 的 Block 不叫做 Block,叫做 Closures,
它是一個將 Method 當做一個變數使用的應用。

一般的宣告方法如下
var aClosures: (NSString) -> Void = {string in
	NSLog("String: %@", string)
}

Closures 比較特別的是基本宣告都是宣告傳入或傳出的變數型態,
型態所對應變數名稱是在實作的時候才給予,這在基本宣告的時候還可以,
不過下面這個宣告方法就有可能看不懂了。

將 Closures 定義成一個型態之後再宣告
typealias bClosures = (NSNumber!) -> Void

var _bClosures:bClosures = {number in
	 NSLog("Number: %@", number)
;}

這時候如果不看這個型態內部定義的變數的話,就會完全不懂 number 這個變數是啥型態了,
這只能說 Swift 的風格特殊了。

接下來,有宣告當然就要有實作 Closures 的 Method,
其實實作 Method 的方法與 Block 的實作 Method 差異比較小,也可以說作法幾乎是相同的。

func methodWithaClosures(aClosures:(NSString) -> Void)
{
	NSLog("String: %@", string)
}

func methodWithbClosures(closures:bClosures)
{
	closures(NSNumber.numberWithInteger(150))
}

有實作了 Method,這時候就要回到上面將宣告好的 Closures 傳進去了。

var aClosures: (NSString) -> Void = {string in
	NSLog("String: %@", string)
}

typealias bClosures = (NSNumber!) -> Void

var _bClosures:bClosures = {number in
	 NSLog("Number: %@", number)
;}

self.methodWithaClosures(aClosures)

self.methodWithbClosures(_bClosures)

教學就到這邊,下次再看看有哪個東西需要教的了。

2014年5月15日 星期四

Class Method (三):Signleton 改 - 在多執行續的解法

在上一篇文章的 Class Method (二):Signleton 有在多執行續使用上的問題,
所以追加教學在多執行續中的 Signleton 的作法。

在舊的 signleton 的作法是這個樣子:
+ (id)method
{
	static Method *singleton = nil;
	if (singleton == nil) {
		singleton = [[Method alloc] init];
	}
	return singleton;
}

這在多執行續之下會有每個執行續都建立一個相同的 signleton 的問題,
所以要避免這個問題,就需要改寫 signleton 的寫法。

新個寫法如下,利用 GCD 的 dispatch_once 的方法來確保,
不管在哪個執行續下都是只有一個 signleton 的物件存在。
+ (id)method
{
	static Method *singleton = nil;
	
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		singleton = [DTFileController new];
	});
	
	return singleton;
}

2014年5月1日 星期四

從圖片檔案讀取 EXIF 資訊

這次是要如何從檔案中讀取一個 EXIF 資訊回來,
EXIF 是保存由相機拍攝下來的資料,
所以通常只要是相機拍的數位相片都有這項資訊,
但是要怎麼取出這些資訊了?
作法請看下面的教學

首先這個教學需要使用 ImageIO 的 framework,所以自己要實作的時候要記得將他 import 進來。

- (NSDictionary *)imagePropertiesWithPath:(NSString *)path
{
	// 將檔案的路徑轉成 NSURL 物件
	NSURL *imageFileURL = [NSURL fileURLWithPath:path];
	// 讀取這個檔案的資訊
	CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)imageFileURL, NULL);
	
	/* 設定準備讀資料的選項,這裡是不要將檔案使用快取的方式,
		這是避免檔案過大,而消耗過多記憶體空間的問題。 */
	NSDictionary *options = @{(id)kCGImageSourceShouldCache: @(NO)};
	
	// 從檔案資訊中擷取關於圖片的資料
	CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (CFDictionaryRef)options);
	
	CFRelease(imageSource);
	
	return (NSDictionary *)imageProperties;
}

- (void)viewDidLoad
{
	~
	// 取得剛剛的圖片資訊
	NSDictionary *imageProperties = [self imagePropertiesWithPath:_filePath];
	
	// 再從中取出 EXIF 資訊
	NSDictionary *EXIFInformation = imageProperties[(id)kCGImagePropertyExifDictionary];
	
	// 取出 EXIF Auxiliary 資訊
	NSDictionary *EXIFAuxiliary   = imageProperties[(id)kCGImagePropertyExifAuxDictionary];
	
	~
}

這樣子就能取得 EXIF 資訊,另外還有 GPS 資訊也是可以在 imageProperties 中取得,
另外,這次的範例檔:https://github.com/Darktt/EXIF-Reader
範例檔的使用方法,建議使用模擬器,先執行過一次,在 Log 中能找到

**** Directory Path: 

這個資訊,這後面就是接著你要放數位照片的路徑,
請用 Finder 打開這個路徑,放入你要讀取的照片,
重新執行這個程式,這時候就會讀到這張照片的檔名了。