作業#49 照片編輯App

目的:練習製作出照片編輯App以及利用UIGraphicsImageRenderer取得編輯後的照片

這次練習模仿手機版LINE的個人主頁,可以點選要編輯變更背景圖片或大頭照然後變更個性簽名,最後可以將自己的個人主頁的畫面截圖並分享出去,本篇文章主要分享主要功能,完整程式碼歡迎點擊最下方GitHub連結~

功能主要運用

  1. 利用UIImagePickerViewController使用拍照功能以及PHPickerViewController使用相簿選圖的功能
  2. 利用CGAffineTransform將圖片鏡像或旋轉
  3. 利用CIFilter讓圖片有濾鏡效果
  4. 利用UIGraphicsImageRenderer截下編輯後的圖片
  5. 利用UIActivityViewController將畫面分享出去

App架構

從個人主頁點選背景圖片或大頭貼,切換到圖片預覽然後點選要拍照或是從相簿內選擇照片,最後進行圖片編輯再用unwindSegue回傳到個人主頁顯示,另外可以點選個性簽名編輯想要的文字或emoji,並一樣回傳顯示到主頁上

個人主頁(左)、個性簽名(中)、圖片預覽及編輯(右)

選圖功能-UIImagePickerViewController、PHPickerViewController

actionSheet

點選編輯圖片的Button後,會先跳出actionSheet讓使用者選擇拍照還是使用相簿中的照片

UIImagePickerViewController

  1. 先檢查裝置中有沒有相機功能才執行生成UIImagePickerViewController
  2. didFinishPickingMediaWithInfo中設定使用者拍下圖片後做什麼事
  3. 從info[.originalImage]取得拍下圖片並轉型成UIImage,並給previewImage這個變數是要用來傳遞到下一個畫面的變數
  4. 使用圖片後把UIImagePickerViewController關掉並切換到下一頁
  5. 但也有可能最後並沒有使用拍到的圖片,那就關掉UIImagePickerViewController

PHPickerViewController

  1. 設定PHPickerConfiguration,filter設定只選取圖片,然後用設定好的Configuration去初始化一個PHPickerViewController並Present出來
  2. 使用delegate的function,didFinishPicking處理使用者選擇到的圖片,先檢查使用者是否有選擇圖片,然後讀取UIImage型別的東西,因為loadObject是在背後運作,所以要讓獲取image的工作在main thread執行,並且dismiss掉PHPickerViewController,切換到編輯圖片頁面
  3. 有可能使用者點開編輯但沒有選擇任何圖片就關掉,因此在判斷是否有選擇到圖片的if let加一個else然後dismiss掉PHPickerViewController

圖片編輯功能-切換比例、旋轉、鏡像、濾鏡效果

view堆疊

  1. 希望最後能將編輯後的圖片區域整個截圖下來,最下層放一個Draw View負責截下包含他裡面的整個畫面,所以需要將其他的view都放進去成為他的subview
  2. 負責旋轉以及鏡像功能的view(RotateView&MirrorView),兩個功能各用一個View,不然會無法同時進行
  3. 最後一個BackView裝負責縮放的scrollView以及ImageView

切換比例

  1. 用segmentedControl讓使用者選擇比例,所以function的參數裡帶入index以及要變化的view
  2. defaultLength在負責編輯圖片功能的類別裡已經先設定好了,然後根據不同的比例去變更寬跟高
  3. 然後將變更後的寬跟高給要變化的view,然後因為要變更比例的view會是最大的draw裡的subview所以代表座標的xy要看的在DrawView裡的位子,那整個View是正方形,所以center剛好是原本寬高的一半,固定center是為了在變更比例後還是停留在中間

旋轉、鏡像

  1. 旋轉設定一個旋轉次數,每次旋轉都+=1這樣才會一直旋轉下去
  2. 鏡像圖片這是設定一個負責鏡像的變數1,讓他每次都*=1在1跟-1切換,來預設跟鏡像的切換

濾鏡

濾鏡功能

  1. function接受兩個參數,傳入要變更的圖片以及濾鏡代表的tag,因為會用button去讓使用者去選擇要替換的濾鏡,這邊就用tag來區分使用者所選擇的濾鏡
  2. 因為傳入的參數是UIImage?,所以先用guard let去取得,然後將它轉換成CIImage
  3. 用switch去判斷使用者選擇的濾鏡名稱去初始化一個CIFilter
  4. 將傳入的圖片變成有濾鏡效果,接著在outputImage可以獲得轉換後的圖片,但這時候獲得的是CIImage,在CIImage轉換回UIImage時會有圖片轉向的問題,所以我們要判斷原圖的方向並把圖片轉向回去,方法下方會分享Peter的文章,對詳細有興趣的歡迎點擊
  5. 然後轉換回UIImage並回傳

使用濾鏡

  1. 在controller上使用的function,帶入button的tag作為參數並回傳UIImage?
  2. 這個function也是在編輯圖片功能的類別裡,這個類別有一個image負責在接受要編輯的圖片作為原圖
  3. 根據使用者選擇的button去變更濾鏡

截圖-UIGraphicsImageRenderer

  1. 這個function因為個人主頁也會用到因此我把它寫在extension內
  2. 傳入要截圖的view,回傳UIImage
  3. 先告訴UIGraphicsImageRenderer要截圖的位子跟大小,然後用.drawHierarchy去做截圖,然後回傳截下來的UIImage

分享畫面-UIActivityViewController

  1. 先將整個個人主頁截圖下來
  2. 初始化UIActivityViewController並讓他分享的是截下來的圖片
  3. 使用completionWithItemHandler,獲得是否分享成功並跳出alert提醒使用者

操作畫面

濾鏡變更跟利用scrollView縮放圖片,在實機操作沒問題但不知道為什麼模擬機上無法動作🥲

分享到line上

練習心得:

整個作業做完花了四天,中間卡了有點久差點崩潰,還好問了一下Peter後很多問題就解開了,最困難的部分我覺得是調整圖片比例的部分,搞了很久我認為主要對View的操作還不夠熟悉,其實最後發現真的沒有這麼難就是觀念的問題要再多多練習

文章參考連結:

GitHub連結:

--

--