티스토리 뷰
이미지와 동영상 파일에는 방향 정보가 있어 뷰에 표시할 때에 방향을 적용해서 표시해야 한다. 적용가능한 UIImage에 적용 가능한 Orientation의 종류는 다음과 같다. (UIImage.Orientation, Image.Orientation)
- Up
- 원본 픽셀이 이미지의 의도와 동일. 방향 전환이 필요 없음.
- Down
- 180도 회전 필요.
- Left
- 반시계 방향으로 90도 회전 필요.
- Right
- 시계 방향으로 90도 회전 필요.
- Up Mirrored
- 좌우 반전 필요.
- Down Mirrored
- 위아래 반전 필요.
- Left Mirrored
- 좌우 반전 후 시계 방향으로 90도 회전 필요.
- Right Mirrored
- 좌우 반전 후 반시계 방향으로 90도 회전 필요.
아이폰에서 촬영한 사진/동영상의 경우 카메라 방향에 따라 이 방향 정보가 설정되는데 이 정보를 제대로 읽어와야 한다. 읽어온 뒤 UIImage 또는 Image(SwiftUI 뷰타입)에 넘겨주면 된다.
Orientation 가져오기
AVCapturePhoto에서 Orientation 가져오기
AVCapturePhoto의 metadata에 접근하여 방향 정보를 가져올 수 있다.
let photo: AVCapturePhoto = ...
guard let metadataOrientation = photo.metadata[String(kCGImagePropertyOrientation)] as? UInt32,
let cgImageOrientation = CGImagePropertyOrientation(rawValue: metadataOrientation) else { return }
CGImagePropertyOrientation은 UIImage, Image의 Orientation과 동일한 case를 갖고 있지만 같은 타입이 아니고 rawValue가 다르기 때문에 직접 매핑해주어야 한다.
https://developer.apple.com/documentation/imageio/cgimagepropertyorientation
extension Image.Orientation {
init(_ cgImageOrientation: CGImagePropertyOrientation) {
switch cgImageOrientation {
case .up: self = .up
case .upMirrored: self = .upMirrored
case .down: self = .down
case .downMirrored: self = .downMirrored
case .left: self = .left
case .leftMirrored: self = .leftMirrored
case .right: self = .right
case .rightMirrored: self = .rightMirrored
}
}
}
CIImage에서 Orientation 가져오기
CIImage는 정보를 가져오기 위해 TIFF 프로퍼티에 접근해야 한다.
let ciImage: CIImage = ...
guard let tiffOrientation = ciImage.properties["Orientation"] as? Int else { return }
Orientation 키의 값을 가져오면 정수 값이 나오는데 이 숫자는 Image.Orientation의 rawValue와는 다르기 때문에 별도의 매핑이 필요하다.
extension Image.Orientation {
init?(tiffValue: Int) {
switch tiffValue {
case 1:
self = .up
case 3:
self = .down
case 8:
self = .left
case 6:
self = .right
case 2:
self = .upMirrored
case 4:
self = .downMirrored
case 5:
self = .leftMirrored
case 7:
self = .rightMirrored
default:
return nil
}
}
}
AVAsset에서 기기 회전 정보 및 카메라 전/후 가져오기
extension AVAsset {
func videoOrientation() -> (orientation: UIInterfaceOrientation, device: AVCaptureDevice.Position) {
var orientation: UIInterfaceOrientation = .unknown
var device: AVCaptureDevice.Position = .unspecified
let tracks :[AVAssetTrack] = self.tracks(withMediaType: AVMediaType.video)
if let videoTrack = tracks.first {
let t = videoTrack.preferredTransform
if (t.a == 0 && t.b == 1.0 && t.d == 0) {
orientation = .portrait
if t.c == 1.0 {
device = .front
} else if t.c == -1.0 {
device = .back
}
}
else if (t.a == 0 && t.b == -1.0 && t.d == 0) {
orientation = .portraitUpsideDown
if t.c == -1.0 {
device = .front
} else if t.c == 1.0 {
device = .back
}
}
else if (t.a == 1.0 && t.b == 0 && t.c == 0) {
orientation = .landscapeRight
if t.d == -1.0 {
device = .front
} else if t.d == 1.0 {
device = .back
}
}
else if (t.a == -1.0 && t.b == 0 && t.c == 0) {
orientation = .landscapeLeft
if t.d == 1.0 {
device = .front
} else if t.d == -1.0 {
device = .back
}
}
}
return (orientation, device)
}
}
출처: https://gist.github.com/kimdwkimdw/bdc68dcbbd7b6ca994a99c90dd24a7cb
CGAffineTransform의 정보를 이용하여 회전 정보 및 카메라 정보를 가져온다. 그리고 해당 정보를 Orientation에 매핑한다.
let asset: AVAsset = ...
var orientation = Image.Orientation.up
switch asset.videoOrientation().orientation {
case .landscapeRight:
orientation = .up
case .landscapeLeft:
orientation = .down
case .portraitUpsideDown:
orientation = .left
case .portrait:
orientation = .right
case .unknown:
break
@unknown default:
break
}
뷰에 Orientation 적용하기
SwiftUI Image
CIImage를 CGImage로 변환해준 뒤 Image를 방향정보와 함께 이니셜라이즈한다.
let image = Image(decorative: cgImage, scale: 1, orientation: orientation)
UIKit UIImage
let uiImage = UIImage(cgImage: cgImage, scale: 1, orientation: orientation)'가이드' 카테고리의 다른 글
| SwiftUI에서 스피닝 프로그래스 뷰 만들기 (0) | 2022.08.20 |
|---|---|
| SwiftUI에서 원형 프로그래스 뷰 만들기 (0) | 2022.08.20 |
| 네이버 지도 SDK 줌 레벨 알아보기 (0) | 2022.07.30 |
| SwiftUI에서 뷰 스크린샷 캡쳐하기 (0) | 2022.07.30 |
| SwiftUI에서 구글로그인 띄우기 (0) | 2022.07.30 |
