| 항목 | CreateDIBitmap 방식 | Gdiplus::Bitmap::FromStream 방식 | 성능 영향 |
|---|---|---|---|
| 처리 레이어 | 순수 GDI (낮은 레벨) | GDI+ (높은 레이어, 추상화됨) | GDI+가 느림 |
| 포맷 파싱 | 거의 없음 (직접 구조체 캐스팅) | BMP 헤더 + 픽셀 데이터 완전 파싱 + 검증 | 매우 큼 |
| 픽셀 데이터 복사 방식 | 포인터로 직접 참조 (복사 거의 없음) | 내부적으로 전체 픽셀 버퍼 복사 + 변환 | 큼 |
| 색상 변환 / 프리멀티플라이드 | 거의 안 함 (DIB_RGB_COLORS 그대로) | 내부적으로 ARGB → PARGB 변환 가능성 있음 | 중간~큼 |
| 검증 (validation) | 없음 | GdipImageForceValidation() 계열 호출 (전체 픽셀 강제 materialization) | 매우 큼 |
| 최종 HBITMAP 생성 방식 | CreateDIBitmap = 드라이버에 직접 전달 | GDI+ → GDI 변환 (GetHBITMAP 내부에서 BitBlt 수준 복사) | 중간 |
GDI+의 강제 픽셀 materialization + 검증
GDI+는 보안/안정성을 위해 이미지 로드 후 GdipImageForceValidation() 계열을 내부적으로 호출한다.
→ 전체 픽셀을 실제로 읽고 압축 해제하고 검증하는 작업이 들어간다.
특히 큰 이미지일수록 이 단계가 치명적이다.
FromStream 자체의 오버헤드
SHCreateMemStream + FromStream 조합은
GetHBITMAP() 내부 복사
Gdiplus::Bitmap은 기본적으로 PixelFormat32bppPARGB (premultiplied) 형태로 들고 있다.
→ GetHBITMAP() 호출 시 비-premultiplied HBITMAP을 만들기 위해 픽셀 단위 변환 + 복사가 발생한다.
이 복사는 상당히 무겁다(특히 큰 해상도에서).
많은 게임/실시간 영상 처리 코드에서 GDI+를 피하고 CreateDIBitmap / CreateDIBSection 계열을 선호하는 이유가 바로 이것이다.
필요하면 GDI+를 쓰더라도
- Bitmap을 풀(pool)로 재사용하거나
- CachedBitmap을 활용하거나
- PixelFormat32bppRGB로 강제 생성
하는 식으로 최적화하면 어느 정도 빨라지긴 하다.
하지만 단발성 BMP 메모리 → HBITMAP 변환이라면 거의 항상 CreateDIBitmap 계열이 압승이다.