MFC DIB 섹션 & BYTE 사용법: 300×400 비트맵으로 알아보는 픽셀 단위 그래픽 렌더링 및 화면 채우기 원리
1. 비트맵 메모리 버퍼의 기본 구성
- 비트맵 크기:
- 너비: 300 픽셀
- 높이: 400 픽셀
- 총 픽셀 수: 300 × 400 = 120,000 픽셀
- 픽셀 당 바이트 수:
- 32비트 컬러를 사용하면 한 픽셀은 4바이트를 차지합니다. (8 bit == 1byte)
- 전체 메모리 크기: 300 × 400 × 4 = 480,000 바이트
- 메모리 배열 순서:
- 비트맵 데이터는 행 단위(Row-major order)로 연속된 메모리에 저장됩니다.
- 첫 번째 행의 300픽셀, 두 번째 행의 300픽셀, …, 마지막 행의 300픽셀이 순서대로 저장됩니다.
2. BYTE* 포인터를 통한 픽셀 데이터 접근
BYTE* pBits
는 480,000 바이트의 연속 메모리 블록의 시작 주소를 가리킵니다. 각 픽셀은 4바이트로 구성되며, 보통 순서는 Blue, Green, Red, Alpha입니다.
픽셀 오프셋 계산
특정 좌표 (x, y)의 픽셀에 접근하기 위해 메모리 오프셋은 다음과 같이 계산됩니다.
int bytesPerPixel = 4; // 32비트 컬러
int imageWidth = 300; // 이미지 너비
int offset = (y * imageWidth + x) * bytesPerPixel;
BYTE* pPixel = pBits + offset; // (x, y) 위치의 픽셀 주소
예를 들어, 좌표 (10, 20)의 픽셀에 접근하려면:
- 계산: offset = (20 × 300 + 10) × 4
- 이 주소를 통해 해당 픽셀의 데이터를 읽거나 쓸 수 있습니다.
픽셀 데이터 설정 예제
특정 픽셀에 빨간색을 채우려면 다음과 같이 작성합니다.
pPixel[0] = 0; // Blue 채널
pPixel[1] = 0; // Green 채널
pPixel[2] = 255; // Red 채널
pPixel[3] = 255; // Alpha 채널 (불투명)
이 방식으로 전체 화면을 순회하며 원하는 색상이나 패턴으로 채울 수 있습니다.
3. BITMAPINFOHEADER의 biHeight와 픽셀 오프셋
biHeight 필드는 비트맵의 높이와 메모리 배열에서 행의 순서를 결정합니다. 이 값의 부호에 따라 두 가지 방식이 있습니다.
3.1 Top-Down 비트맵 (음의 biHeight)
- 설명:
biHeight
가 음수인 경우, 비트맵은 top-down 방식으로 저장됩니다.- 메모리의 첫 번째 행은 실제 이미지의 최상단 픽셀에 해당합니다.
- y = 0일 때 최상단, y = imageHeight - 1일 때 최하단 픽셀이 됩니다.
- 픽셀 오프셋 계산:
int offset = (y * imageWidth + x) * bytesPerPixel;
-
메모리 구조 다이어그램 (Top-Down):
+-------------------------------------------------------------+ | Row 0 (최상단) : pBits[0] ... pBits[1199] | | Row 1 : pBits[1200] ... pBits[2399] | | ... | | Row 399 (최하단): pBits[478800] ... pBits[479999] | +-------------------------------------------------------------+
3.2 Bottom-Up 비트맵 (양의 biHeight)
- 설명:
biHeight
가 양수인 경우, 비트맵은 bottom-up 방식으로 저장됩니다.- 메모리의 첫 번째 행은 실제 이미지의 가장 아래 픽셀에 해당합니다.
- y = 0은 이미지의 맨 아래, y = imageHeight - 1는 맨 위 픽셀이 됩니다.
- 픽셀 오프셋 계산:
int offset = ((imageHeight - 1 - y) * imageWidth + x) * bytesPerPixel;
여기서
imageHeight
는 비트맵의 실제 높이(절대값)입니다. -
메모리 구조 다이어그램 (Bottom-Up):
+-------------------------------------------------------------+ | Row 0 (가장 아래) : pBits[0] ... pBits[1199] | | Row 1 : pBits[1200] ... pBits[2399] | | ... | | Row 399 (최상단): pBits[478800] ... pBits[479999] | +-------------------------------------------------------------+
결론
- Top-Down 비트맵 (음의 biHeight):
- 픽셀 오프셋:
(y * imageWidth + x) * bytesPerPixel
- 픽셀 오프셋:
- Bottom-Up 비트맵 (양의 biHeight):
- 픽셀 오프셋:
((imageHeight - 1 - y) * imageWidth + x) * bytesPerPixel
- 픽셀 오프셋:
이처럼 biHeight의 부호에 따라 메모리 내 행의 순서가 달라지고, 이에 맞춰 픽셀 좌표를 계산하는 방식이 달라집니다.
4. 전체 과정 요약
- 메모리 버퍼 준비:
- 300×400 크기의 DIB 섹션을 생성하면, 480,000 바이트의 연속 메모리 영역이 할당되고
BYTE* pBits
가 이 영역의 시작 주소를 가리킵니다.
- 300×400 크기의 DIB 섹션을 생성하면, 480,000 바이트의 연속 메모리 영역이 할당되고
- 픽셀 좌표 계산:
- (x, y) 좌표를 기준으로 픽셀 오프셋을 계산합니다.
- biHeight의 부호에 따라 top-down 또는 bottom-up 방식으로 계산합니다.
- 픽셀 데이터 기록:
- 해당 메모리 위치에 원하는 색상 값을 기록하여, 픽셀 단위로 이미지를 구성합니다.
5. 결론
GDI, DirectX, OpenGL 등 다양한 그래픽 API들은 최종적으로 화면의 픽셀 데이터를 조작하여 이미지를 출력합니다.
GDI GDI는 주로 CPU를 이용해 소프트웨어 렌더링을 수행하며, 그려진 결과를 프레임 버퍼에 복사하여 화면에 표시합니다.
DirectX (Direct3D) DirectX는 GPU를 활용하여 정점 처리, 픽셀 처리 등의 병렬 렌더링 작업을 수행하고, 최종 결과를 GPU 메모리의 프레임 버퍼에 출력합니다.
두 방식 모두 내부적으로는 “모니터의 픽셀 하나하나에 점을 찍는” 원리를 기반으로 하고 있습니다.
이 글이 MFC를 이용한 DIB 섹션 생성과 BYTE*를 통한 픽셀 단위 그래픽 렌더링의 원리를 이해하는 데 도움이 되길 바랍니다.
댓글