관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 3. 이미지 리사이징 - CGImageSourceCreateThumbnailAtIndex와 이미지 회전 처리 옵션 (#CGDictionary) 본문

iOS 응용 (swift)

[iOS - swift] 3. 이미지 리사이징 - CGImageSourceCreateThumbnailAtIndex와 이미지 회전 처리 옵션 (#CGDictionary)

jake-kim 2023. 11. 23. 01:05

1. 이미지 리사이징 - ImageIO, ImageSource를 활용한 이미지 리사이징 개념 (CGImageSourceCreateThumbnailAtIndex, "Terminated due to memory")

2. 이미지 리사이징 - ImageIO, ImageSource를 활용한 이미지 리사이징 구현 (CGImageSourceCreateThumbnailAtIndex)

3. 이미지 리사이징 - CGImageSourceCreateThumbnailAtIndex와 이미지 회전 처리 옵션 (#CGDictionary)

지난내용1) ImageSource를 이용한 이미지 리사이징

  • ImageSource 개념
    • ImageSource는 ImageIO모듈에 있고 file에서부터 I/O를 시도하고, ImageSource 이 이미지 스트림을 통해 이미지를 read하거나 write하는 방식
    • 주로 이미지 파일 형식 간 변환 및 메타데이터 작업에 사용
  • 기존 방법인 UIGraphicsImageRenderer를 사용한 이미지 리사이징보다 ImageSource를 사용하면 메모리 사용이 75%줄어들고 50% 성능 향상이 존재
  • ImageSource와 CGImageSourceCreateThumbnailAtIndex를 사용하여 손쉽게 리사이징이 가능

지난내용2) UIImage의 extension에 리사이징 함수 추가

  • 여기에 3번째 인수인 CGDictionary에 특정 옵션을 주어서, 원본 이미지에서 alpha값을 유지할 것인가, 썸네일 캐싱을 할 것인지 등의 옵션 추가가 가능
    • 이를 UIImage 확장을 통해 아래처럼 사용이 가능
extension UIImage {
        guard
            let data = jpegData(compressionQuality: 1.0),
            let imageSource = CGImageSourceCreateWithData(data as CFData, nil),
            let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, [CFString: Any]() as CFDictionary))
        else { return nil }
        
        let resizedImage = UIImage(cgImage: cgImage)
        return resizedImage
    }
}
  • 여기서 CFDictionary에서 리사이징 옵션이 존재
    • CFDictionary는 c기반이기 때문에 낮은 오버헤드와 빠른 접근 속도
    • 애플에서 빠른 속도 최적화를 위해 Swift의 Dictionary가 아닌 CFDictionary를 사용

리사이징 옵션

  • "kCG-" 이름이 붙은 c에 선언된 전역변수 key값들을 사용
func resizeV3(to size: CGSize) -> UIImage? {
    let options: [CFString: Any] = [
        kCGImageSourceShouldCache: false,
        kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceCreateThumbnailFromImageIfAbsent: true,
        kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height),
        kCGImageSourceCreateThumbnailWithTransform: true
    ]
    
    guard
        let data = jpegData(compressionQuality: 1.0),
        let imageSource = CGImageSourceCreateWithData(data as CFData, nil),
        let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
    else { return nil }
    
    let resizedImage = UIImage(cgImage: cgImage)
    return resizedImage
}
  • kCGImageSourceShouldCache: 캐시 저장 유무

https://developer.apple.com/documentation/imageio/kcgimagesourceshouldcache

  • kCGImageSourceCreateThumbnailFromImageAlways: 이미지의 썸네일을 항상 생성 여부 (true로 설정하면 캐싱되어 있더라도 생성함)

https://developer.apple.com/documentation/imageio/kcgimagesourcecreatethumbnailfromimagealways

  • kCGImageSourceCreateThumbnailFromImageIfAbsent: 이미 캐시된 썸네일이 있다면 그 썸네일을 사용할 것인지 유무

https://developer.apple.com/documentation/imageio/kcgimagesourcecreatethumbnailfromimageifabsent

  • kCGImageSourceThumbnailMaxPixelSize: 리사이징 할 때 크기를 얼만큼 줄일 것인지에 대한 여부

https://developer.apple.com/documentation/imageio/kcgimagesourcethumbnailmaxpixelsize

  • kCGImageSourceCreateThumbnailWithTransform: 옵션을 사용하여 EXIF 회전 정보를 유지할 것인지 여부

https://developer.apple.com/documentation/imageio/kcgimagesourcecreatethumbnailwithtransform

 

중요한 옵션) 이미지 회전 - kCGImageSourceCreateThumbnailWithTransform

  • 아이폰에서 사진을 세로로 두고 찍으면 사진의 메타 데이터 중 하나인 EXIF의 rotation 반시계 방향으로 이동되어 있는데, kCGImageSourceCreateThumbnailWithTransform 활성화 하지 않으면 돌아간 형태로 유지됨
    • 참고) 아이폰 앨범에서 보이는 형태는 EXIF의 Rotation 정보가 적용된 형태이며 UIImage(named:)에 설정할때도 적용된 이미지가 그대로 적용됨
    • EXIF 관련 내용은 이전 포스팅 글 참고
  • ex)kCGImageSourceCreateThumbnailWithTransform 옵션을 주지 않은 리사이징 결과
    • 원본 사진은 위 방향을 바라보며 정상적으로 들어가있지만 kCGImageSourceCreateThumbnailWithTransform 옵션을 주지 않으면 아래처럼 돌아가있음

  •  cf) kCGImageSourceCreateThumbnailWithTransform 옵션을 활성화하면 EXIF 메타데이터도 변경됨
print(image.imageOrientation == .up) // false
print(image.resizeV3(to: .init(width: 100, height: 100))?.imageOrientation == .up) // true

* 전체 코드: https://github.com/JK0369/ExImageResizing

* 참고

- https://developer.apple.com/documentation/imageio/kcgimagesourcecreatethumbnailwithtransform

- https://developer.apple.com/documentation/imageio/kcgimagesourcecreatethumbnailfromimageifabsent

- https://developer.apple.com/documentation/imageio/kcgimagesourcecreatethumbnailfromimagealways

- https://developer.apple.com/documentation/imageio/kcgimagesourceshouldcache

- https://developer.apple.com/documentation/corefoundation/cfdictionary-rum

Comments