2012年7月26日 星期四

Clean Install OS X Mountain Lion

since: 2012/07/26
update: 2012/07/29

reference:
1. How to Clean Install OS X Mountain Lion
2. Create an OS X Mountain Lion Installation Boot DVD or USB Drive with LionDiskMaker

A. 取得 OS X Mountain Lion
     從 Mac App Store - OS X Mountain Lion 購買(NT$590)並下載,
     但是先不要安裝.

----------------------------------------------------------------------

B. 製作 Mountain Lion 系統磁碟
     1. 說明: 先嘗試製作成 DVD系統安裝片, 無論使用之前的方式, 或
                   Lion Diskmaker 軟體, 都會說 4.7GB 空間不足, 但是放入 8.5GB 的
                   空白DVD 片, 到最後都燒錄失敗, 也可能是空白片本身的問題, 因此,
                   決定改成製作 USB 系統磁碟.

     2. 先將「應用程式」內的「安裝 OS X Mountain Lion.app」拷貝至桌面.

     3. 將至少 8GB 的 USB 放入 Mac 的 USB 插槽, 下載最新版本的
          Lion DiskMaker. (在此為: 2.0rc2)

     4. 承上, 解壓縮至桌面後, 執行: Lion Diskmaker 2rc2.app 檔案.

     5. 選擇製作成開機磁碟的 Mac OS X 版本:
          Mountain Lion (10.8)

     6. 選擇桌面上的 "安裝 OS X Mountain Lion.app" 檔案.

     7. 選擇 "創建安裝磁盤"

     8. 選擇磁盤種類:
          8GB 的 USB 隨身碟

     9. 選定該USB 隨身碟.

     10. 警示: 磁碟的整個內容將被擦除.
           擦除並創建安裝磁盤.

     11. 進行拷貝過程.

     12. 完成了, 按下: 退出

     13. 完成後的 USB 隨身碟內容.

----------------------------------------------------------------------

C.安裝 Mountain Lion
    1. 將 USB 隨身碟與 Mac 連接好, 重新開機並按下 "Option" 鍵,
        從開機選單選澤有 "Mountain Lion" 圖示的磁碟.

    2. 以繁體中文作為主要的語言.

    3. 選取磁碟工具程式 > 選擇要格式化的硬碟 > 切換到 "清除" 頁籤
         > 在 "格式" 項目, 選擇: "Mac OS 擴充格式 (日誌式) "
         > 輸入磁碟名稱


    4. 按下 "清除" (這是無法回復的點)

    5. 完成後, 離開磁碟工具程式.

    6. 選擇 "重新安裝 OS X" > 繼續 > 同意 > 同意

    7. 選取剛才格式化好的磁碟機, 並開始安裝.

    8. 安裝完成.


----------------------------------------------------------------------

D. 備註
    
1. 裝了以下的軟體:
          uTorrent, aMule, ToyViewer, Paintbrush, TextWrangler,
          Adium, Line, Core Data Editor, Icon Maker, FireFox, Xcode,
          Google Driver, Sophos Anti-Virus, Opengl Extension Viewer,
          MPlayerX, iExplorer, QREncoder, XMarks (for FireFox & Safari),
          CleanMyMac, AVerTV, OmniGraffle Professional, TheUnarchiver,
          PlistEdit Pro, Toast, Photoshop CS5, Cog, Paragon NTFS for Mac

     2. 終端機模式下, 用 Mac 的文字編輯器開啟某個檔案的方式:
          $ sudo /Applications/TextEdit.app/Contents/MacOS/TextEdit /etc/hosts
            
           編輯後存檔:
           command + s

           刷新快取內容:
           $ sudo dscacheutil -flushcache

2012年7月25日 星期三

Filter4Cam 實作: 24. 影像方向調整之五

since: 2012/07/25
update: 2012/07/25

reference:
1. The iOS 5 Developer's Cookbook, 3/e

拍照

A. 說明:
     1. 要產生的圖片, 不需要再次從 filter 取得 CIImage 的輸出:
         self.ciImage = [self.coreImageFilter outputImage], 直接使用 self.ciImage 即可, 
         因為 self.ciImage 會在之前的處理過程中, 採用原始影像套用濾鏡.

     2. ALAssetOrientation 的值, 可有以下 8 種:
         ALAssetOrientationUp;
         ALAssetOrientationUpMirrored; 
         ALAssetOrientationDown;
         ALAssetOrientationDownMirrored;
         ALAssetOrientationRight;
         ALAssetOrientationRightMirrored;
         ALAssetOrientationLeft;
         ALAssetOrientationLeftMirrored;

     3. "擷取的濾鏡影像範圍"(fromRect:) 與 drawFilteredImage: 方法中,
          drawImage:inRect:fromRect: 裡的 fromRect: 設定值相同

     4. 使用 ALAssetsLibraryCGImageRef 儲存到相簿裡的函式有二個:
          a. writeImageToSavedPhotosAlbum:metadata:completionBlock:
          b. writeImageToSavedPhotosAlbum:orientation:completionBlock:

     5. 依照 "設備擺放方向", "前後置鏡頭" 與 "設備上次擺放方向" 來調整
         產生圖片的方向.

-----------------------------------------------------------------------------

B. 開啟 ViewController.m 檔案, 修改如下:
....
//@update: "拍照": 只截取濾鏡範圍的影像
- (void)savePhoto
{   
    // 產生 CGImageRef
    CGImageRef cgImage = nil;
   
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
   
    ALAssetOrientation ALAOrientation = ALAssetOrientationUp;
       
    // ################################################# //
    // A. 設備擺放方向為: "垂直" 或 "垂直 180 度" 或 "水平向右" 或 "水平向左" //
    // ################################################# //
    if (orientation == UIDeviceOrientationPortrait ||
        orientation == UIDeviceOrientationPortraitUpsideDown ||
        orientation == UIDeviceOrientationLandscapeRight ||
        orientation == UIDeviceOrientationLandscapeLeft)
    { 
        ///////////////////////////////////////
        // 1. 擷取濾鏡影像範圍
        //
       
        // 設備垂直擺放
        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 ||
                 orientation == UIDeviceOrientationLandscapeLeft)
        {
            cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(123.5, 23.5, 274, 274)];
        }
       
        ///////////////////////////////////////
        // 2. "前置鏡頭" 影像方向
        //
       
        // 前置鏡頭
        if (self.isUsingFrontCamera)
        {           
            // 設備水平向左擺放
            if (orientation == UIDeviceOrientationLandscapeLeft)
            {
                ALAOrientation = ALAssetOrientationDownMirrored;
            }
            // 其它: 垂直, 垂直 180 度, 水平向右
            else
            {
                ALAOrientation = ALAssetOrientationUpMirrored;
            }
           
            // 將 CGImageRef 儲存到相簿裡
            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
           
            [library writeImageToSavedPhotosAlbum:cgImage orientation:ALAOrientation
                                  completionBlock:^(NSURL *assetURL, NSError *error) {
                                     
                              // 釋放 CGImage, 這是一個 callback block, 當處理完畢時才會觸發.
                                      CGImageRelease(cgImage);
                                  }];
        }
       
        ///////////////////////////////////////
        // 3. "後置鏡頭" 影像方向
        //
       
        // 後置鏡頭
        else
        {
            // 設備水平向右擺放
            if (orientation == UIDeviceOrientationLandscapeRight)
            {              
                ALAOrientation = ALAssetOrientationDown;
               
                // 將 CGImageRef 儲存到相簿裡
                ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
               
                [library writeImageToSavedPhotosAlbum:cgImage orientation:ALAOrientation
                                      completionBlock:^(NSURL *assetURL, NSError *error) {
                                         
                                  // 釋放 CGImage, 這是一個 callback block, 當處理完畢時才會觸發.
                                          CGImageRelease(cgImage);
                                      }];
            }
            // 其它: 垂直, 垂直 180 度, 水平向左  
            else {
                // 將 CGImageRef 儲存到相簿裡
                ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
               
                [library writeImageToSavedPhotosAlbum:cgImage
                                             metadata:[self.ciImage properties]
                                      completionBlock:^(NSURL *assetURL, NSError *error) {
                                         
                                    // 釋放 CGImage, 這是一個 callback block, 當處理完畢時才會觸發.
                                          CGImageRelease(cgImage);
                                      }];
            }
        }
    }
    // ############################### //
    // B. 設備擺放方向為: "朝上" 或 "朝下" 或 "未知" //
    // ############################### //
    else if(orientation == UIDeviceOrientationFaceUp ||
            orientation == UIDeviceOrientationFaceDown ||
            orientation == UIDeviceOrientationUnknown)
    {
        ///////////////////////////////////////
        // 1. 擷取濾鏡影像範圍
        //
       
        // 上次為直擺
        if (lastOrientation == Portrait)
        {
            cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(23, -557.5, 274, 274)];
        }
        // 上次為直擺且上下顛倒
        else if (lastOrientation == PortraitUpsideDown)
        {
            cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(-458.5, 83.5, 274, 274)];
        }
        // 上次為 "橫擺朝右" 或上次為 "橫擺朝左"
        else if (lastOrientation == LandscapeRight ||
                   lastOrientation == LandscapeLeft)   

        {
            cgImage = [self.coreImageContext createCGImage:self.ciImage fromRect:CGRectMake(123.5, 23.5, 274, 274)];
        }
        else
        {
            NSLog(@"savePhoto: orientation = FaceUp/FaceDown/Unknown, lastOrientation not defined!");
        }


        ///////////////////////////////////////
        // 2. "前置鏡頭" 影像方向
        //
       
        if (self.isUsingFrontCamera)
        {           
            // 上次為 "橫擺朝左"
            if (lastOrientation == LandscapeLeft)
            {
                ALAOrientation = ALAssetOrientationDownMirrored;
            }
            // 其它: 上次為 "直擺", "直擺且上下顛倒" 或 "橫擺朝右"
            else
            {
                ALAOrientation = ALAssetOrientationUpMirrored;
            }
           
            // 將 CGImageRef 儲存到相簿裡
            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
           
            [library writeImageToSavedPhotosAlbum:cgImage orientation:ALAOrientation
                                  completionBlock:^(NSURL *assetURL, NSError *error) {
                                     
                              // 釋放 CGImage, 這是一個 callback block, 當處理完畢時才會觸發.
                                      CGImageRelease(cgImage);
                                  }];
        }

        ///////////////////////////////////////
        // 3. "後置鏡頭" 影像方向
        //
       
        // 後置鏡頭
        else
        {
            // 上次為 "橫擺朝右"
            if (lastOrientation == LandscapeRight)    
            {              
                ALAOrientation = ALAssetOrientationDown;
               
                // 將 CGImageRef 儲存到相簿裡
                ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
               
                [library writeImageToSavedPhotosAlbum:cgImage orientation:ALAOrientation
                                      completionBlock:^(NSURL *assetURL, NSError *error) {
                                         
                                    // 釋放 CGImage, 這是一個 callback block, 當處理完畢時才會觸發.
                                          CGImageRelease(cgImage);
                                      }];
            }
            else {
                // 將 CGImageRef 儲存到相簿裡
                ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
               
                [library writeImageToSavedPhotosAlbum:cgImage
                                             metadata:[self.ciImage properties]
                                      completionBlock:^(NSURL *assetURL, NSError *error) {
                                         
                                  // 釋放 CGImage, 這是一個 callback block, 當處理完畢時才會觸發.
                                          CGImageRelease(cgImage);
                                      }];
            }
        }
    }
    else
    {
        NSLog(@"savePhoto: No orientation match!");
    }
}
....

-----------------------------------------------------------------------------

C. 編譯並執行:

     1. 先將 buttonView 的 backgroundColor 註解後, 再編譯並執行.
     // ViewController.m
....
// 用來放所有按鈕的 View
- (UIView *)buttonView
{
    if (_buttonView == nil) {
        _buttonView = [[UIView alloc] init];
        //@測試使用
        //_buttonView.backgroundColor = [UIColor redColor];    
    }
   
    return _buttonView;
}
....

     2. 設備水平向右擺放:
         (相機鏡頭在右後方, 功能按鈕遠離相機鏡頭位置)

     3. 拍照結果:

Filter4Cam 實作: 23. 影像方向調整之四

since: 2012/07/25
update: 2012/07/25

reference:
1. The iOS 5 Developer's Cookbook, 3/e

畫出 "濾鏡範圍" 內的影像

A. 說明:
     修改原本的 drawFilteredImage: 方法, 主要調整:
     1. "設備水平向右擺放" 時的, 繪製來源區塊(fromRect)與目的區塊(inRect)位置.

     2. 對 "設備朝上擺放", "設備朝下擺放" 或 "設備擺放方向未知" 的情況, 加入依據
         "上次設備的擺放方向" 來作調整的處理.

------------------------------------------------------------------------

B. 開啟 ViewController.m 檔案, 修改如下:

....
// 畫出 "濾鏡範圍" 內的影像(含方向轉變的調整)
- (void)drawFilteredImage:(CIImage *)filteredImage
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
   
    // ############# //
    // A. 設備垂直擺放 //
    // ############# //
    if (orientation == UIDeviceOrientationPortrait)
    {       
        [self.coreImageContext drawImage:filteredImage inRect:CGRectMake(23.5, 83.5, 274, 274)
                                // x 越小, 濾鏡越向右; y 負越多, 濾鏡越向上
                                fromRect:CGRectMake(23.5, -557.5, 274, 274)];
    }
    // #################### //
    // B. 設備垂直 180 度擺放 //
    // #################### //
    else if (orientation == UIDeviceOrientationPortraitUpsideDown)
    {       
        [self.coreImageContext drawImage:filteredImage inRect:CGRectMake(23.5, 83.5, 274, 274)
                                // x 負越多, 濾鏡越向左; y 越多, 濾鏡越向上
                                fromRect:CGRectMake(-458.5, 83.5, 274, 274)];
    }
    // ####################################### //
    // C. "設備水平向右擺放" 或 "設備水平向左擺放" //
    // ####################################### //
    else if (orientation == UIDeviceOrientationLandscapeRight ||
             orientation == UIDeviceOrientationLandscapeLeft)
    {       
        [self.coreImageContext drawImage:filteredImage inRect:CGRectMake(123.5, 23.5, 274, 274)
                                // x 越大, 濾鏡越向左; y 越多, 濾鏡越向下
                                fromRect:CGRectMake(123.5, 23.5, 274, 274)];
    }
    // ################################################### //
    // D. "設備朝上擺放" 或 "設備朝下擺放" 或 "設備擺放方向未知" //
    // #################################################### //
    else if (orientation == UIDeviceOrientationFaceUp ||
             orientation == UIDeviceOrientationFaceDown ||
             orientation == UIDeviceOrientationUnknown)
    {       
        // case 1: 上次為直擺
        if (lastOrientation == Portrait)
        {
            [self.coreImageContext drawImage:filteredImage inRect:CGRectMake(23.5, 83.5, 274, 274)
                                    // x 越大, 濾鏡越向左; y 越多, 濾鏡越向上
                                    fromRect:CGRectMake(23.5, -557.5, 274, 274)];
        }
        // case 2: 上次為直擺且上下顛倒
        else if (lastOrientation == PortraitUpsideDown)
        {
             [self.coreImageContext drawImage:filteredImage inRect:CGRectMake(23.5, 83.5, 274, 274)
                                    // x 負越多, 濾鏡越向左; y 越多, 濾鏡越向上
                                    fromRect:CGRectMake(-458.5, 83.5, 274, 274)];
        }
        // case 3: 上次為 "橫擺朝右" 或 case 4: 上次為 "橫擺朝左"
        else if (lastOrientation == LandscapeRight || lastOrientation == LandscapeLeft)   
        {
            [self.coreImageContext drawImage:filteredImage inRect:CGRectMake(123.5, 23.5, 274, 274)
                                    // x 越大, 濾鏡越向左; y 越多, 濾鏡越向上
                                    fromRect:CGRectMake(123.5, 23.5, 274, 274)];
        }
        else
        {
            NSLog(@"drawFilteredImage: orientation = FaceUp/FaceDown/Unknown, lastOrientation not defined!");
        }
    }
    else
    {
        NSLog(@"drawFilteredImage: No orientation match!");
    }
}
....

2012年7月24日 星期二

Filter4Cam 實作: 22. 影像方向調整之三

since: 2012/07/24
update: 2012/07/24

reference:
1. The iOS 5 Developer's Cookbook, 3/e

轉換原始影像的方向

A. 說明:
     1. 將原本的 orientationTransform: 方法, 整個內容全部重寫. 在設備不同的
         擺放情形中, 增加前後鏡頭切換的判斷. 

     2. 調整當 "設備水平向右擺放" 時, 原本 "按鈕功能" 會靠近相機鏡頭位置,
         改成 "按鈕功能" 遠離相機鏡頭位置.

     3. 當 "設備面朝上",  "設備面朝下" 或 "設備方向未知" 時, 加入依據 "上次設備
         的擺放方向" 來作調整的處理.

     4. 在這裡, 同時使用了 CGAffineTransform(仿射轉換) 與 CATransform3D(3D 轉換)
         來作影像方向的調整. 原本希望能只用 CATransform3D 來處理就好, 但沒有測試
         成功, 因此整個程式碼看起來瑣碎而複雜.

    5. 調整的要領是: 先利用 "仿射轉換的旋轉角度" 搭配 "GLKView 作 3D 旋轉",
        來使得螢幕上呈現的影像為正向(包含: 上下, 左右), 接著再來調整 "濾鏡表單"
        與 "功能按鈕" 的呈現.

-----------------------------------------------------------------------------

B. 開啟 ViewController.m 檔案, 修改如下:
....
// 轉換原始影像的方向
- (CIImage *)orientationTransform:(CIImage *)sourceImage
{
    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
    CGAffineTransform affineTransform = CGAffineTransformIdentity; // 仿射轉換
    CATransform3D transform3D = CATransform3DIdentity; // 3D 轉換
   
    // Debug: 由於在 shouldAutorotateToInterfaceOrientation:
    //               中無法偵測到這三個方向,

    //               & 當上一次設備的方向為此三種情況時, 不記錄
    if (orientation == UIDeviceOrientationFaceUp) {
        NSLog(@" -> FaceUp");
        //lastOrientation = FaceUp; // 記錄為上次: 面朝上
    }
    if (orientation == UIDeviceOrientationFaceDown) {
        NSLog(@" ---> FaceDown");
        //lastOrientation = FaceDown; // 記錄為上次: 面朝下
    }
    if (orientation == UIDeviceOrientationUnknown) {
        NSLog(@" -----> Unknown");
        //lastOrientation = Unknown; // 記錄為上次: 未知
    }
   
    // ############# //
    // A. 設備垂直擺放 //
    // ############## //
    if (orientation == UIDeviceOrientationPortrait)
    {        
        // 上次為前置鏡頭, 本次為前置鏡頭
        if (self.isLastFrontCamera && self.isUsingFrontCamera)
        {            
            // 將 GLKView, TableView 與 buttonView 對 Y 軸作 180 度旋轉
            transform3D = CATransform3DMakeRotation(M_PI, 0.0f, 1.0f, 0.0f);
            self.glView.layer.transform = transform3D;
            self.filterListTableView.layer.transform = transform3D;
            self.buttonView.layer.transform = transform3D;
        }
        // 上次為後置鏡頭, 本次為後置鏡頭
        else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
        {                    
            // 將 GLKView 對 Z 軸作 180 度旋轉
            transform3D = CATransform3DMakeRotation(M_PI, 0.0f, 0.0f, 1.0f);
            self.glView.layer.transform = transform3D;
           
            // 對 Z 軸作 180 度旋轉為基準, 將 GLKView 對 X 軸作 180 度旋轉
            transform3D = CATransform3DRotate(transform3D, M_PI, 1.0f, 0.0f, 0.0f);
            self.glView.layer.transform = transform3D;

            // 對 Z 軸作 180 度旋轉, 再對 X 軸作 180 度旋轉為基準,
            // 將 GLKView 對 Y 軸作 180 度旋轉
            self.glView.layer.transform = CATransform3DRotate(transform3D, M_PI, 0.0f, 1.0f, 0.0f);
           
            // 將 TableView 與 buttonView 轉成單位矩陣
            self.filterListTableView.layer.transform = CATransform3DIdentity;
            self.buttonView.layer.transform = CATransform3DIdentity;
        }
        // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
        else
        {
            self.isLastFrontCamera = !self.isLastFrontCamera;
        }
       
        // 仿射轉換, 並將輸入角度轉成弧度 (直接輸入 -M_PI /2 亦可)
        affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(-90.0));
    }
    // #################### //
    // B. 設備垂直 180 度擺放 //
    // #################### //
    else if (orientation == UIDeviceOrientationPortraitUpsideDown)
    {
        // 上次為前置鏡頭, 本次為前置鏡頭
        if (self.isLastFrontCamera && self.isUsingFrontCamera)
        {            
            // 將 GLKView, TableView 與 buttonView 對 Y 軸作 180 度旋轉
            transform3D = CATransform3DMakeRotation(M_PI, 0.0f, 1.0f, 0.0f);
            self.glView.layer.transform = transform3D;
            self.filterListTableView.layer.transform = transform3D;
            self.buttonView.layer.transform = transform3D;
           
            // 將 GLKView 對 X 軸作 180 度旋轉
            self.glView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0f, 0.0f, 0.0f);
        }
        // 上次為後置鏡頭, 本次為後置鏡頭
        else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
        {                  
            // 將 TableView 與 buttonView 轉成單位矩陣
            self.filterListTableView.layer.transform = CATransform3DIdentity;
            self.buttonView.layer.transform = CATransform3DIdentity;
           
            // 將 GLKView 對 Z 軸作 180 度旋轉
            self.glView.layer.transform = CATransform3DMakeRotation(M_PI, 0.0f, 0.0f, 1.0f);
        }
        // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
        else
        {
            self.isLastFrontCamera = !self.isLastFrontCamera;
        }
       
        affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(90.0));
    }
    // ################# //
    // C. 設備水平向右擺放 //
    // ################# //
    else if (orientation == UIDeviceOrientationLandscapeRight)
    {
        // 上次為前置鏡頭, 本次為前置鏡頭
        if (self.isLastFrontCamera && self.isUsingFrontCamera)
        {                  
            // "按鈕功能" 靠近相機鏡頭(不採用)
            /*
            // 將 GLKView 對 Z 軸作 90 度旋轉
            transform3D = CATransform3DMakeRotation(M_PI/2, 0.0f, 0.0f, 1.0f);
            self.glView.layer.transform = transform3D;
           
            // 對 Z 軸作 90 度旋轉為基準, 將 GLKView 與 TableView 對 Y 軸作 180 度旋轉
            transform3D = CATransform3DRotate(transform3D, M_PI, 0.0f, 1.0f, 0.0f);
            self.glView.layer.transform = transform3D;
            self.filterListTableView.layer.transform = transform3D;
           
            // 以單位矩陣為基準, 將 buttonView 對 X 軸作 180 度旋轉
            self.buttonView.layer.transform = CATransform3DRotate(CATransform3DIdentity, M_PI, 1.0f, 0.0f, 0.0f);
            */
           
            // "按鈕功能" 遠離相機鏡頭(採用此方式)
            // a. 以單位矩陣為基準, 將 GLKView 對 Z 軸作 90 度旋轉
            transform3D = CATransform3DRotate(CATransform3DIdentity, M_PI/2, 0.0f, 0.0f, 1.0f);
            self.glView.layer.transform = transform3D;

            // 以 a. 為基準, 將 GLKView 對 X 軸作 180 度旋轉
            self.glView.layer.transform = CATransform3DRotate(transform3D, M_PI, 1.0f, 0.0f, 0.0f);
           
            // 以 a. 為基準, 將 TableView 對 X 軸作 180 度旋轉
            self.filterListTableView.layer.transform = CATransform3DRotate(transform3D, M_PI, 1.0f, 0.0f, 0.0f);

            // 以單位矩陣為基準, 將 buttonView 對 Y 軸作 180 度旋轉
            self.buttonView.layer.transform = CATransform3DRotate(CATransform3DIdentity, M_PI, 0.0f, 1.0f, 0.0f);
        }
        // 上次為後置鏡頭, 本次為後置鏡頭
        else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
        {      
            // "按鈕功能" 靠近相機鏡頭 (不採用)
            /*
            // 將 TableView 對 Z 軸作 90 度旋轉
            transform3D = CATransform3DMakeRotation(M_PI/2, 0.0f, 0.0f, 1.0f);
            self.filterListTableView.layer.transform = transform3D;
           
            // 對 Z 軸作 90 度旋轉為基準, 將 GLKView 對 X 軸作 180 度旋轉
            transform3D = CATransform3DRotate(transform3D, M_PI, 1.0f, 0.0f, 0.0f);
            self.glView.layer.transform = transform3D;
           
            // 對 Z 軸作 90 度旋轉, 再對 X 軸作 180 度旋轉為基準,
            // 將 GLKView 對 Y 軸作 180 度旋轉
            transform3D = CATransform3DRotate(transform3D, M_PI, 0.0f, 1.0f, 0.0f);
            self.glView.layer.transform = transform3D;
           
            // 以單位矩陣為基準, 將 buttonView 對 Z 軸作 90 度旋轉
            self.buttonView.layer.transform = CATransform3DRotate(transform3D, M_PI/2, 0.0f, 0.0f, 1.0f);
            */

            // "按鈕功能" 遠離相機鏡頭(採用此方式)
            // 以單位矩陣為基準, 將 GLKView 對 Z 軸作 90 度旋轉
            transform3D = CATransform3DRotate(CATransform3DIdentity, M_PI/2, 0.0f, 0.0f, 1.0f);
            self.glView.layer.transform = transform3D;
           
            // 以單位矩陣為基準, 將 TableView 對 Z 軸作 -90 度旋轉
            self.filterListTableView.layer.transform = CATransform3DRotate(CATransform3DIdentity, -M_PI/2, 0.0f, 0.0f, 1.0f);
           
            // 以單位矩陣為基準, 將 buttonView 對 Z 軸作 180 度旋轉
            self.buttonView.layer.transform = CATransform3DRotate(CATransform3DIdentity, M_PI, 0.0f, 0.0f, 1.0f);
        }
        // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
        else
        {
            self.isLastFrontCamera = !self.isLastFrontCamera;
        }
       
        // "按鈕功能" 靠近相機鏡頭(不採用)
        //affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(180.0));
        // "按鈕功能" 遠離相機鏡頭(採用此方式)
        affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
    }
    // ################# //
    // D. 設備水平向左擺放 //
    // ################# //
    else if (orientation == UIDeviceOrientationLandscapeLeft)
    {  
        // 上次為前置鏡頭, 本次為前置鏡頭
        if (self.isLastFrontCamera && self.isUsingFrontCamera)
        {                       
            // 將 GLKView 對 Z 軸作 -90 度旋轉
            transform3D = CATransform3DMakeRotation(-M_PI/2, 0.0f, 0.0f, 1.0f); 
            self.glView.layer.transform = transform3D;
           
            // 對 Z 軸作 -90 度旋轉為基準, 將 GLKView 對 Y 軸作 -180 度旋轉
            transform3D = CATransform3DRotate(transform3D, -M_PI, 0.0f, 1.0f, 0.0f);
            self.glView.layer.transform = transform3D;
           
            // 對 Z 軸作 -90 度旋轉, 再對 Y 軸作 -180 度旋轉為基準,
            // 將 TableView 對 Z 軸作 -180 度旋轉
            transform3D = CATransform3DRotate(transform3D, -M_PI, 0.0f, 0.0f, 1.0f);
            self.filterListTableView.layer.transform = transform3D;

            // 以單位矩陣為基準, 將 buttonView 對 X 軸作 -180 度旋轉
            self.buttonView.layer.transform = CATransform3DRotate(CATransform3DIdentity, -M_PI, 1.0f, 0.0f, 0.0f);
        }
        // 上次為後置鏡頭, 本次為後置鏡頭
        else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
        {                         
            // 將 GLKView 對 Z 軸作 -90 度旋轉
            transform3D = CATransform3DMakeRotation(-M_PI/2, 0.0f, 0.0f, 1.0f);
            self.glView.layer.transform = transform3D;
           
            // 對 Z 軸作 -90 度旋轉為基準, 將 GLKView 對 X 軸作 -180 度旋轉
            transform3D = CATransform3DRotate(transform3D, -M_PI, 1.0f, 0.0f, 0.0f);
            self.glView.layer.transform = transform3D;
           
            // 對 Z 軸作 -90 度旋轉, 再對 X 軸作 -180 度旋轉為基準,
            // 將 GLKView 與 TableView 對 Y 軸作 -180 度旋轉
            transform3D = CATransform3DRotate(transform3D, -M_PI, 0.0f, 1.0f, 0.0f);
            self.glView.layer.transform = transform3D;
            self.filterListTableView.layer.transform = transform3D;
           
            // 將 buttonView 轉成單位矩陣
            self.buttonView.layer.transform = CATransform3DIdentity;
        }
        // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
        else
        {
            self.isLastFrontCamera = !self.isLastFrontCamera;
        }
       
        affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
    }
    // ###################### //
    // E. 設備面朝上或設備面朝下 //
    // ###################### //
    else if (orientation == UIDeviceOrientationFaceUp ||
                orientation == UIDeviceOrientationFaceDown)
    {
        ////////////////////////////////////////
        // case 1: 上次為直擺
        //
        if (lastOrientation == Portrait)
        {
            // 上次為前置鏡頭, 本次為前置鏡頭
            if (self.isLastFrontCamera && self.isUsingFrontCamera)
            {
                // 將 GLKView 對 Z 軸作 -180 度旋轉
                transform3D = CATransform3DMakeRotation(-M_PI, 0.0f, 0.0f, 1.0f);
                self.glView.layer.transform = transform3D;
               
                // 對 Z 軸作 -180 度旋轉為基準,
                // 將 GLKView , TableView 與 buttonView 對 X 軸作 -180 度旋轉
                transform3D = CATransform3DRotate(transform3D, -M_PI, 1.0f, 0.0f, 0.0f);
                self.glView.layer.transform = transform3D;
                self.filterListTableView.layer.transform = transform3D;
                self.buttonView.layer.transform = transform3D;
            }
            // 上次為後置鏡頭, 本次為後置鏡頭
            else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
            {
                // 將 GLKView 對 Z 軸作 -180 度旋轉
                transform3D = CATransform3DMakeRotation(-M_PI, 0.0f, 0.0f, 1.0f);
                self.glView.layer.transform = transform3D;
               
                // 對 Z 軸作 -180 度旋轉為基準, 將 GLKView 對 X 軸作 -180 度旋轉
                transform3D = CATransform3DRotate(transform3D, -M_PI, 1.0f, 0.0f, 0.0f);
                self.glView.layer.transform = transform3D;
               
                // 對 Z 軸作 -180 度旋轉, 再對 X 軸作 -180 度旋轉為基準,
                // 將 GLKView, TableView 與 buttonView 對 Y 軸作 -180 度旋轉
                transform3D = CATransform3DRotate(transform3D, -M_PI, 0.0f, 1.0f, 0.0f);
                self.glView.layer.transform = transform3D;
                self.filterListTableView.layer.transform = transform3D;
                self.buttonView.layer.transform = transform3D;
            }
            // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
            else
            {
                self.isLastFrontCamera = !self.isLastFrontCamera;
            }
           
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(-90.0));
        }
       
        ////////////////////////////////////////
        // case 2: 上次為直擺且上下顛倒
        //
        else if (lastOrientation == PortraitUpsideDown)
        {
            // 上次為前置鏡頭, 本次為前置鏡頭
            if (self.isLastFrontCamera && self.isUsingFrontCamera)
            {               
                // 將 GLKView 對 Z 軸作 -180 度旋轉
                transform3D = CATransform3DMakeRotation(-M_PI, 0.0f, 0.0f, 1.0f);
                self.glView.layer.transform = transform3D;
               
                // 對 Z 軸作 -180 度旋轉為基準, 將 GLKView 對 Y 軸作 -180 度旋轉
                self.glView.layer.transform = CATransform3DRotate(transform3D, -M_PI, 0.0f, 1.0f, 0.0f);
               
                // 以單位矩陣為基準, 將 TableView 與 buttonView 對 Y 軸作 -180 度旋轉
                transform3D = CATransform3DRotate(CATransform3DIdentity, -M_PI, 0.0f, 1.0f, 0.0f);
                self.filterListTableView.layer.transform = transform3D;
                self.buttonView.layer.transform = transform3D;
            }
            // 上次為後置鏡頭, 本次為後置鏡頭
            else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
            {               
                // 將 GLKView, TableView 與 buttonView 轉成單位矩陣
                self.glView.layer.transform = CATransform3DIdentity;
                self.filterListTableView.layer.transform = CATransform3DIdentity;
                self.buttonView.layer.transform = CATransform3DIdentity;
               
                // 將 GLKView 對 X 軸作 -180 度旋轉
                transform3D = CATransform3DMakeRotation(-M_PI, 1.0f, 0.0f, 0.0f);
                self.glView.layer.transform = transform3D;
               
                // 對 X 軸作 -180 度旋轉為基準,
                // 將 GLKView 對 Y 軸作 -180 度旋轉
                self.glView.layer.transform = CATransform3DRotate(transform3D, -M_PI, 0.0f, 1.0f, 0.0f);
            }
            // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
            else
            {
                self.isLastFrontCamera = !self.isLastFrontCamera;
            }
           
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(90.0));
        }

        ////////////////////////////////////////
        // case 3: 上次為橫擺朝右
        //         (與 "設備水平向右擺放" 設定相同)
        else if (lastOrientation == LandscapeRight)
        {
            // 上次為前置鏡頭, 本次為前置鏡頭
            if (self.isLastFrontCamera && self.isUsingFrontCamera)
            {      
                // a. 以單位矩陣為基準, 將 GLKView 對 Z 軸作 90 度旋轉
                transform3D = CATransform3DRotate(CATransform3DIdentity, M_PI/2, 0.0f, 0.0f, 1.0f);
                self.glView.layer.transform = transform3D;
               
                // 以 a. 為基準, 將 GLKView 對 X 軸作 180 度旋轉
                self.glView.layer.transform = CATransform3DRotate(transform3D, M_PI, 1.0f, 0.0f, 0.0f);
               
                // 以 a. 為基準, 將 TableView 對 X 軸作 180 度旋轉
                self.filterListTableView.layer.transform = CATransform3DRotate(transform3D, M_PI, 1.0f, 0.0f, 0.0f);
               
                // 以單位矩陣為基準, 將 buttonView 對 Y 軸作 180 度旋轉
                self.buttonView.layer.transform = CATransform3DRotate(CATransform3DIdentity, M_PI, 0.0f, 1.0f, 0.0f);
            }
            // 上次為後置鏡頭, 本次為後置鏡頭
            else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
            {                        
                // 以單位矩陣為基準, 將 GLKView 對 Z 軸作 90 度旋轉
                transform3D = CATransform3DRotate(CATransform3DIdentity, M_PI/2, 0.0f, 0.0f, 1.0f);
                self.glView.layer.transform = transform3D;
               
                // 以單位矩陣為基準, 將 TableView 對 Z 軸作 -90 度旋轉
                self.filterListTableView.layer.transform = CATransform3DRotate(CATransform3DIdentity, -M_PI/2, 0.0f, 0.0f, 1.0f);
               
                // 以單位矩陣為基準, 將 buttonView 對 Z 軸作 180 度旋轉
                self.buttonView.layer.transform = CATransform3DRotate(CATransform3DIdentity, M_PI, 0.0f, 0.0f, 1.0f);
            }
            // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
            else
            {
                self.isLastFrontCamera = !self.isLastFrontCamera;
            }
           
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
        }       
       
        ////////////////////////////////////////
        // case 4: 上次為橫擺朝左
        //
        else if (lastOrientation == LandscapeLeft)
        {
            // 上次為前置鏡頭, 本次為前置鏡頭
            if (self.isLastFrontCamera && self.isUsingFrontCamera)
            {  
                // a. 以單位矩陣為基準, 將 GLKView 對 Z 軸作 90 度旋轉
                transform3D = CATransform3DRotate(CATransform3DIdentity, M_PI/2, 0.0f, 0.0f, 1.0f);
                self.glView.layer.transform = transform3D;
               
                // 以 a. 為基準, 將 TableView 對 Y 軸作 180 度旋轉  
                self.filterListTableView.layer.transform = CATransform3DRotate(transform3D, M_PI, 0.0f, 1.0f, 0.0f);
               
                // 以 a. 為基準, 將 GLKView 對 X 軸作 -180 度旋轉
                self.glView.layer.transform = CATransform3DRotate(transform3D, -M_PI, 1.0f, 0.0f, 0.0f);
               
                // 以單位矩陣為基準, 將 buttonView 對 X 軸作 -180 度旋轉
                self.buttonView.layer.transform = CATransform3DRotate(CATransform3DIdentity, -M_PI, 1.0f, 0.0f, 0.0f);
            }
            // 上次為後置鏡頭, 本次為後置鏡頭
            else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
            {        
                // 以單位矩陣為基準, 將 GLKView 與 TableView 對 Z 軸作 90 度旋轉
                transform3D = CATransform3DRotate(CATransform3DIdentity, M_PI/2, 0.0f, 0.0f, 1.0f);
                self.glView.layer.transform = transform3D;
                self.filterListTableView.layer.transform = transform3D;
               
                // 將 buttonView 轉成單位矩陣
                self.buttonView.layer.transform = CATransform3DIdentity;
            }
            // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
            else
            {
                self.isLastFrontCamera = !self.isLastFrontCamera;
            }
           
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
        }
        else
        {
            NSLog(@"orientationTransform: orientation = FaceUp/FaceDown, lastOrientation not defined!");
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
        }
    }
    // ############## //
    // F. 設備方向未知 //
    // ############## //
    else if (orientation == UIDeviceOrientationUnknown)
    {
        ////////////////////////////////////////
        // case 1: 上次為直擺
        //
        if (lastOrientation == Portrait)
        {
            // 上次為前置鏡頭, 本次為前置鏡頭
            if (self.isLastFrontCamera && self.isUsingFrontCamera)
            {
                // Do Nothing
            }
            // 上次為後置鏡頭, 本次為後置鏡頭
            else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
            {
                // Do Nothing
            }
            // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
            else
            {
                self.isLastFrontCamera = !self.isLastFrontCamera;
            }
           
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(-90.0));
        }
       
        ////////////////////////////////////////
        // case 2: 上次為直擺且上下顛倒
        //
        else if (lastOrientation == PortraitUpsideDown)
        {
            // 上次為前置鏡頭, 本次為前置鏡頭
            if (self.isLastFrontCamera && self.isUsingFrontCamera)
            {               
                // Do Nothing
            }
            // 上次為後置鏡頭, 本次為後置鏡頭
            else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
            { 
                // Do Nothing
            }
            // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
            else
            {
                self.isLastFrontCamera = !self.isLastFrontCamera;
            }
           
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(90.0));
        }
       
        ////////////////////////////////////////
        // case 3: 上次為橫擺朝右
        //         (與 "設備水平向右擺放" 設定相同)
        else if (lastOrientation == LandscapeRight)
        {
            // 上次為前置鏡頭, 本次為前置鏡頭
            if (self.isLastFrontCamera && self.isUsingFrontCamera)
            {   
                // Do Nothing
            }
            // 上次為後置鏡頭, 本次為後置鏡頭
            else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
            {     
                // Do Nothing
            }
            // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
            else
            {
                self.isLastFrontCamera = !self.isLastFrontCamera;
            }
           
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
        }       
       
        ////////////////////////////////////////
        // case 4: 上次為橫擺朝左
        //
        else if (lastOrientation == LandscapeLeft)
        {
            // 上次為前置鏡頭, 本次為前置鏡頭
            if (self.isLastFrontCamera && self.isUsingFrontCamera)
            {  
                // Do Nothing
            }
            // 上次為後置鏡頭, 本次為後置鏡頭
            else if (!self.isLastFrontCamera && !self.isUsingFrontCamera)
            {      
                // Do Nothing
            }
            // "前置切換成後置鏡頭" 或 "後置切換成前置鏡頭"
            else
            {
                self.isLastFrontCamera = !self.isLastFrontCamera;
            }
           
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
        }
        else
        {
            NSLog(@"orientationTransform: orientation = Unknown, lastOrientation not defined!");
            affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
        }
    }
    else
    {
        NSLog(@"orientationTransform: No orientation match!");
        affineTransform = CGAffineTransformMakeRotation(DegreesToRadians(0.0));
    }
   
    return [sourceImage imageByApplyingTransform:affineTransform];
}
....