Search

'DDB'에 해당되는 글 4건

  1. 2007.03.30 DIB/DDB 구조
  2. 2007.02.05 DIB구조
  3. 2007.02.05 DIB를 DDB로 변환
  4. 2007.02.01 BMP를 DDB로 변환

DIB/DDB 구조

Projects/CoVNC 2007.03.30 18:01 Posted by soulfree >동네청년<

비트맵은 그림을 컴퓨터에 저장하기 위해 그림을 구성하는 각 점의 색상값을2차원
배열의 형태로 저장하는 포맷의 일종이다. 이 방식은 마이크로소프트가윈도우에서
처음소개하였다. 물론그림을컴퓨터에저장하고표현하는방식에는비트맵방식이
외에도G I F, J P G와 같은 여러 가지다른 방식이 있지만, 비트맵을제외한다른그래
픽 포맷은 압축되어있기때문에프로그램에서빠른속도로 처리하거나이미지를가
공하기가힘들다.
비트맵은 압축되지 않은 형태이므로비록 용량을 많이 차지하고 있지만 가공하기가
유리하고화면에직접 출력될수있는 장점이있어 기본그림 파일형식으로 많이사
용되고있다.
비트맵 구조와 종류
비트맵은말그대로여러개의비트(b i t)가하나의맵(m a p)을이루고있다. 즉, 그림을
구성하는픽셀정보는2차원배열의형태로저장되어있다. 그래서비트맵은픽셀색
상, 이미지의위치와크기, 해상도등의정보를가지고있는데이터구조를갖고있다.
게임프로그래밍에서는그래픽이미지가다른부분보다중요한데, 게임에서사용되는
복잡한이미지는SetPixel,LineTo,Rectangle,Ellipse 와같은그리기함수를이용하
여 그리는것보다 비트맵이미지를이용하여그리는것이 훨씬 효율적이고생산적이
기때문이다.


비트맵
여기에서는비트맵의구조와종류에대해알아보고각비트맵의종류별특징을비교해본다.

마지막으로장치종속적 비트맵을이용하여비트맵을화면에그리는예제를작성해볼것이다.
■ 비트맵구조와종류

■장치 종속적비트맵과장치 독립적비트맵
■ 비트맵파일을화면에 그리는간단한예제


비트맵을 사용하면 이미지데이터의양이 많기때문에실행파일의크기가커지며

메모리를 많이 사용하는단점이있지만그단점에비 해적은CPU 부담으로정밀한묘사
가가능하고처리과정이간단해지는장점이있다.
그렇다면게임에서필수적으로 사용하는 비트맵의 종류와 구조에대해서알아보자.
장치 종속적 비트맵과 장치 독립적 비트맵
윈도우 CE는 비트맵 형식으로 장치 종속적 비트맵(DDB, Device Dependent
B i t m a p)과장치독립적비트맵(DIB, Device Independent Bitmap)을지원하고있다.


장치종속적비트맵은현재시스템의디스플레이가직접처리할수있는비트맵을말
한다. 그래서비트맵을이루는픽셀의형식과배열은디스플레이의것과동일하다. 따
라서 별도의 변환 과정 없이 비트맵은 시스템의 디스플레이에바로 전송될수 있다.
그러나장치 종속적 비트맵은현재 시스템의디스플레이장치가가지고있는 부가적
인 정보(팔레트, 픽셀포맷등)를 따로 보관하지않기 때문에다른 종류의 디스플레이
장치에서는정확하게출력되지않는단점이있다.
장치 독립적 비트맵은 시스템의 디스플레이 장치와 상관 없이 비트맵을 출력하는데
필요한 모든정보(팔레트, 픽셀포맷등)를가지고 있는비트맵이다. 따라서어떠한종
류의디스플레이하드웨어에서도동일한모습의비트맵을출력할수있다. 그러나특
정 디스플레이하드웨어의구성이장치 독립적 비트맵의구성과다르다면적절한픽

"여기서잠깐
GDI의 그리기함수
GDI 그리기 함수에는 점을 찍는 SetPixel() 함수, 선을 그리는 LineTo() 함수, 사각형을 그리는 Draw3DRect(), FillRect() 함수, 타원을그리는Ellipse() 함수등이있다.
그럼, 이함수를이용하여 삼각형모양 을 간단하게그려본다고생각해보자. GDI에는삼각형그리기함수가없기때문에 삼각형은 LineTo( ) 와MoveTo( ) 함수를여러번호출해서그려야한다. 그리고 삼각형의색을 칠하기 위하여 복잡한 연산을 거쳐야 한다. 하지만비트맵 이미지로 삼각형 그림을 가지고 있으면 이러한 복잡한과정없이쉽게그림을화면이그릴수있다.
여기에서는 간단한 삼각형을가지고예를 들었지만게임에서는삼각형보다훨씬 복잡한 그림이 많이 나온다. 이러한그림을항상 GDI 의그리기함수로그린다고생각하면끔직한일이아닐수없다."



셀 포맷의변환작업이 필요하고 팔레트에해당하는색상을 매핑시켜야하는 부담이
있어, 비트맵의출력속도가떨어질수있는단점이있다.
표면적으로보았을때에는장치독립적비트맵( D I B)이장치종속적비트맵(D D B)보다
훨씬 성능이 좋은 포맷이고D I B가 D D B보다 최신 포맷이다. 하지만아직까지는두
가지포맷모두사용해야하므로어느하나를선택할수는없다. 예를들어, D I B가장
치 독립적이고 최신 포맷이긴 하지만 디바이스 컨텍스트(Device Context)에 선택될
수있는비트맵은D D B뿐이고프로그램내부에서의생성과파괴작업도D D B가훨씬
효율적이다. 그래서두가지 포맷의특징을모두 알고 있어야하며 상호변환 방법에
대해서도알고있어야한다.


장치종속적비트맵
먼저장치종속적비트맵에대해알아보자. DDB 구조는다음과같다.
typedef struct tagBITMAP {
LONG bmType;
LONG bmWidth;
LONG bmHeight;
LONG bmWidthBytes;
WORD bmPlanes;
WORD bmBitsPixel;
LPVOID bmBits;
} BITMAP;


• b m T y p e 은비트맵타입이지만항상0이다.
• b m W i d t h 와 b m H e i g h t 는 실제 비트맵 이미지의 폭과 높이다. bmWidthBytes는
bitmap 이미지의한줄에표현될바이트수인데비트맵은word 단위로기록되므로
b m W i d t h B y t e s 는항상짝수다.
• b m P l a n e s 는색상면의개수다.
• b m B i t s P i x e l 은한픽셀에필요한비트의개수다.
• b m B i t s 는실제비트맵데이터를가리키는포인터다. 단, bmBits는반드시c h a r a c t e r
배열, 즉1 바이트배열의포인터이어야한다.


DDB는 CreateB i t m a p() 함수로도쉽게만들수있다. 이함수는간단한장치종속적비
트맵을만들어주는역할을한다. 성능적인측면을고려해볼때, 대체로 CreateBitmap()
함수는 흑백 비트맵을 만들 때 주로 사용하고, 컬러 비트맵을 만들 때에는
CreateCompatibleBitmap()
함수를사용한다. 그이유는C r e a t e B i t m a p() 함수로만들어
진비트맵은S e l e c t O b j e c t() 함수로D C에선택할때속도가느리기때문이다.
그럼C r e a t e B i t m a p() 함수를살펴보자.

HBITMAP CreateBitmap(
int nWidth,
int nHeight,
UINT cPlanes,
UINT cBitsPerPel,
CONST VOID *lpvBits );


이함수가호출되면리턴값으로비트맵, 즉DDB 핸들이리턴된다.
또한CreateCompatibleBitmap() 함수로도DDB를 만들 수 있다. 이함수는hdc를
인자로받아서디바이스컨텍스트와픽셀포맷, 색상수가동일한빈비트맵을만들어
준다.

, 이함수로만들면비트맵의각픽셀은초기화되지않는다.
함수의원형은다음과같다. 주의해서보아야될부분은CreateCompatibleBitmap()
인데, 이함수는 인자로디바이스컨텍스트를받는다. 그이유는SelectObject() 함수
를이용하여 비트맵을DC로 선택할때 빠른성능을내기때문이다.
HBITMAP CreateCompatibleBitmap(
HDC hdc,
int nWidth,
int nHeight );

• nWidth, nHeight는이미지의폭과높이다.
• c P l a n e s 는장치에있는색상면의수이며반드시1이어야한다.
• c B i t s P e r P e l 은픽셀의색상을결정하기위한필요한비트수다.
• l p v B i t s 는비트맵데이터이고반드시워드(2 바이트) 배열로이루어져야한다.
• h d c에는디바이스컨텍스트의핸들을넣어준다.
• n W i d t h 와 n H e i g h t 에는비트맵의폭과높이를설정한다.


이렇게만들어진비트맵은 SelectObject() 함수를통해 메모리디바이스컨텍스트에선택되며해당디바이스컨텍스트에대한 GDI함수는 선택된 비트맵에그려지게된다.
사용이끝난비트맵은DeleteObject() 함수를호출하여제거할수있다.


장치독립적비트맵
다음은 장치 독립적 비트맵의 구조에 대해서 알아보자. DIB는 크게 BITMAPFILEHEADER 와

BITMAPINFO 그리고 비트맵이미지데이터로 이루어져 있다.
 

사용자 삽입 이미지




typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;


• bfType 은 이 파일이 비트맵인지를 식별할 수 있도록 두 바이트로 표시해 두는 것
이며반드시 BM(0x42,0x4d) 이어야한다. bfSize는 비트맵파일의크기다.
• bfReserved1, bfReserved2는 예약되어 있는 값이고 0으로 설정되어 있다.
bfOffBits 는 실제 비트맵 데이터 값과 헤더의 오프셋 값이다. 즉, 이 값은
BITMAPFILEHEADER 와 BITMAPINFO 의 크기다.


BITMAPINFO 구조체는 BITMAPINFOHEADER 구조체와 RGBQUAD 구조체로
이루어져있는데먼저BITMAPINFOHEADER 구조체를살펴보면다음과같다.


typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;

• biSize 는 BITMAPINFOHEADER 구조체의크기를 나타낸다.
• biWi d t h 는비트맵의가로픽셀수, biHeight는비트맵의세로픽셀수다.
• b i P l a n e s 는장치에있는색상면의개수이며 반드시1 이어야한다.
• b i B i t C o u n t 는한픽셀을표현할수있는비트수다.
• b i C o m p r e s s i o n 은 압축 형태를 지정한다. BI_RGB는 압축되지 않은 비트맵이고
BI_RLE8 은8 비트압축, BI_RLE4는4 비트압축을뜻한다.
• b i S i z e I m a g e 는 실제 이미지의 바이트 크기이며 압축되지 않은 비트맵일 경우에는
0이다.
• biX elsPerMeter 는미터당가로픽셀수다.
• biYPelsPerMeter 는미터당세로픽셀수다.
• biClrUsed 는색상테이블의색상 중 실제로 비트맵에서사용되는 색상수를 나타낸
다. 이값이 0이면 비트맵은사용할 수 있는모든색상을사용한다. 이값이 0이아
니라면 RGBQUAD 구조체배열의크기는 이멤버값만큼된다.
• iClrImportant 는 비트맵을 출력하는데 필수적인 색상수를 나타내며 이 값이 0이면
모든색상이 다 사용되어야한다.
RGBQUAD 구조체는다음과같이이루어져있다.
typedef struct tagRGBQUAD {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;


우선다음의GDI 함수를알아보고코드를살펴보자.
CreateCompatibleBitmap( ) 함수
HBITMAP CreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight );

• 이 함수는디바이스 컨텍스트와 호환되는, 즉픽셀 포맷과 색 상수 등이 같은 비트
맵을 만드는데 CreateBitmap( ) 함수처럼 비트맵 이미지 데이터를 초기화할 수는
없다. 단순히폭과높이만설정할수있다.
• 함수를사용한후에는반드시DeleteObject() 함수를호출해야한다.


CreateCompatibleDC( ) 함수
HDC CreateCompatibleDC(HDC hdc );

• 이 함수는 장치의 디바이스 컨텍스트와 호환되는디바이스 컨텍스트, 즉 메모리디바이스 컨텍스트를만든다. 비트맵을 디바이스 컨텍스트에 선택할 때 이 함수를 이용하여 메모리 dc를 만들어 선택한다. 사용한 후에 반드시 DeleteDC() 함수를 호출한다.
• hdc 인자로N U L L을전달할때에는디폴트로현재디스플레이화면의디바이스컨
텍스트와호환되는디바이스컨텍스트핸들을반환하게된다.

SelectObject () 함수
HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj );

• 이 함수는 디바이스 컨텍스트에GDI 객체를선택할수 있게 한다. GDI 객체란펜이
나 브러시, 폰트, 비트맵 등을 말하는데 여기에서는 비트맵을 디바이스 컨텍스트에
선택하기 위해서 사용한다. GDI 객체는반드시 디바이스 컨텍스트에 선택되어진후
사용되기때문에GDI 객체를사용할때에는반드시이 함수를사용해야된다. 이함
수를 사용하면 반환 값으로 선택되기 전의 GDI 객체가반환되는데이 값을 받아 두
었다가 GDI 객체를사용한 후, 반드시 디바이스 컨텍스트에 이전 GDI 객체를 선택
한다.


BitBlt() 함수

BOOL BitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop );

• DDB를 뿌리는데 가장 유용한 이 함수는 내부적으로 그리려는 타깃과 소스의 픽셀
포맷이 다르면 타깃의 픽셀 포맷에 맞게 픽셀 포맷을 변환하여 뿌린다. 또한
dwRop 인자에의해서여러가지로그릴 수도있다. 여기에서는 SRCCOPY 를 사용
해단순히타깃에원본을복사했다.

신고

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

Microsoft XML Core Service(MSXML)  (0) 2007.05.05
C++을 사용해 바이트 배열에 저장된 DIB정보를 DIB메모리 블럭 만들기  (2) 2007.03.31
DIB/DDB 구조  (0) 2007.03.30
CListBox  (0) 2007.02.21
부요리눅스의 클립보드  (0) 2007.02.20
Virtual Network Computing  (0) 2007.02.14

DIB구조

Projects/CoVNC 2007.02.05 20:54 Posted by soulfree >동네청년<
비트맵 이미지에는 두가지 종류가 있는데 DDB와 DIB가 바로 그것입니다.

DDB(Device Dependent Bitmap)은 이름을 봐도 알수 있드시 장치에 의존하여 비트맵을 출력하는 방식입니다.

DDB는 원래 윈도우 3.0 버전 이하 버전에서 사용하던 포맷인데, DDB는 별도의 팔레트 정보를 파일안에 포함하지 않고 있으므로, 실행 시키는 곳의 장치에 따라 다른 색깔의 이미지가 보여질 수 있습니다. 그에반해 DIB(Device Independent Bitmap) 의 경우 장치에 독립된 비트맵이기 때문에 어떤 장치에서 실행을 시키더라도 같은 모습의 비트맵 이미지를 볼수 있습니다.

물론 DIB의 중요도가 훨씬 더 높고 우리가 이번 시간에 알아볼 비트맵 포맷도 DIB 이지만, DDB 역시도 아직까지 많이 사용되고 있으므로 무시해도 되는 개념은 아님을 알아두시길 바랍니다.

DDB는 비트맵 이미지에 대한 간단한 정보와 이미지 비트만으로 구성되어져 있기때문에 아주 간단하게 구성되어 있지만, DIB는 꽤나 복잡한 구조로 이루어져 있습니다.


이런식으로 구성되어져 있는데, 이제 하나하나 그 멤버들을 살펴보도록 하겠습니다.

BITMAPFILEHEADER

typedef struct tagBITMAPFILEHEADER
{
   WORD    bfType;
   DWORD  bfsize;
   WORD    bfReserved1;
   WORD    bfReserved2;
   DWORD  bfOffBits;
} BITMAPFILEHEADER;

bfType Bitmap 파일의 형식이 기록되는 부분입니다.
비트맵 파일은 반드시 bfType의 값이 BM(0x42, 0x4d)이어야 합니다.
bfSize비트맵 파일의 크기를 바이트 단위로 나타냅니다.
bfReserved1  항상 0으로 설정해주면 됩니다. 현재 사용되지 않는 비트입니다.
bfReserved2마찬가지로 0으로 설정해주시면 됩니다.
bfOffBits이 값은 BITMAPFILEHEADER, BITMAPINFOHEADER, RGBQUAD
3개 구조체의 크기를 더한 값으로 실제 이미지 비트의 OffSet을 의미합니다.

BITMAPFILEHEADER은 구조체명에서도 알수 있듯이, 비트맵 이미지 그 자체에 대한 정보보다는, 비트맵 파일에 대한 정보를 주로 가지고 있습니다. 따라서 비트맵 파일을 DIB 형식으로 저장할 때에만 쓰이고, 화면에 출력할때에는 쓰이지 않는 구조체입니다.

BITMAPINFOHEADER

typedef struct tagBITMAPINFOHEADER
{
   DWORD biSize;
   LONG biWidth;
   LONG biHeight;
   WORD biPlanes;
   WORD biBitCount;
   DWORD biCompression;
   DWORD biSizeImage;
   LONG biXPelsPerMeter;
   LONG biYPelsPerMeter;
   DWORD biClrUsed;
   DWORD biClrImportant;
} BITMAPINFOHEADER;

biSize 이 구조체의 크기를 나타냅니다.
biWidth비트맵의 가로 픽셀수.
biHeight비트맵의 세로 픽셀수.
이 값이 양수이면, 바텀업 방식이라고 하며, 출력시, 아래쪽 부터 출력을 해야 합니다.
또 이 값이 음수이면, 탑다운 방식이라고 하며, 출력시, 위쪽부터 차례로 출력 합니다.
biPlanes비트맵의 플래인 개수를 나타내는데 이 값은 반드시 1로 고정되어야 합니다.
biBitCount한 픽셀이 몇개의 비트로 이루어지는가를 나타내며 이 값에 따라 픽샐이 가질수 있는 색상수가 결정됩니다.
1이면 흑백, 4이면 16색, 8이면 256색... 과 같이, 2의 제곱승으로 계산됩니다.
biCompression압축 방식을 나타내는데요. 반드시 바텀업 방식일때만 압축이 가능하며,
이 값이 BI_RGB이면 압축되지 않았다는 것을 의미하고,
BI_RLE8이면 8비트 압축, BI_RLE4이면 4비트 압축으로 압축되어 있는 것입니다.
biSizeImage이미지의 크기를 바이트 단위로 나타내며 BI_RGB(압축이 안된 상태) 비트맵에서의 이 값은 0입니다.
biXPelsPerMeter가로 해상도를 의미합니다.
biYPelsPerMeter세로 해상도를 의미합니다.
biClrUsed비트맵에 사용된 색상수를 의미하며, 이값에 따라 RGBQUAD의 배열을 메모리 할당하여서 읽어오시면 됩니다.
이 값이 0이면 모든 색깔을 다 사용한다는 의미입니다.
biClrImportant 비트맵을 출력하는데 필수적인 색상수를 나타내며, 이 값이 0이면 모든 색상을 다 사용한다는 의미입니다.

이 구조체에는 이미지의 폭, 높이, 해상도, 팔레트 정보등 비트맵의 실제 구성 정보가 기록 되어져 있습니다.

RGBQUAD는 팔레트를 사용하는 경우에만 사용되며 팔레트를 쓰지 않는 경우에는 사이즈가 0입니다. 우리는 팔레트를 사용하지 않으므로, RGBQUAD에 대한 내용은 언급하지 않고 넘어가도록 하겠습니다.

신고

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

Java DataFlavor를 이용한 클립보드 사용  (0) 2007.02.07
DIB 형식 파일로 저장  (0) 2007.02.06
DIB구조  (0) 2007.02.05
DIB를 DDB로 변환  (0) 2007.02.05
BMP를 DDB로 변환  (0) 2007.02.01
비트맵 파일 저장하고 읽기  (0) 2007.02.01
TAG Bitmap, bmp, DDB, DIB

DIB를 DDB로 변환

Projects/CoVNC 2007.02.05 17:14 Posted by soulfree >동네청년<


출처 네이버 블로그 > 탑건매직
http://blog.naver.com/topgunmagic/120033732401


ReadDIB.zip

* DIB

1. 직접 비트맵을 파싱하여 처리

2.  DIB를 DDB 로 변환 (2가지)

[코드]

case WM_PAINT:
  hdc=BeginPaint(hWnd, &ps);

  // 1) loadimage를 이용한 변환  (DDB->DIB)  ----1
  hbit = (HBITMAP) LoadImage( NULL, "dragon00.bmp",
     IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );

  MemDC=CreateCompatibleDC(hdc);
  SelectObject(MemDC,hbit);

  BitBlt(hdc,0,0,96,96,MemDC,0,0,SRCCOPY);
 
 
 
  // DDB로 변환하여 그리기 ---------------------2
/* hbit=CreateDIBitmap(hdc,(BITMAPINFOHEADER *)ih,
     CBM_INIT, (PBYTE)fh+fh->bfOffBits,
     (BITMAPINFO)ih,DIB_RGB_COLORS);   

       MemDC=CreateCompatibleDC(hdc);
  SelectObject(MemDC,hbit);

  BitBlt(hdc,0,0,ih->biWidth,ih->biHeight,MemDC,0,0,SRCCOPY);
*/

  // DIB로 그리기  -----------------------------3
  if (fh) {
  SetDIBitsToDevice(hdc,0,0,bx,by,0,0,0,by,pRaster,(BITMAPINFO *)ih,DIB_RGB_COLORS);
  //StretchDIBits(hdc,0,0,bx*2,by*2,0,0,bx,by,pRaster,(BITMAPINFO *)ih,DIB_RGB_COLORS,SRCCOPY);
  }
  EndPaint(hWnd, &ps);
  return 0;



// 비트맵 파싱

BITMAPFILEHEADER *fh=NULL;
BITMAPINFOHEADER *ih;
BITMAPINFO* info;
int bx,by;
BYTE *pRaster;


// DDB 변환용
HBITMAP hbit;



void LoadDIB(char *Path)
{
HANDLE hFile;
DWORD FileSize, dwRead;

hFile=CreateFile(Path,GENERIC_READ,0,NULL,
  OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile==INVALID_HANDLE_VALUE) {
  return;
}

FileSize=GetFileSize(hFile,NULL);

if (fh)
  free(fh);


// 헤더 정보 읽기
fh=(BITMAPFILEHEADER *)malloc(FileSize);
ReadFile(hFile,fh,FileSize,&dwRead,NULL);
CloseHandle(hFile);


  // 데이타의 위치
pRaster=(PBYTE)fh+fh->bfOffBits;
// 비트맵 info header
ih=(BITMAPINFOHEADER *)((PBYTE)fh+sizeof(BITMAPFILEHEADER));


  // info
/*info->bmiHeader = ih;
info->bmiColors = (RGBQUAD)((PBYTE)fh+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER));*/



bx=ih->biWidth;
by=ih->biHeight;

  }




신고

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

DIB 형식 파일로 저장  (0) 2007.02.06
DIB구조  (0) 2007.02.05
DIB를 DDB로 변환  (0) 2007.02.05
BMP를 DDB로 변환  (0) 2007.02.01
비트맵 파일 저장하고 읽기  (0) 2007.02.01
CF_BITMAP 사용하기  (0) 2007.01.30
TAG DDB, DIB, 비트맵

BMP를 DDB로 변환

Projects/CoVNC 2007.02.01 14:03 Posted by soulfree >동네청년<

출처 : 블로그 > Priss In The Attic
http://blog.naver.com/priling/80012774193
===========================================

[부대에서 구린 컴퓨터로나마 비주얼C를 돌려볼 수 있다는 것이 얼마나 고마운지 모릅니다.

2년이나 쉬어서 그런지 코드 한 줄 쓰기도 낯설더군요.

그래도 옛 생각 새록새록 나는게 기분이 삼삼~하네요

무려 3일 동안이나 삽질하던거를 잊어버리지 않도록 그냥 한번 써봤습니다.]



BMP 파일은 DIB이다. 윈도우즈 프로그램에서 이것을 이용하기 위해서는 내부적으로 DDB로 바꾸어 주는 편이 낫다. DIB의 형식을 유지한 채로 메모리 상에서 이용하는 방법이 없는 것은 아니지만 (CreateDIBSection함수) 이렇게 되면 당연히 이미지 처리 속도가 늦어지게 된다.
DIB라는 것이 화면의 DC와는 별개로 자체적인 컬러 포맷을 가진 이미지 형식이므로 이것을 DC에서 출력하기 위해선 DDB로 변환해 DC와 같은 포맷으로 만들어 주어야만 원만한 처리 속도를 기대할 수 있다.

1. BMP 파일을 어떻게 화면에 뿌릴까?
도스 시절 때처럼 생각하면 헤맨다. 도스 때에 그냥 메모리에 그림 파일을 읽어 올려서 화면 컬러 포맷에 맞추어서 이미지 데이터를 비디오 메모리에 전송하면 되었지만, 윈도우는 DC라는 시스템이 있어서 조금 거쳐가야 한다.

즉 읽어들인 그림 파일을 프로그래머 임의의 방식으로 가지고 있다가 화면에 뿌려주는 게 아니고 DC에 보관했다가 DC간의 메모리 전송으로 화면에 출력해야 한다는 것이다.

CreateCompatibleDC 함수를 사용해 메모리 상에 화면 DC와 같은 포맷의 DC를 만든다. 이것을 memDC라고 하면, memDC에서 SelectObject 함수를 사용해 HBITMAP 형식의 이미지를 붙일 수 있다. (이것은 DC에서 브러시나 펜 등을 설정하는 것과 같다. 한번에 하나의 비트맵이 선택될 수 있다.)

이제 우리는 두개의 DC를 가지고 있다.
주화면 DC (hDC라고 하자)와 memDC..
두 개의 DC끼리는 BitBlt 함수를 사용해 이미지를 복사할 수 있다.


2. 그럼 BMP 파일을 DDB로 바꾸는 방법은?
SelectObject 함수로 이미지를 DC에 선택하려면 DDB가 필요하다. 그러나 BMP 파일은 DIB이기 때문에 변환이 필요하다. 다음 함수가 바로 DIB를 DDB로 한방에 바꾸어 주는 놈이다.

HBITMAP CreateDIBitmap(
  HDC hdc,                        // handle to DC
  CONST BITMAPINFOHEADER *lpbmih, // bitmap data
  DWORD fdwInit,                  // initialization option
  CONST VOID *lpbInit,            // initialization data
  CONST BITMAPINFO *lpbmi,        // color-format data
  UINT fuUsage                    // color-data usage
);

인자 설명 ::
HDC hdc  => 생성될 DDB의 컬러 포맷을 참조할 DC (주화면 DC 핸들을 넣으면 된다)
CONST BITMAPINFOHEADER *lpbmih  => 말그대로 BMP파일의 BITMAPINFOHEADER
DWORD fdwInit  => CBM_INIT라는 상수를 넣으면 된다 (자세한 건 msdn참조)
CONST VOID *lpbInit  => 이미지 데이터 블록의 포인터를 넣어주자
CONST BITMAPINFO *lpbmi  => BMP 파일의 BITMAPINFO의 포인터를 넘기면 된다
UINT fuUsage  => 디스플레이의 현재 색비트 수가 8이하라면 DIB_PAL_COLORS, 16이상이면 DIB_RGB_COLORS 이다


3. 그외 겪었던 잡다한 문제들
(1) 색깔이 이상하게 나온다?
처음에 겪은 버그. 이미지의 모양은 제대로 출력 되지만 색깔이 이상했다.
RGB의 순서가 뒤바뀐 듯한 느낌. 실제로
빨강이 초록으로
초록이 파랑으로
파랑이 빨강으로 표시되는 현상이 생겼다.

이것은 작은 실수에 의한 것이다. 그러나 찾기는 쉽지 않다. 게다가 이미지의 모양은 제대로 출력되면서 색깔만이 이상하게 나오기 때문에 속기 쉬워서 컬러 포맷의 비트 변환에서 계속 문제를 찾느라 시간을 허비했다. 이 버그는 이미지의 왼쪽 세로 라인 하나가 오른쪽에 잘려붙여져 나타나는 현상을 동반한다.
이건 다름아니라.. 이미지 데이터 블록의 포인터를 잘못 잡은 탓이다.
BMP파일에서 이미지 데이터 블록을 읽어들일 때 한 바이트라도 빗나가면 RGB의 순서가 뒤바뀌게 되는 것이다. BMP 파일에서 헤더부터 순차적으로 읽어들이다가 조금이라도 어긋나면 이렇게 되버린다. 차라리 나은 방법은 fseek를 사용해서 BMP파일의 뒤에서 위치를 재어 들어가는 것이다.

// bmi는 BITMAPINFO 구조체, pixels는 이미지 데이터를 보관할 포인터
fseek(fp, -(int)(bmi->bmiHeader.biSizeImage), SEEK_END);
pixels = (unsigned char*) malloc(bmi->bmiHeader.biSizeImage);
fread(pixels, bmi->bmiHeader.biSizeImage, 1, fp);


(2) 8비트 BMP를 읽어들일 때 팔레트 문제
8비트라고 해서 별다른 게 있는 것은 아니다. CreateDIBitmap 함수는 컬러 포맷에 관계없이 대상 DC와 BITMAPINFO 구조체 정보를 이용해 양쪽을 잘 매치해준다.
다만, 8비트는 팔레트를 파일에서 읽어줘야 한다는 문제가 있다.
어려움을 겪은 부분은 BIMAPINFO 구조체의 팔레트 부분이었다.

typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader;
  RGBQUAD          bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;

두번째 멤버변수가 바로 팔레트를 위한 부분인데, 문제는 배열의 크기가 1이라는 것이다.
8비트 팔레트는 256개의 RGBQUAD가 필요한데 배열을 확보하기 위해서 약간의 꽁수가 필요하다.

BITMAPINFO* bmi=NULL;
bmi = (BITMAPINFO*) malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 255);

fread(bmi, sizeof(BITMAPINFOHEADER), 1, fp);
if (bmi->bmiHeader.biBitCount == 8)
fread(bmi->bmiColors, sizeof(RGBQUAD), 256, fp);

그냥 변수로 선언하면 팔레트엔 1개의 엔트리 뿐이게 되므로 포인터 선언을 한 후 메모리 할당을 해주는데 이때 255개의 RGBQUAD 분량의 메모리를 더 잡아주면 이미 BITMAPINFO에 들어 있는 1개의 엔트리에 255개 만큼의 엔트리가 더해지게 된다.
그 후에 BITMAPINFOHEADER를 읽어들이면 다음은 팔레트 차례가 된다.




// BMP 읽어서 화면에 뿌려주는 코드의 핵심부
HBITMAP hbm;
:
:
BMPLoad("a.bmp");
hdc = GetDC(hWnd);
hbm = CreateDIBitmap(hdc, &(bmi->bmiHeader), CBM_INIT, pixels, bmi, DIB_RGB_COLORS);
memDC = CreateCompatibleDC(hdc);
SelectObject(memDC, hbm);
BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, memDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd,hdc);   




// BMP 로드 함수
BITMAPFILEHEADER bf;
BITMAPINFO* bmi=NULL;
unsigned char* pixels=0;
:
:
int BMPLoad(char* filename)
{

FILE* fp;
fp = fopen(filename, "rb");

bmi = (BITMAPINFO*) malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 255);

fread(&bf, sizeof(BITMAPFILEHEADER), 1, fp);
fread(bmi, sizeof(BITMAPINFOHEADER), 1, fp);
if (bmi->bmiHeader.biBitCount == 8)
{
  fread(bmi->bmiColors, sizeof(RGBQUAD), 256, fp);
}

       // 픽셀 데이터 읽기
fseek(fp, -(int)(bmi->bmiHeader.biSizeImage), SEEK_END);
pixels = (unsigned char*) malloc(bmi->bmiHeader.biSizeImage);
fread(pixels, bmi->bmiHeader.biSizeImage, 1, fp);

fclose(fp);


return TRUE;
}


색깔 바뀌는 버그는 군대 오기 전에도 DDRAW 만지면서 한 번 당해서 고생했던 기억이 난다.
문제는 다 해결하고 나서야 어? 전에도 이랬던 적이 있었던거 같애! 거 희한하네~ 하는게 문제지.

신고

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

DIB구조  (0) 2007.02.05
DIB를 DDB로 변환  (0) 2007.02.05
BMP를 DDB로 변환  (0) 2007.02.01
비트맵 파일 저장하고 읽기  (0) 2007.02.01
CF_BITMAP 사용하기  (0) 2007.01.30
클립보드에서 이미지 읽기  (0) 2007.01.25
TAG bmp, DDB, DIB