ios

ios에서 적은 메모리로 이미지를 만들기(공부)

코코넛딩 2024. 12. 13. 08:53

참조한 블로그입니다.
https://velog.io/@o_joon_/Swift-Image-and-Memory

 

[Swift] Image and Memory

WWDC2018에서 설명한 이미지와 메모리의 연관성 및 이미지의 최적화에 대해 알아보자.

velog.io

 

iOS : 이미지와 메모리

개요

  • 이미지와 관련된 메모리는 파일 용량이 아닌 이미지 해상도와 관련이 있다.

 

이미지 렌더링 과정

  1. 이미지 렌더링하는데 사용되는 메모리양
    이미지 파일 : 590KB, 2028 * 1536
    다음 과 같은 조건을 갖는 이미지 파일을 불러올 때 사용되는 메모리는 10MB
    20배 많은 메모리를 차지함

  2. 많은 메모리가 쓰이는 이유
    1. Load
      1. 메모리에 데이터화된 이미지가 load된다.
    2. Decode
      1. 로그된 이미지를 GPU가 읽을 수 있는 형태로 decode한다.
      2. 해당 과정에서 JPEG로 압축된 파일을 압축 해제하며 10MB가 된다.
    3. Render
      1. decode된 이미지를 렌더링하여 이미지의 형태로 변경한다.

 

UIGraphicsImageRenderer

  • UIGraphicsBeginImageContextWithOptions
    • 항상 SRGB를 사용한다.
      • 픽셀당 4바이트 사용
      • Alpha 8과 Wide(픽셀당 8바이트 필요)처럼 더 작거나 큰 포맷을 사용할 수 없다.
        • Alpha 8 
          • 픽셀당 1바이트를 필요로 함
          • alpha 값 하나로만 이루어져있다.
          • SRGB보다 75% 적은 메모리를 사용한다.
          • 모노크롬(흑백 텍스트), 마스크(투명도)에 사용됨

 

// Circle via UIGraphicsImageRenderer
let bounds = CGRect(x: 0, y: 0, width:300, height: 100)
let renderer = UIGraphicsImageRenderer(size: bounds.size)
let image = renderer.image { context in
	// Drawing Code
	UIColor.black.setFill()
	let path = UIBezierPath(roundedRect: bounds,
					  byRoundingCorners: UIRectCorner.allCorners,
					  cornerRadii: CGSize(width: 20, height: 20))
    path.addClip()
	UIRectFill(bounds)
}

// 블루색으로 바꿔었지만 여전히 픽셀 당 1byte를 사용하는 이미지임
let imageView = UIImageView(image: image)
imageView.tintColor = .blue
  • UIGraphicsImageRenderer
    • 최적의 포맷을 알아서 적용시켜 준다고 한다.
    • ios 12 부터 사용가능
    • 장점
      • 메모리 관리
        • 렌더링 완료시 자동으로 메모리 해제
        • 메모리 누수를 방지
      • GPU 활용
        • GPU 가속을 활용하여 렌더링 기능을 향상시킬 수 있다.
        • CPU 부담을 줄이고, 더 빠르고 효율적으로 렌더링할 수 있게한다.
        • UIGraphicsBeginImageContextWithOptions는 주로 CPU 기반으로 렌더링을 처리하므로 성능에서 다소 제한이 있을 수 있다.
      • 해상도 자동 관리
        • 디스플레이 해상도에 맞는 이미지를 자동으로 생성하여, Retina 디스플레이와 같은 고해상도 디스플레이어에서 더 선명한 이미지를 출력할 수 있다. 이때 scale 속성을 자동으로 관리한다.
        • UIGraphicsBeginImageContextWithOptions에서는 scale을 명시적으로 설정해야 하므로, 고해상도 지원에 있어 더 많은 수동 조정이 필요할 수 있습니다.
    • 위의 코드는 검정색 원을 그리는 코드이다.
      • 시스템이 자동으로 Alpha 8 포맷을 사용하여 SRGB를 사용할 떄 보다 75% 적게 메모리를 사용한다.
      • SRGB와 품질은 동일하다.
    • tintColor를 파란색으로 바꾸어도 픽셀당 1바이트만 사용하여 메모리는 훨씬 적게 사용하면서 색상을 입힐 수 있다.
      • 렌더링할 때 적용되는 색상이 변경되는 것 뿐, 이미지의 실제 데이터를 건드리는 것이 아니기 때문에 메모리를 추가로 사용하지 않음

 

이미지 리사이징

UIGraphicsImageRenderer

  • UIImage를 통해 리사이징 하기 때문에 이미지의 크기를 바꾸는 과정에서 비효율적이다.
    • 이미지 전체 정보를 압축해제하여 메모리에 로드한다.
    • UIImage 객체는 내부적으로 이미지의 크기, 위치 및 다른 속성을 관리하기 위해 내부의 좌표공간을 사용한다.
    • 이미지를 회전, 크기 조정 또는 반전 작업을 위해서는 이 좌표 공간들을 변환하는데에 비용이 많이 든다.

 

Image I/O

  • Image I/O는 Foundation, UIKit와 같은 프레임 워크 입니다.
  • 해당 프레임워크를 통해 대부분의 이미지 파일 형식을 읽고 쓸 수 있고 효율적이면서 색상관리나 메타데이터 접근을 제공합니다.
  • ImageIO는 이미지를 효율적으로 다운샘플링 할 수 있으며, 해당 프레임워크의 Streaming API를 이용하여 다운 샘플링에 필요한 사이즈와 메타데이터를 제외한 더티 메모리들은 사용하지 않습니다.
  • ImageIO는 UIImage가 아닌 CGImage로 작업을 하는데, CGImage는 UIImage와 다르게 크기와 스케일등의 정보를 제외한 데이터만 가지고 있습니다.