iOS

[iOS] Image: iOS 이미지 렌더링 과정

Dev_Ted 2025. 9. 20. 18:37

Load → Decode → Render

590KB의 이미지가 있고, 2048 * 1536의 해상도를 가진다고 가정

Load

  • 이미지를 메모리에 로드
  • 590KB 파일을 메모리로 불러옴

Decode

  • 로딩한 이미지 파일을 GPU가 렌더링 할 수 있는 포맷으로 변환
  • 이 과정에서 대략 10MB 크기의 데이터가 됨
  • 이미지는 바이너리 데이터이기 때문에 인코딩 된 상태였기 때문에, 디코딩 단계가 필요

Render

  • 디코딩 된 이미지를 화면에 렌더링 하는 단계

 

 

iOS 이미지 렌더링 과정

iOS에서 네트워크 이미지를 화면에 표시할 때, 단순히 imageView.image = image 한 줄로 끝나는 것처럼 보이지만 실제로는 내부적으로 여러 단계의 렌더링 파이프라인이 실행됩니다.

핵심 흐름은 다음과 같습니다.

Image Load
↓
UIImage 생성
↓
UIImageView에 설정
↓
Layer Tree Commit
↓
Display Preparation (Decode)
↓
GPU Texture Upload
↓
Core Animation Compositing
↓
Framebuffer
↓
Display 출력
 

이 과정을 코드와 함께 단계별로 살펴보겠습니다.

 

1. 이미지 다운로드 (압축 데이터 상태)

먼저 네트워크에서 이미지를 다운로드합니다.

let url = URL(string: "https://example.com/photo.jpg")!

URLSession.shared.dataTask(with: url) { data, _, _ in
guard let data else { return }

let image = UIImage(data: data)

DispatchQueue.main.async {
imageView.image = image
}
}.resume()
 

 

이 단계에서 메모리에 올라오는 데이터는 다음과 같습니다.

photo.jpg
 

압축된 JPEG / PNG 데이터입니다.

이 시점에는 아직 다음 작업이 수행되지 않았습니다.

  • 이미지 디코딩
  • GPU 업로드
  • 화면 렌더링

 

2. UIImage 생성

다운로드한 데이터로 UIImage 객체를 생성합니다.

 
let image = UIImage(data: data)

 

 

이 단계는 단순히 이미지 객체를 생성하는 단계입니다.

JPEG / PNG
↓
UIImage 객체
 

 

이때 중요한 점은 다음입니다.

이 단계에서 항상 bitmap이 생성되는 것은 아닙니다.

 

즉 아직 display-ready 상태가 아닐 수 있습니다.

 

3. UIKit 레이아웃 계산 (Point 좌표)

이미지와 별개로 UIKit은 먼저 레이아웃을 계산합니다.

예를 들어 다음 코드가 있습니다.

imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
 

여기서 100은 Pixel이 아니라 Point입니다.

UIKit은 이 단계에서 다음을 계산합니다.

  • View 위치
  • View 크기
  • AutoLayout 결과
  • View hierarchy

 

즉 이 단계는

레이아웃 계산 단계이며 이미지 픽셀과는 관계가 없습니다.

 

4. UIImageView에 이미지 설정

이제 이미지를 화면에 표시합니다.

imageView.image = image

 

이 코드가 실행되면 내부적으로 다음 일이 일어납니다.

UIImageView
↓
CALayer
↓
layer.contents = CGImage

 

즉 이미지는 Core Animation Layer에 연결됩니다.

이 코드는 렌더링 요청 코드입니다.

 

5. RunLoop → Core Animation Commit

UIKit은 즉시 화면을 다시 그리지 않습니다.

다음 RunLoop 사이클에서 Core Animation이 commit을 수행합니다.

imageView.image = image
↓
Layer 상태 변경 기록
↓
RunLoop
↓
CATransaction Commit

이 단계에서 Layer Tree가 렌더링 시스템으로 전달됩니다.

 

6. Display Preparation (이미지 디코딩)

이미지를 실제로 화면에 표시하려면 압축 이미지를 bitmap으로 변환해야 합니다.

이 과정이 Image Decode입니다.

JPEG / PNG
↓
Decode (CPU)
↓
RGBA Bitmap

 

예를 들어 다음 3000 × 3000 이미지가 있다고 가정합니다.

디코딩 후 메모리 사용량

3000 × 3000 × 4 bytes
≈ 36MB

이 작업은 CPU에서 수행되는 비용이 큰 작업입니다.

 

그래서 이미지 디코딩은 스크롤 성능 저하의 주요 원인이 될 수 있습니다.

 

7. GPU Texture Upload

디코딩된 bitmap은 GPU에서 사용할 수 있도록 Texture로 업로드됩니다.

RGBA Bitmap
↓
GPU Texture

이 단계 이후 GPU가 이미지를 렌더링할 수 있습니다.

 

8. Point → Pixel 변환

UIKit 좌표는 Point 기반입니다.

 

imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)

이 값은 100pt입니다.

 

하지만 디바이스의 screen.scale 값이 3이라면 실제 화면 해상도는 100pt × 3 = 300px 입니다.

 

즉 렌더링 과정에서 다음 변환이 발생합니다.

Point → Pixel

 

이 변환은 Layer의 contentsScale을 기준으로 GPU 렌더링 과정에서 처리됩니다.

 

9. GPU Compositing

GPU는 여러 Layer를 하나의 화면으로 합성합니다.

Background Layer

Image Layer

Text Layer

 

GPU는 다음 작업을 수행합니다.

  • transform
  • alpha blending
  • clipping
  • layer compositing

이 과정에서 최종 프레임이 생성됩니다.

 

10. Framebuffer 생성

GPU 합성 결과는 Framebuffer에 기록됩니다.

1170 × 2532 pixel

 

이 데이터가 실제 화면 출력 데이터입니다.

 

11. Display 출력

마지막 단계에서는 Display Controller가 Framebuffer 데이터를 읽어 디스플레이에 출력합니다.

Framebuffer
↓
Display Controller
↓
OLED / LCD Pixel

이 단계에서 사용자가 실제 화면을 보게 됩니다.

 

전체 코드 기준 흐름

정리하면 다음 코드

let image = UIImage(data: data)
imageView.image = image

이후 실제 내부 흐름은 다음과 같습니다.

UIImage 생성
↓
imageView.image = image
↓
CALayer.contents 설정
↓
Layer Tree Commit
↓
Display Preparation (Decode)
↓
GPU Texture Upload
↓
Point → Pixel 변환
↓
GPU Compositing
↓
Framebuffer
↓
Display

 

 

핵심 정리

 
 

iOS에서 이미지가 화면에 표시되는 과정은 다음과 같습니다.

  1. 네트워크 또는 번들에서 이미지 데이터가 로드됩니다.
  2. UIImage 객체가 생성됩니다.
  3. imageView.image = image로 UIImageView에 이미지가 설정됩니다.
  4. 다음 RunLoop에서 Core Animation commit이 발생합니다.
  5. Display Preparation 단계에서 이미지가 bitmap으로 디코딩됩니다.
  6. bitmap 데이터가 GPU Texture로 업로드됩니다.
  7. GPU 렌더링 과정에서 Point → Pixel 변환이 적용됩니다.
  8. Core Animation이 여러 Layer를 GPU에서 합성합니다.
  9. Framebuffer가 생성됩니다.
  10. Display Controller가 Pixel 데이터를 화면에 출력합니다.
728x90