본문 바로가기

Projects/CoVNC

C++을 사용해 바이트 배열에 저장된 DIB정보를 DIB메모리 블럭 만들기

# 바이트 배열에 저장된 DIB정보를 DIB메모리 블럭 만들기
2007년 3월 31일
울산대학교 PSLab 이태호
http://www.soulfree.net
혹시나 퍼가실땐 위의 내용을 꼭 추가해 주세요~
==================================================================================================

우선 알아보기 어려운 이 글의 제목부터 장황하게 설명 하도록 하겠습니다. ^^;;
이 글의 제목은 위에서 보고 클릭하셨다시피 "바이트 배열에 저장된 DIB정보를 DIB메모리 블럭 만들기"입니다.
제 블로그의 졸업작품 카테고리를 보셔서 아시겠지만, DIB는 Device Independent Bitmap의 약자로
장치에 의존적이지 않는 비트맵이라는 뜻입니다.

(세상에는 여러 종류의 운영체제가 존재하고 그런 운영체제 중에서도 Graphic User Interface를 지원하는
운영체제가 많이 배포되고 운영되고 있습니다.
따라서 그런 GUI운영체제들은 자신만의 색깔 코드를 가지고 있어서, 그림을 보여줄때 자신만의 코드를 사용하여
보여주기도 합니다. (저의 추측이 섞였습니다...) 그렇게 보여주는 비트맵 형식이 바로 DDB입니다.
Device Dependent Bitmap이라고 하고요...
DIB 형식은 그와 다르게 비트맵에 색상정보가 들어가 있습니다. 따라서 어떤 운영체제든지 장치든지 같은
그림을 보게 되는 것이고, DDB는 장치에 의존적이어서 운이 나쁘면 서로 다른 그림을 보게 됩니다.)

이번 졸업 작품에는 클라이언트나 서버로 부터 전송받은 바이트 배열에서 비트맵 부분을 추출하여 보여주도록하는 내용을 포함하게 되었습니다. 그런데 이때 전송하는 내용은 DIB 형식의 비트맵입니다.

바이트 배열은 8비트씩 1바이트로 길게 열을 지어 늘어진 녀석입니다.
그리고 DIB의 경우에는 BITMAPFILEHEADER 구조체부터 시작해서 BITMAPINFOHEADER 구조체와 RGBQUAD
구조체 배열
, 그리고 비트맵 내용들로 구조가 이루어져 있습니다.
이런 DIB를 이루는 구조체의 내용은 제 블로그를 잘 보시면 쉽게 아실 수 있고,
제가 여기서 설명 드리고 싶은 것은 DIB를 이루는 구조체 변수를 만들고
그 구조체 변수에 해당하는 크기의 메모리를 할당하여
바이트 배열에 저장된 DIB내용을 그런 구조체에 저장하는 순서를 보여 드리는 것입니다.

즉, 단지 바이트 배열 형태인 장치 독립적인 비트맵 정보를 장치 독립적인 비트맵 정보인 DIB 형태로
변환하는 과정입니다.
그림으로 나타내어 보겠습니다.

사용자 삽입 이미지

=============바이트 배열을 DIB 형식으로 저장하기=====================

1)DIB구조중에 가장 먼저 시작되는 BITMAPFILEHEADER 구조체에 값을 할당하는 과정입니다.
//DIB 내용이 저장된 바이트 배열의 이름은 byteImage[]입니다.

int j = 0; <- 요 변수는 바이트 배열의 인덱스로 사용할 녀석입니다.

//BITMAPFILEHEADER 구조체의 공간을 할당합니다.
BITMAPFILEHEADER* bf = (BITMAPFILEHEADER *) malloc(sizeof(BITMAPFILEHEADER));

//바이트 배열에 저장된 BITMAPFILEHEADER 내용을 방금 생성한 bf에 저장합니다.
//실제로는 바이트 배열에서 BITMAPFILEHEADER 내용이 시작하는 부분의 주소를 저장하는 것입니다...
bf = (BITMAPFILEHEADER*) byteImage; <- 이렇게 하면 byteImage배열에서 bf에 할당한 메모리 크기만큼만
bf에 저장되겠지요.

//바이트 배열의 인덱스를 계산합니다.
j = sizeof(BITMAPFILEHEADER); <- 위에 제가 그린 그림을 참조하면 j 변수는 24가 저장되겠지요.

2)다음으로 BITMAPINFOHEADER 구조체에 값을 할당하는 과정입니다.

//BITMAPFILEHEADER 구조체의 공간을 할당합니다.
BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER *) malloc(sizeof(BITMAPINFOHEADER));

//바이트 배열에 저장된 BITMAPINFOHEADER내용을 방금 생성한 bf에 저장합니다.
//이것 역시 실제로는 바이트 배열에서 BITMAPFILEHEADER 내용이 시작하는 부분의 주소를 저장하는 것입니다...
bmih = (BITMAPINFOHEADER*) (byteImage + j);
//바이트 배열의 인덱스를 계산합니다.
j += sizeof(BITMAPINFOHEADER); <- 그림을 참조하면 j 변수는 104가 저장되겠지요.

3)다음으로 RGBQUAD 구조체 배열에 값을 할당하는 과정입니다.

** 여기서 잠깐!!***---------------------------------------
이 글을 참조하시면 잘 아시겠지만 RGBQUAD 배열의 크기는 정해져 있지 않습니다.
RGBQUAD는 팔레트 정보를 담고 있는 배열로써
DIB의 내용이 트루컬러의 경우는 4, 그외 8색이면 4 * 8, 16색은 4 * 16, 4 * 256은 256색을 표현할때의 RGBQUAD 구조체 배열의 크기가 됩니다. 단위는 바이트...
따라서 경우에 따른 if, else 문으로 나누어 주어야합니다.
또한 바이트 배열에 저장된 DIB의 RGBQUAD 배열의 크기는 BITMAPINFOHEADER 구조체 맴버변수인
biClrUsed에 저장되어있습니다. 다만 트루컬러의 경우 4가 저장되어야 하나 0이 저장된다고 하는군요.
--------------------------------------------------------

 RGBQUAD* rgbq;
//DIB의 내용이 트루 컬러일때가 아닐 때 입니다.
 if(bmih->biClrUsed != 0){

//메모리 공간을 할당하고
  rgbq = (RGBQUAD*) malloc(bmih->biClrUsed);

//주소를 복사한 뒤(즉, RGBQUAD의 내용을 바이트 배열에서 추출한 뒤)
  rgbq = (RGBQUAD *)(rfbImage + j);

//인덱스를 다시 계산합니다.
  j += sizeof(RGBQUAD) * bmih->biClrUsed;
 }


//트루 컬러일때입니다.
 else{
  rgbq = (RGBQUAD*) malloc(sizeof(RGBQUAD));
  rgbq = (RGBQUAD *)(rfbImage + j);
  j += sizeof(RGBQUAD);
 }

4)다음으로 BITMAPINFO 구조체에 값을 할당하는 과정입니다.
BITMAPINFO 구조체는 이 글을 참조하시면 아실 수 있듯이 BITMAPINFOHEADER 구조체와 RGBQUAD 구조체 배열을 그저 묶은 구조체입니다. 따라서 왜 만드는지 반문 하실 분들이 계실겁니다.
이 과정은 CreateDIBitmap() 함수를 사용해 DIB 메모리 블럭을 만들때
CreateDIBitmap() 함수가 BITMAPINFO 구조체의 주소를 매개변수로 입력받기 때문입니다.

//j 변수에는 BITMAPFILEHEADER와 BITMAPINFO 크기(BITMAPINFOHEADER 크기 + RGBQUAD[] 크기)가
// 저장된 값이 들어가 있을 것입니다.
//따라서 j의 값에 BITMAPFILEHEADER를 빼주면 BITMAPINFO 크기를 얻을 수 있겠죠.
 BITMAPINFO* bmi = (BITMAPINFO*) malloc(j - sizeof(BITMAPFILEHEADER));

//이것 역시 RGBQUAD 구조체 배열때문에 나누어 주어야합니다.
//트루 컬러가 아닐 때입니다.
for(i = 0; i < bmih->biClrUsed; i++){
 bmi->bmiColors[i] = rgbq[i];
}

//트루 컬러 일 때 입니다.
if(bmih->biClrUsed == 0)
  bmi->bmiColors[0] = rgbq[0];

//BITMAPINFOHEADER는 그냥 집어넣어주면 되겠죠
bmi->bmiHeader = *bmih;

5)다음으로 실제 비트맵 데이터를 임시 바이트 배열에 할당하는 과정입니다.
이 과정역시 CreateDIBitmap() 함수를 사용해 DIB 메모리 블럭을 만들때
CreateDIBitmap() 함수가 바이트 배열로 된 실질적인 비트맵 정보를 매개변수로 입력받기 때문입니다.

 char *pixels = (char*) malloc(len - j);
 for(i = 0; i < len - j; i++){
  pixels[i] = rfbImage[i+j];
 }

6)마지막으로 메모리 블럭을 만듭니다.
HDC hdc = GetDC(m_hwnd);
HBITMAP hbm; //저장될 메모리 블럭
 
hbm = CreateDIBitmap(hdc, &(bmi->bmiHeader), CBM_INIT, pixels, bmi, DIB_RGB_COLORS);

매개변수를 설명하자면
(윈도우 핸들러, BITMAPINFOHEAD의 주소, 초기화 상수, 바이트 배열 형식의 실제 비트맵 정보, BITMAPINFO , 컬러 정보 상수)


결론~~
이렇게 바이트 배열에 담겨있는 DIB 정보를 추출하여 실제로 사용가능한 DIB형식으로 만들어 내는 과정을 기술하여 보았습니다. 상당히 난잡하고 메모리 낭비가 있는 과정일지도 모르니, 이글을 보시는 고수님들께서는 과감히 댓글을 부탁드립니다...
사실 이 과정을 알아내고 이해하는게 조금 힘이 들었는데 (약 하루, 이틀 소요가 되었으니까요...)
바이트 배열에서 DIB 형태로 변환하는 문서가 일목 요연하게 나와있는게 없어서 그랬습니다.

이런 과정을 시도한 사람은 저뿐이었는지도?? ㅠㅠ

조만간 졸업작품과 연계하여 쓰고 있는 저널논문의 내용을 요약해서 글 쓰도록 하겠습니다.

'Projects > CoVNC' 카테고리의 다른 글

MSXML 사용법 요약  (0) 2007.05.05
Microsoft XML Core Service(MSXML)  (0) 2007.05.05
DIB/DDB 구조  (0) 2007.03.30
CListBox  (0) 2007.02.21
부요리눅스의 클립보드  (0) 2007.02.20