๋์๋ณด๋ฉฐ
์์น ๊ณผ์ ์ ์์ํ๊ณ ๋ฒ์จ 30๋ฒ์งธ TIL์ด๋ค. (1, 2์ผ์ฐจ TIL์ ์ด์ฉ๋ค ๋ณด๋ ๋นผ๋จน๊ฒ ๋์์ง๋ง) ์ฐธ ์๊ฐ ๋น ๋ฅด๋ค... ์ฒ์์๋ ์๋ฒฝํ๊ฒ ์ฐ๊ณ ์ถ์ด์ ๋ฏธ๋ฃจ๋ค๊ฐ ์ ๋ง ๋ง์ด ๋ฐ๋ ธ์๋๋ฐ ์ด๋ฌ๋ค๊ฐ ํ๋๋ ๋ชป ์ธ ๊ฒ ๊ฐ์์ ๊ฐ๋จํ๊ฒ ํ๊ธฐํด ๋๋ ๊ฑฐ ์งค๋งํ๊ฒ ์ฌ๋ฆฌ๋ ํํ๋ก ๋ฐ๊พธ์๋ค. ๋์ค์ ๋ค์ ์ฐพ์๋ณผ ์ ์๋ ํค์๋๋ฅผ ๋ชจ์๋์๋ค๊ณ ์๊ฐํ๋ฉด ์ถฉ๋ถํ ์ข์ ์์ฐ์ด ๋์ง ์์๊น ์ถ๋ค. (30์ผ์ฐจ๊น์ง ๊ทธ๋๋ ๋ช ์ ์ ์ผ๋ ค๊ณ ๋ ธ๋ ฅํ ๊ฒ์ ์นญ์ฐฌํ๋ค.)
์ฌ๊ธฐ์ ์์ฒด ํผ๋๋ฐฑ์ ํ์๋ฉด, TIL์ ๊ทธ๋ ๊ทธ๋ ์ฐ๋๊ฒ ๋ฒ ์คํธ์ธ ๊ฒ ๊ฐ๊ณ ํค์๋๊ฐ ์๋ค๋ฉด ๊ทธ์ ๋ํด ๊ณ ๋ฏผํ๋ ๋์ ์๊ฐ์ ์ต๋ํ ๋ง์ด ์ ๋ ๋ฐฉ์์ผ๋ก ๋ณด์ํด๋๊ฐ๋ ค๊ณ ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ฝ๋ ์กฐ๊ฐ๋ ๋ง์ด ๋ชจ์๋์ผ๋ฉด ์ข๊ฒ ๋ค๊ณ ์๊ฐ์ด ๋ ๋ค. ์ฌ์ค 30์ผ์ฐจ๊น์ง์ TIL์ ๋ด์ฉ์ ์ฑ์๋ฃ๊ธฐ์ ๊ธ๊ธํ๋ ๊ฒ ๊ฐ๊ณ , ๊น์ด๊ฐ ๋ง์ด ๋ถ์กฑํ ๊ฒ ๊ฐ๋ค. ๊ทธ๋์ ๋ญ๊ฐ ์๊ธฐ ํฉ๋ฆฌํํ๋ฉด์ ๋๋ฌด ๋ง์ด ๋ํํด์ก๋ ๊ฒ ๊ฐ๊ณ ์๊ฐ๋ ๋ง ์ด ๊ฒ ๊ฐ๋ค. ์กฐ๊ธ ๋ ์๊ฒฉํ๊ฒ ๋๋ฅผ ํต์ ํ๊ณ , ์ค๊ฐ ์ค๊ฐ ๋ณต์ต ๋ชป ํ๋ ๋ด์ฉ ๊ผญ ์กฐ๊ธ์ฉ์ด๋ผ๋ ๋ณด์ํด๋๊ฐ๋ณด์.
์์์ ํ๋ฆ๋๋ก ๋ช ์ ์ ์ผ๋ฉด์
๋ฏธ๋์ด ๊ด๋ จ
- ์ฌ์ง ์ดฌ์
- ๊ฐค๋ฌ๋ฆฌ ์ ๊ทผ
- ๊ฐค๋ฌ๋ฆฌ ์ ์ฅ
๐ UIImagePickerController - ์ปค์คํ
๋ถ๊ฐ, ์ฌ์ง ์ดฌ์
๐ฅ AVFoundation - ์ปค์คํ
(๋ฏธ๋์ด ๊ด๋ จํ ์ธ๋ถ ์ฒ๋ฆฌ)
๐ PHPickerViewController - iOS 14์ด์, ๊ฐค๋ฌ๋ฆฌ ์ ๊ทผ, ๊ฐค๋ฌ๋ฆฌ ์ ์ฅ, ๋ค์ค ์ ํ
YPImagePicker
- ์ธ์คํ ๊ทธ๋จ๊ณผ ๊ฐ์ ์ด๋ฏธ์ง, ๋น๋์ค ํผ์ปค
- Third-party ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ๊ธฐ๋ณธ ImagePicker๋ ์ปค์คํ ์ด ์ ํ์ ์ด๊ธฐ ๋๋ฌธ์, ์์ ๊ธฐํ ๋ฐ ๊ท๋ชจ ๋ฑ์ ๋ณด๊ณ ์ ์ ํ๊ฒ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํ๋๋ก ํ์.
- TLPhotoPicker๋ผ๊ณ ๋ ๋ง์ด ์ฐ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ค. ๊ทธ๋ฌ๋ YPImagePicker๊ฐ ๋ ๋ง์ด ์ฐ์ธ๋ค๊ณ ํ๋ค.
์์ธํ ์๋ ๋ฐฉ๋ฒ์ ๊ณต์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋๋ก ํ์.
let picker = YPImagePicker()
picker.didFinishPicking { [unowned picker] items, _ in
if let photo = items.singlePhoto {
print(photo.fromCamera) // Image source (camera or library)
print(photo.image) // Final image selected by the user
print(photo.originalImage) // original image selected by the user, unfiltered
print(photo.modifiedImage) // Transformed image, can be nil
print(photo.exifMeta) // Print exif meta data of original image.
self.imageView.image = photo.image
}
picker.dismiss(animated: true, completion: nil)
}
present(picker, animated: true, completion: nil)
UIImagePickerController
iOS 14.0 ์ด์ ๋ถํฐ๋ ๊ฐค๋ฌ๋ฆฌ ์ ๊ทผ, ์ ์ฅ ๊ฐ์ ๊ฒฝ์ฐ๋ PHPickerViewController๋ฅผ ์ด์ฉํ๋๋ก ํ์.
์นด๋ฉ๋ผ
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
return
}
picker.sourceType = .camera
picker.allowsEditing = true // ํธ์งํ๋ฉด ๋ฑ์ฅ
present(picker, animated: true)
์จ๋ฒ
guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else {
return
}
picker.sourceType = .photoLibrary
picker.allowsEditing = false // ํธ์งํ๋ฉด ๏ฟฝX
present(picker, animated: true)
์ฌ์ง ์ ์ฅ
if let image = imageView.image {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
๋ธ๋ฆฌ๊ฒ์ดํธ ๋ฉ์๋
๊ธฐ๋ณธ์ ์ผ๋ก UIImagePickerController๋ ๋ค๋น๊ฒ์ด์ ์ปจํธ๋กค๋ฌ๋ฅผ ์์ ๋ฐ๊ณ ์๋ค. ๊ทธ๋์ ์๋์ UINavigationControllerDelegate๋ ํจ๊ป ์ฑํํด์ฃผ๊ณ ์์.
extension CameraViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
// UIImagePickerController - ์ฌ์ง์ ์ ํํ๊ฑฐ๋ ์นด๋ฉ๋ผ ์ดฌ์ ์งํ ์คํ
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// - ์๋ณธ, ํธ์ง, ๋ฉํ ๋ฐ์ดํฐ ๋ฑ infoKey
// - ๊ฐค๋ฌ๋ฆฌ ์์ ์๋ ์ด๋ฏธ์ง๋ originalImage
if let image = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
self.imageView.image = image
dismiss(animated: true)
}
}
// UIImagePickerController 5. ์ทจ์ ๋ฒํผ ํด๋ฆญ ์
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
// code
}
}
Clova ์ผ๊ตด ์ธ์ API + MultipartFormData
๋ฌธ์์ด์ด ์๋ ํ์ผ, ์ด๋ฏธ์ง, PDF ํ์ผ ์์ฒด๊ฐ ๊ทธ๋๋ก ์ ์ก ๋์ง ์๋๋ค. ๊ทธ๋์ ํ์ผ์ ํ ์คํธ ํํ๋ก ์ธ์ฝ๋ฉํ์ฌ ์๋ฒ๋ก ์ ์กํด์ผ ํ๋ค. ๊ฒฐ๊ตญ ์ด ํํ๋ body์ ๋ด์๋ณด๋ด๋ post ์์ฒญ์ ํ ํํ๋ผ๊ณ ๋ณผ ์ ์๋ค.
import Alamofire
import SwiftyJSON
@IBAction func clovaFaceButtonTapped(_ sender: UIButton) {
let url = "https://openapi.naver.com/v1/vision/celebrity"
let headers: HTTPHeaders = [
"X-Naver-Client-Id": "-",
"X-Naver-Client-Secret": "-",
"Content-Type": "multipart/form-data"
]
// UIImage๋ฅผ ํ
์คํธ ํํ(๋ฐ์ด๋๋ฆฌ ํ์
)๋ก ๋ณํํด์ ์ ๋ฌ
// MIME Type
guard let imageData = imageView.image?.jpegData(compressionQuality: 0.5) else { return }
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(imageData, withName: "image")
}, to: url, headers: headers)
.validate(statusCode: 200...500)
.responseData { response in
switch response.result {
case .success(let value):
let json = JSON(value)
print(json)
case .failure(let error):
print(error)
}
}
}
Content-Type
์ด๋ค ํ์ผ์ ์ข ๋ฅ๊ฐ ์ ์ก๋๋์ง ๋ช ์ํด์ค ํ์๊ฐ ์๋ค. ์ฌ๋ฌ ํ์ผ์ ์ ๋ก๋ ํด์ผ ํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด ํค๋์ Content-Type์ multipart/form-data๋ก ๋ช ์ํด์ฃผ์ด์ผ ํ๋ค.
UIImage๋ฅผ ๋ฐ์ด๋๋ฆฌ ํ์ ์ผ๋ก ๋ณํ
// pngData()๋ผ๋ ๋ฉ์๋๋ ์๋ค.
// ํฌ๊ธฐ๊ฐ ํฐ ์ด๋ฏธ์ง๋ฅผ ์๋ฒ๋ก ๋ณด๋ด๋ ค๊ณ ํ๋ฉด ํต์ ์ด ์๋๋ ๊ฒฝ์ฐ๋ ์๋๋ฐ ์๋์ ๊ฐ์ด ์์ถํด์ ๋ณด๋ด๋ฉด ํด๊ฒฐํ ์ ์๋ค.
guard let imageData = imageView.image?.jpegData(compressionQuality: 0.5) else { return }
'๐ฑ SeSAC' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SeSAC] 220817 TIL (0) | 2022.08.20 |
---|---|
[SeSAC] 220816 TIL (0) | 2022.08.16 |
[SeSAC] 220811 TIL (0) | 2022.08.15 |
[SeSAC] 220810 TIL (0) | 2022.08.14 |
[SeSAC] 220809 TIL (0) | 2022.08.12 |