'모종의 음모/Bitmap 조작'에 해당되는 글 2건

  1. 2009.06.25 원하는 크기안에 꼭 맞는 크기얻기
  2. 2009.03.28 완전 날로먹는 Bitmap 구조분석하기 6
적절한 제목이 안떠오르는데..
아무튼, 특정 이미지를 특정 사이즈의 사각형(Rectangle) 에 맞도록 출력해주는 일이 있는데
예를들면 탐색끼의 미리보기처럼, 100x100사이즈의 미리보기에 어떠한 크기의 이미지가 오더라도
벗어나지 않도록 적절한 크기의 이미지를 출력해주는 함수가 필요했다.

한달정도 깔끔한 알고리즘을 고심하다가 GG치고 다른 방법으로 구현했었는데
약간의 오작동을 보여서, 또 다시 고민을 하다가 어제 퇴근길 지하철에서 !! 했다.


#define min(a,b)    (((a) < (b)) ? (a) : (b))
#define max(a,b)    (((a) < (b)) ? (b) : (a))
#define FALSE               0 
#define TRUE                1 

#define CALC_MULTIPLIER	1000

typedef struct tagRECT {
	int		x1, y1, x2, y2;
} RECT;

RECT getRectsize(RECT dispRect, RECT imgRect)
{
	RECT ret;
	unsigned int Rx, Ry;
	unsigned char bhorAxis = FALSE;
	unsigned char bscale = FALSE;
	
	Rx = imgRect.x2 * CALC_MULTIPLIER / dispRect.x2;
	Ry = imgRect.y2 * CALC_MULTIPLIER / dispRect.y2;
	if(min(Rx,Ry) > CALC_MULTIPLIER)
	{
		if(Rx > Ry)
			bhorAxis = TRUE;
		else	bhorAxis = FALSE;
		bscale = TRUE;
	}
	else if(max(Rx,Ry) > CALC_MULTIPLIER)
	{
		if(Rx > Ry)
			bhorAxis = TRUE;
		else	bhorAxis = FALSE;
		bscale = TRUE;
	}

	if(bscale == TRUE)
	{
		if(bhorAxis == TRUE)
		{
			ret.x2 = dispRect.x2;
			ret.y2 = imgRect.y2 * dispRect.x2 / imgRect.x2;
			ret.x1 = dispRect.x1;
			ret.y1 = dispRect.y1 + (dispRect.y2 - ret.y2) / 2;
		}
		else
		{
			ret.y2 = dispRect.y2;
			ret.x2 = imgRect.x2 * dispRect.y2 / imgRect.y2;
			ret.x1 = dispRect.x1 + (dispRect.x2 - ret.x2) / 2;
			ret.y1 = dispRect.y1;
		}
	}
	else
	{
		ret.x2 = imgRect.x2;
		ret.y2 = imgRect.y2;
		ret.x1 = dispRect.x1 + (dispRect.x2 - imgRect.x2) / 2;
		ret.y1 = dispRect.x2 + (dispRect.y2 - imgRect.y2) / 2;
	}
	return ret;
}


간단한 구현원리는

1. 가로길이의 비율, 세로길이의 비율을 얻는다. (원본 크기 / 넣어야 할 크기)
   Rx, Ry - 가로 세율의 비율
   Ix, Iy - 원본 이미지의 가로세로 크기
   Dx, Dy - 표시할 사각형의 크기
   Rx = Ix / Dx
   Ry = Iy / Dy
2. 만약에 축소가 필요 하다면, 위의 비율은 1을 넘게 되고, 축소가 필요 없으면 1 이하가 나온다.
3. 비율값들이 모두 1을 넘으면 어느 방향이던지 간에 축소를 해주어야 함
4. 비율값들이 둘다 1이하면 그대로 출력하면 됨
5. 비율값이 하나만 1보다 크면, 작은쪽 값이 맞추어 축소함

'모종의 음모 > Bitmap 조작' 카테고리의 다른 글

완전 날로먹는 Bitmap 구조분석하기  (6) 2009.03.28
Posted by 구차니
300번째 글 기념(응?)
완전 날로먹는 Bitmap 구조 분석하기 입니다 ^^;
Visual Studio C++ 6.0 프로젝트이며, 헤더만 있다면 다른 플랫폼도 이식 가능할 듯 합니다.


알림 : 네이버 블로그 / 구차니의 잡동사니 모음에서 같은 거 있는데! 라고 하시면..
        동일 인물입니다라고 밖에 답변을 해드릴게 없습니다 -ㅁ-!

typedef struct tagBITMAPFILEHEADER
{
  WORD  bfType;
  DWORD bfSize;
  WORD  bfReserved1;
  WORD  bfReserved2;
  DWORD bfOffBits;
} BITMAPFILEHEADER,  *PBITMAPFILEHEADER;
WORD bfType;          // 위의 첫 바이트 BM 으로 Bitmap 이라는 의미를 지닌 헤더
DWORD bfSize;         // 0x00075736 = 481078 bytes, 파일 전체 크기(헤더 포함한 전체 파일)
WORD bfReserved1;  // 0x0000 으로 사용하지 않는 부분
WORD bfReserved2;  // 0x0000 으로 사용하지 않는 부분
DWORD bfOffBits;      // 현재 위치로부터 실제 데이터가 존재하는 곳 까지의 거리

bfOffBits는 약간의 설명이 필요하다. 일단 256색상 이하의 비트맵은 indexed color 방식으로
팔레트를 이용하게 된다. 팔레트 이후에는 1pixel = 1byte로 연결된 인덱스들이 나열되어 있다.
그런 이유로, 팔레트에 저장된 색상의 갯수가 다르거나, 팔레트를 사용하지 않는다면 이 값은 상당히 다른 값을 보이게 된다.
자세한 내용은 아래의 팔레트를 참고하면 된다.

typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO, *PBITMAPINFO;
256 색 이하의 이미지라면, RGBQUAD는 팔레트로 사용되고,
16bit 이상의 이미지라면 이 내용에 바로 pixel별 색상이 들어간다.

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,  *PBITMAPINFOHEADER;
DWORD biSize;                      // BITMAPINFO 헤더의 크기
LONG  biWidth;                      // 이미지의 넓이(화면상에 보이는 크기)
LONG  biHeight;                     // 이미지의 높이(화면상에 보이는 크기)
WORD  biPlanes;                    // 이미지의 장수(bitmap은 layer가 존재하지 않으므로 항상 1)
WORD  biBitCount;                  // 한 픽셀의 컬러 비트수(256컬러는 2^8 이므로 8이 표기됨)
DWORD biCompression;          // 비트맵이 압축이 되었는지 어떠한 방식으로 압축이 되었는지 표시
DWORD biSizeImage;
LONG  biXPelsPerMeter;
LONG  biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;

typedef struct tagRGBQUAD
{
  BYTE rgbBlue;
  BYTE rgbGreen;
  BYTE rgbRed;
  BYTE rgbReserved;
} RGBQUAD;

BYTE rgbBlue;            // RGB 중 파랑(Blue)에 대한 값
BYTE rgbGreen;          // RGB 중 녹색(Green)에 대한 값
BYTE rgbRed;             // RGB 중 빨강(Red)에 대한 값
BYTE rgbReserved;     // 사용하지 않음

---------------------------------------------------------------------------------------------------
1.
bitmap은 단순하게, 하나의 pixel에 대한 RGB 정보나 index 정보를 이용하여 이미지를 표시한다.
pixelPicture Element의 약자이며, 우리가 말하는 점 하나를 의미한다.

2.
비트맵은 4사분면을 기준 좌표로 사용하며,
좌상단이 (0.0)이다. 하지만 pc에서는 1사분면을 기준 좌표로 사용하므로 우하단이 (0,0)이다.
그런 이유로, 좌표대로 출력을 하면 비트맵은 상하가 뒤집힌 채로 나오게 된다.
(다르게 말하면, 저장시에 데이터는 상하가 뒤집힌 채로 저장되어 있다)

3.
비트맵은 특정 크기의 데이터를 한번에 전송하기 위해 DMA(Direct Memory Access)나 BLIT(Bit-Block Transfer)를
사용한다. 그런 이유로 특정 블럭을 맞추어 주어야 하고, 그렇기 때문에 이미지는 byte align이나 DWORD align
사용하게 된다(DWORD = 4bytes = 64bit) 이 방법은 몇 비트 이미지냐에 따라 달라지게 되는데,
기본적으로는 4byte align을 맞춰준다.

4.
256색 미만의 비트맵은 팔레트라는 것을 사용한다. (팔레트는 RGBQUAD 구조체 사용)
이러한 팔레트는 8bit로 표현이 가능하므로, 256가지의 색상을 팔레트로 주로 사용가능하다.
예를 들어

이러한 팔레트를 만들고, 번호만으로 각 픽셀별로 색상을 지정해준다. 그렇다면 상당한 저장 공간을 아낄 수 있다.
그런 이유로, 팔레트를 사용하는 경우에는 팔레트를 Lookup(참조) 하여 변환을 해야하는 작업이 추가되게 된다.
grayscale의 경우에는 256color RGBQUAD 구조체
팔레트가 없을 경우(jpeg 변환등) for(i=0;i<256;i++) ; 을 이용하여 생성하면 된다.

5.
이유는 모르겠지만, 24bit 비트맵의 경우는 RGBQUAD가 아닌 RGBTRIPLE이라는 구조를 사용한다.

6. 정리를 하자면
1bit - RGBQUAD 팔레트 2개 / 1byte = 8 pixel / 1byte align 4byte align(2009.10.12 windows 그림판 확인)
2bit -
RGBQUAD 팔레트 4개 / 1byte = 4 pixel / 1byte align
4bit - RGBQUAD 팔레트 16개 / 1byte = 2 pixel / 1byte align
8bit - RGBQUAD 팔레트 256개 / 1byte = 1 pixel / 4byte align
16bit - RGBTRIPLE / 2byte = 1 pixel / 4byte align
24bit - RGBTRIPLE / 3byte = 1 pixel / 4byte align (width * 3)을 한뒤 align
32bit - RGBQUAD  / 4byte = 1 pixel / 4byte align 픽셀이 이미 4의 배수이므로 align 안해도 상관없음

 BITMAPFILEINFO
 http://msdn.microsoft.com/en-us/library/dd183374(VS.85).aspx
 BITMAPINFO  http://msdn.microsoft.com/ko-kr/library/dd183375(en-us,VS.85).aspx
 BITMAPINFOHEADER  http://msdn.microsoft.com/ko-kr/library/dd183376(en-us,VS.85).aspx
 RGBQUAD  http://msdn.microsoft.com/ko-kr/library/dd162938(en-us,VS.85).aspx

 BITMAPCOREINFO  http://msdn.microsoft.com/en-us/library/dd183373(VS.85).aspx
 BITMAPCOREHEADER  http://msdn.microsoft.com/en-us/library/dd183372(VS.85).aspx
 RGBTRIPLE  http://msdn.microsoft.com/en-us/library/dd162939(VS.85).aspx

'모종의 음모 > Bitmap 조작' 카테고리의 다른 글

원하는 크기안에 꼭 맞는 크기얻기  (0) 2009.06.25
Posted by 구차니