'bmp'에 해당되는 글 2건

  1. 2009.10.24 [BMP] BMP 파일의 구조
  2. 2009.10.11 [AIR] AIR에서 BMP 파일을 읽어서 표현하기
파일 구조2009.10.24 23:08

BMP 파일의 이미지 파일 중 가장 기본적인 파일 형태입니다.

BMP 파일의 특징은 압축이 되어 있지 않아 이미지를 읽어 들이는데에 별도의 연산이 필요하지 않기 때문에 JPG나 GIF 형태의 포멧보다 처리속도가 상당히 빠르며 이미지 파일 포멧 중 가장 화질이 좋은 반면 압축처리를 하지 않음으로써 파일의 용량이 큰 단점을 가지고 있습니다.

1. BMP 파일의 종류

DDB (Device Dependent Bitmap) : 장치에 종속적인 비트맵.
컴퓨터 시스템의 디스플레이 장치가 가지고 있는 부가적인 정보를 이용하여 출력합니다.

장점 : 디스플레이의 정보를 이용함으로 출력 속도가 빠릅니다.
단점 : 다른 종류의 디스플레이 장치에서는 제대로 표현되지 않을 수 있습니다.

DIB (Device Independent Bitmap) : 장치에 독립적인 비트맵.
디바이스(장치)가 가지고 있는 정보를 이용하지 않고 파일 자체적으로 Bitmap을 출력하기 위한 모든 정보를 가지고 있습니다.

장점 : Bitmap을 출력하기 위한 모든 정보를 가지고 있어서 어떠한 디스플레이 장치에서도 동일한 이미지를 표현할 수 있습니다.
단점 : DDB 방식보다 출력속도가 느립니다.

위와 같이 BMP에는 두가지 종류가 존재합니다. 우리가 흔히 보는 bmp 확장자를 가지고 있는 이미지 파일은 DIB 방식으로 저장된 Bitmap 데이타이고 이 파일을 읽어들여 출력하기 위해서 재정의된 형태가 DDB 입니다. 물론, bmp확장자를 가진 파일이 꼭 DIB방식으로 저장된 파일이라고는 할 수 없지만 다양한 시스템에서 사용하기 위하여 현재 bmp 파일로 저장 되어지는 형태는 거의 DIB라고 생각하시면 됩니다.

2. BMP 파일의 구조

 파일 정보 (Bitmap File Header)
 이미지 정보 (Bitmap Info Header)
 색상 테이블 (Pallette)
 이미지의 실제 데이타

파일 정보 (Bitmap File Header)

typedef struct tagBITMAPFILEHEADER {
   WORD bfType; // 파일의 타입 (Bitmap 파일은 반드시 0x42, 0x4D 'BM' 이라고 되어 있어야 함)
   DWORD bfSize; // 파일의 크기 (Byte)
   WORD bfReserved1; // 예약된 값 Reserved (예비값으로 사용되진 않는다. 0x00)
   WORD bfReserved2; // 예약된 값 Reserved (예비값으로 사용되진 않는다. 0x00)
   DWORD bgOffBits; // 실제 이미지 데이타의 offset (파일 정보, 이미지 정보, 색상 테이블 구조체의 크기를 더한 값)
} BITMAPFILEHEADER

 Offset
 Offset  Description
 0x00  파일의 타입 (Bitmap 파일은 반드시 0x42, 0x4D 'BM' 이라고 되어 있어야 함)
 0x02  파일의 크기 (Byte)
 0x06  예약된 값 Reserved (예비값으로 사용되진 않는다. 0x00)
 0x08  예약된 값 Reserved (예비값으로 사용되진 않는다. 0x00)
 0x0A  실제 이미지 데이타의 offset (파일 정보, 이미지 정보, 색상 테이블 구조체의 크기를 더한 값)
(Type : WORD - 2byte, DWORD - 4byte)

이미지 정보 (Bitmap Info Header)

typedef struct tagBITMAPINFOHEADER {
   DWORD biSize; // 이 구조체의 크기
   LONG biWidth; // 비트맵의 가로 픽셀 수 (넓이)
   LONG biHeight; // 비트맵의 세로 픽셀 수 (높이)
   WORD biPlanes; // 비트맵의 플래인 수 (반드시 1로 고정되어야 한다.)
   WORD biBitCount; // 한 픽셀이 가지는 색의 수를 비트로 나타냄 (2의 제곱승으로 표현 - 1이면 흑백(2^1), 4이면 16색(2^4) ... )
   DWORD biCompression; // 압축방식 (BI_RGB : 압축x, BI_RLE4 : 4bit 압축, BI_RLE8 : 8bit 압축)
   DWORD biSizeImage; // 이미지의 크기 (byte)
   LONG biXPelsPerMeter; // 가로 해상도 (미터당 가로 픽셀)
   LONG biYPelsPerMeter; // 세로 해상도 (미터당 세로 픽셀)
   DWORD biClrUsed; // 비트맵에 사용된 색상 수 (0일 경우 모든 색상을 다 사용한다는 의미)
   DWORD biClrImportant; // 비트맵 출력시 필수적인 색상 수 (0일 경우 모든 색상을 다 사용한다는 의미)
} BITMAPINFOHEADER;

 Offset 
0x0E  이미지 정보(Bitmap Info Header)의 크기
0x12  비트맵의 가록 픽셀 수 (넓이)
0x16  비트맵의 세로 픽셀 수 (높이)
0x1A  비트맵의 플래인 수 (반드시 1로 고정되어야 한다.)
0x1C  한 픽셀이 가지는 색의 수를 비트로 나타냄 (2의 제곱승으로 표현 - 1이면 흑백(2^1), 4이면 16색(2^4) ... )
0x1E  압축방식 (BI_RGB : 압축x, BI_RLE4 : 4bit 압축, BI_RLE8 : 8bit 압축) BI_RGB(압축x)일 경우 이 값은 0
0x22  이미지의 크기 (byte)
0x26  가로 해상도 (미터당 가로 픽셀) 거의 사용되지 않음
0x2A  세로 해상도 (미터당 세로 픽셀) 거의 사용되지 않음
0x2E  비트맵에 사용된 색상 수 (0일 경우 모든 색상을 다 사용한다는 의미)
0x32  비트맵 출력시 필수적인 색상 수 (0일 경우 모든 색상을 다 사용한다는 의미)
0x36  비트맵 데이타

색상 테이블 (0x36)

사용하는 경우도 있고 사용하지 않는 경우도 있다.
사용할 경우 첫번째 색상의 BGR, 두번째 색상의 BGR 순으로 테이블이 생성 됩니다.

저작자 표시 비영리
신고

'파일 구조' 카테고리의 다른 글

[BMP] BMP 파일의 구조  (0) 2009.10.24
[JPEG] JPEG의 파일구조  (0) 2009.10.10
[JPEG] JPEG 개요  (0) 2009.10.09
Posted by 코멧'★
Flex/AIR/AS3/AIR2009.10.11 17:26

[출처] - 오창훈님 블로그 (http://lovedev.tistory.com/)
http://lovedev.tistory.com/trackback/498

요즘 한참 파일을 바이트 단위로 읽어서 표현하는 방법에 대해 공부하던 중 오창훈님의 블로그에 올라와 있는 글을 보고
발견한 내용입니다.

BMP 파일을 읽는 예제
package
{
	import flash.filesystem.File;
	import flash.filesystem.FileStream;
	import flash.filesystem.FileMode;

	import flash.display.Sprite;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.utils.Endian;

	import flash.geom.Rectangle;

	[SWF(width='550', height='400', backgroundColor='#FFFFFF', frameRate='12')]
	public class BMPViewer extends Sprite
	{
		private static const MAGIC_NUMBER:String = "BM";
		private static const BMP_DATA_OFFSET_POSITION:int = 0xA;
		private static const WIDTH_POSITION:int = 0x12;
		private static const HEIGHT_POSITION:int = 0x16;

		public function BMPViewer()
		{
			loadBMP();
			super();
		}

		/*
			Loads and reads a 24 Bit bitmap file.
			
			Based on BMP info from:
			http://en.wikipedia.org/wiki/BMP%5Ffile%5Fformat
		*/
		private function loadBMP():void
		{
			//Load BMP. This requires AIR.
			//Use FileReference.browse for
			//Flash Player
			var bmpFile:File = new File("app:/image.bmp");
			var fs:FileStream = new FileStream();

			//BMP files are Little Endian, which means their
			//least significant byte is first (right to left)
			fs.endian = Endian.LITTLE_ENDIAN;

			//open the file in READ mode
			fs.open(bmpFile, FileMode.READ);

			//check the first two bytes to make sure
			//it is a valid BMP file
			if(fs.readUTFBytes(2) != MAGIC_NUMBER)
			{
				trace("FAIL : NOT A BMP FILE");

				//not a BMP file, close steam
				//and exit
				fs.close();
				return;
			}

			//note, we could also grab the length from the 
			//header and make sure the file was the correct
			//length

			//change the cursors position to the point
			//in the header that contains the value / offset
			//of where the actual bitmap data begins
			//read in the 4 Bytes that contain the value
			fs.position = BMP_DATA_OFFSET_POSITION;
			var dataPosition:int = fs.readInt();

			//set cursor position to where the BMP
			//width is stored
			fs.position = WIDTH_POSITION;

			//read in the 4 Bytes that contain the width
			var bmpWidth:int = fs.readInt();

			//read in the 4 Bytes that contain the height
			var bmpHeight:int = fs.readInt();

			//set cursor to where the BMP pixel data begins
			fs.position = dataPosition;

			var row:int = 0;
			var column:int = 0;

			//every row length in a BMP file must bee a multiple
			//of 4 (see the spec). So, we need to determine how much
			//padding we need to add at the end of each line. 
			var padding:int = (bmpWidth % 4);

			//create a fixed length Vector to store the pixel
			//values as we read them.
			var pixels:Vector. = new Vector.(bmpWidth * bmpHeight, true);

			//loop through data (rows and columns)
			//note that data stored in BMP is backwards to Flash and is
			//stored from bottom row up, not top row down.
			//So we have to loop backwards
			var counter:int = 0;
			for(var i:int = bmpHeight; i > 0; i--)
			{
				for(var k:int = 0; k < bmpWidth; k++)
				{

					var position:int = ((i - 1) * bmpWidth) + k;
					/*
						This is the original code that I had which works fine
						but is not as effecient as what I have now.
						
						Basically, Pixels are stored within 3 sucessive Bytes
						in a BMP file, with one Byte each for Blue, Green and
						Red values (in that order).
						
						So, this reads the Bytes for each pixel, one at a time
						and then combines them into a single value which is
						the combined RGB pixel value.
						
						I left the code as I think it make it a little easier to
						understand what is going on, as well as how some of these
						calls can be optimized.
					*/

					/*
					var blue:int = fs.readUnsignedByte();
					var green:int = fs.readUnsignedByte();
					var red:int = fs.readUnsignedByte();
					
					pixels[position] = (red << 16 ^ green << 8 ^ blue);
					*/

					/*
						Here is the final code which is more efficient, as it only
						needs to make 2 read calls in order to get the values.
						
						Thanks to Thibault Imbert (bytearray.org) for pointing out
						and helping me understand the optimization.
					*/

					//bytes in file are in Blue, Green, Red order
					//int is 32 bits (8 bytes). So, we store the first two bytes of the pixel
					// (which contain the Red value), and
					//then shift everything over 1 byte (8bits) to make room for
					//the green and blue values (remember the file is little endian), which we
					// then write into the int in the right position
					//The final value has the colors in the correct order (Red, Green, Blue)

					var pixelValue:uint = fs.readUnsignedByte() | fs.readUnsignedShort() << 8;
					pixels[position] = pixelValue;
				}

				//we are at the end of the row, so now we have to move the cursor
				//forward so it ends on a multiple of 4
				if(padding)
				{
					fs.position += padding;
				}
			}

			//done reading file, close stream.
			fs.close();

			//create a Rectangle with width / height of Bitmap
			var rect:Rectangle = new Rectangle(0, 0, bmpWidth, bmpHeight);

			//create the BitmapData object to hold hold the BMP data.
			//we do a red fill here so it is easier to see if we have any errors
			//in our code
			var bmpData:BitmapData = new BitmapData(bmpWidth, bmpHeight, false, 0xFF0000);

			//copy the BMP pixel data into the BitmapData
			bmpData.setVector(rect, pixels);

			//create a new Bitmap instance using the BitmapData
			var bitmap:Bitmap = new Bitmap(bmpData);
			bitmap.x = 10;
			bitmap.y = 10;

			//add Bitmap to the display list
			addChild(bitmap);
		}
	}
}

역시 그래픽 파일의 특성상 LITTLE_ENDIAN으로 바이트를 읽어들입니다. JPEG 같은 경우에는 BIG_ENDIAN이라 한참 헷갈렸던 적이 있었던 기억이 나네요 ^^;

참고 : http://www.mikechambers.com/blog/2009/09/17/parsing-and-displaying-bmp-files-via-actionscript/
예제 다운로드 : http://www.mikechambers.com/blog/files/examples/BMPViewer.zip

오창훈님 블로그에 bmd.setVector (rect, pixels); setVector는 bmd.setPixel보다 빠른 퍼포먼스를 낸다고 조언을 해주셨네요 ^^;
전 setVector 보다 setPixel이 더 퍼포먼스가 좋다고 생각하고 있었는데 역시나 아직 갈길이 멉니다 ㅜ_ㅜ

현재 파일들 구조들에 대해 공부하고 있는데 최종 목표는 flex에서 각 파일 포멧들 간의 변경과 그래픽 파일들로 플래쉬 또는 동영상 파일로 컨버트 할 수 있는 프로그램을 만들려고 하는데 파일들 구조가 생각보다 쉽지 않네요 ㅜ_ㅜ 언제나 완성할 수 있을지 걱정입니다 ㅜ_ㅜ
저작자 표시 비영리 변경 금지
신고
Posted by 코멧'★
TAG AIR, bmp

티스토리 툴바