#keywords C++,Bitmap,GDI+ 일반적으로 개발 포럼에서는 간단하기 때문에 Stream을 사용하는 방법을 많이 답변해주는데 위 방법이 훨~씬 빠르다. {{{#!gcode HBITMAP hbmReturn = NULL; void* buf = new byte[bitmapLength]; // bitmap bytes ... // fast (o) BITMAPFILEHEADER* bmfh = (BITMAPFILEHEADER*)buf; BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)((byte*)buf + sizeof(BITMAPFILEHEADER)); BITMAPINFO* bmi = (BITMAPINFO*)bmih; void* bits = (void*)((byte*)buf + bmfh->bfOffBits); hbmReturn = CreateDIBitmap(pDC->GetSafeHdc(), bmih, CBM_INIT, bits, bmi, DIB_RGB_COLORS); }}} {{{#!gcode // very slow (x) IStream* stream = SHCreateMemStream((BYTE*)buf, length); Bitmap* bitmap = Gdiplus::Bitmap::FromStream(stream); bitmap->GetHBITMAP(Color(255, 255, 255, 255), &hbmReturn); // delay stream->Release(); delete bitmap; }}} 빠른(느린) 이유 {{{#!markdown ### 핵심 차이점 | 항목 | CreateDIBitmap 방식 | Gdiplus::Bitmap::FromStream 방식 | 성능 영향 | |-----------------------------|-----------------------------------------------|------------------------------------------------------------|-----------| | 처리 레이어 | 순수 GDI (낮은 레벨) | GDI+ (높은 레이어, 추상화됨) | GDI+가 느림 | | 포맷 파싱 | 거의 없음 (직접 구조체 캐스팅) | BMP 헤더 + 픽셀 데이터 완전 파싱 + 검증 | 매우 큼 | | 픽셀 데이터 복사 방식 | 포인터로 직접 참조 (복사 거의 없음) | 내부적으로 전체 픽셀 버퍼 복사 + 변환 | 큼 | | 색상 변환 / 프리멀티플라이드 | 거의 안 함 (DIB_RGB_COLORS 그대로) | 내부적으로 ARGB → PARGB 변환 가능성 있음 | 중간~큼 | | 검증 (validation) | 없음 | GdipImageForceValidation() 계열 호출 (전체 픽셀 강제 materialization) | 매우 큼 | | 최종 HBITMAP 생성 방식 | CreateDIBitmap = 드라이버에 직접 전달 | GDI+ → GDI 변환 (GetHBITMAP 내부에서 BitBlt 수준 복사) | 중간 | ### 가장 큰 병목 3가지 (실제 지연 대부분 여기서 발생) 1. **GDI+의 강제 픽셀 materialization + 검증** GDI+는 보안/안정성을 위해 이미지 로드 후 **GdipImageForceValidation()** 계열을 내부적으로 호출한다. → **전체 픽셀을 실제로 읽고 압축 해제하고 검증**하는 작업이 들어간다. 특히 큰 이미지일수록 이 단계가 치명적이다. 2. **FromStream 자체의 오버헤드** SHCreateMemStream + FromStream 조합은 - 스트림 읽기 - BMP 헤더 파싱 - 픽셀 포맷 변환 판단 - 실제 픽셀 데이터 디코딩 + 복사 를 모두 거친다. → CreateDIBitmap은 이 과정 대부분을 **건너뛴다** (이미 우리가 직접 파싱했다고 가정). 3. **GetHBITMAP() 내부 복사** Gdiplus::Bitmap은 기본적으로 **PixelFormat32bppPARGB** (premultiplied) 형태로 들고 있다. → GetHBITMAP() 호출 시 **비-premultiplied HBITMAP**을 만들기 위해 픽셀 단위 변환 + 복사가 발생한다. 이 복사는 상당히 무겁다(특히 큰 해상도에서). 많은 게임/실시간 영상 처리 코드에서 GDI+를 피하고 CreateDIBitmap / CreateDIBSection 계열을 선호하는 이유가 바로 이것이다. 필요하면 GDI+를 쓰더라도 - Bitmap을 풀(pool)로 재사용하거나 - CachedBitmap을 활용하거나 - PixelFormat32bppRGB로 강제 생성 하는 식으로 최적화하면 어느 정도 빨라지긴 하다. 하지만 **단발성 BMP 메모리 → HBITMAP 변환**이라면 거의 항상 CreateDIBitmap 계열이 압승이다. }}}