옛날에 pcx-_-; 같은걸로 게임 만들때 상하,좌우,대각선, 뭐 이런거 대칭 함수 만들었던 기억이 -_-;;
-------------------------
The universe is run by the complex interweaving of three elements: matter, energy, and enlightened self-interest.
- G'kar, Babylon 5
옛날에 pcx-_-; 같은걸로 게임 만들때 상하,좌우,대각선, 뭐 이런거 대칭 함수 만들었던 기억이 -_-;;
어디서 줏어들은 제 알량한 지식으로는, BMP는 거의 raw data에 가깝긴하지만 순수한 raw data는 아니기 때문에 그냥 읽어들여서 곧바로 뒤집으시면 안된다고 알고 있습니다. BMP는 raw data에 BMP 헤더를 붙여준 형태라서, 일단 어디까지가 헤더인지를 찾아내서 그 부분 외의 나머지를 뒤집으셔야 할 것 같습니다.
(그런데, 바로 이 'BMP의 헤더가 어디까지인지 알아내기'가 생각보다 간단치 않다더군요. :?)
-- 자본주의, 자유민주주의 사회에서는 결국 자유마저 돈으로 사야하나보다.
사줄테니 제발 팔기나 해다오. 아직 내가 "사겠다"고 말하는 동안에 말이다!
제가 아는 바로는..헤더에 어디부터가 실제 이미지인지 offset이 나와 있습니다..
DDB의 경우는 전혀 아는 바 없지만..
DIB의 경우 헤더에..
처음 2바이트는 매직 넘버,
다음 4바이트는 BMP 파일의 크기,
다음 4바이트는 빈 공간.,
그 다음 4바이트에 실제 영상정보가 있는 오프셋 입니다..
BMP파일의 끝에서부터 위에 있는 오프셋까지..
뒤에서 부터 읽어서 출력하시면 됩니다..
예전에 BMP 출력하는 루틴을 만든 경험이 있어서;;
하드에 코드가 남아있길래...오래만에 훑어봤네요..^^
옛날에 pcx-_-; 같은걸로 게임 만들때 상하,좌우,대각선, 뭐 이런거 대칭 함수 만들었던 기억이 -_-;;
어디서 줏어들은 제 알량한 지식으로는, BMP는 거의 raw data에 가깝긴하지만 순수한 raw data는 아니기 때문에 그냥 읽어들여서 곧바로 뒤집으시면 안된다고 알고 있습니다. BMP는 raw data에 BMP 헤더를 붙여준 형태라서, 일단 어디까지가 헤더인지를 찾아내서 그 부분 외의 나머지를 뒤집으셔야 할 것 같습니다.
(그런데, 바로 이 'BMP의 헤더가 어디까지인지 알아내기'가 생각보다 간단치 않다더군요. :?)
많이 쓰이는 포맷인데 헤더가 어디까지인지 알기 힘들게 만들지야 않았겠지요 ^^;
물론 depth에 따라서 point bit 수도 다를테고 resolution에 따라서 point 수도 다를테지만, 헤더에 그정도 정보야 다 있겠지요 ^^;
그냥 자동으로 헤더 계산해서 사용하는 대칭 출력 메쏘드를 만들어서 출력할때 뒤집어 출력... 하면 되지 않을까용.
-------------------------
The universe is run by the complex interweaving of three elements: matter, energy, and enlightened self-interest.
- G'kar, Babylon 5
BMP 파일은 BITMAPFILEHEADER와 BITMAPINFOHEADER로 구성됩니다.
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
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;
1) BMP파일을 읽어서 가장 앞에 BITMAPFILEHEADER가 있고 바로 뒤에 BITMAPINFOHEADER가 이어집니다.
2) BITMAPFILEHEADER의 bfOffBits 부분이 이미지가 있는 위치입니다.
3) 이미지를 처리하실때 scanline 단위로 하면 되고 BMP 파일의 스캔라인은 4의 배수 크기입니다.
4) BITMAPINFOHEADER의 biWidth, biBitCount 를 사용해서 스캔라인을 계산하면 되지만 계산된 값을 4의 배수로 조정해 줘야 합니다.
MSDN의 샘플에 나와 있는 코드는 다음과 같습니다. ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
코드의 효용성은 알아서 판단하시구요, 이해는 아랫 코드가 더 쉬울 겁니다.
일반적인 경우라면 colorbit가 하나의 픽셀이 요구하는 bit라고 이해하시면 되구요, 그러니 사이즈를 byte로 표현하려면, colorbit * width / 8입니다. 하지만 여기서 simpid님께서 말씀하신 4byte alignment가 적용됩니다.
따라서, 1bit라도 커지면 +4byte를 하는 효과때문에 (4*8-1)을 더해주는 겁니다.
예를 들어 2bit color에서 width의 크기가 28이라면, 위의 공식에 따라, scanline의 크기는 7byte가 아니라, 8byte가 된다는 겁니다.
BMP는 한라인이 저장될때 DWORD단위로 패딩되게 되어 있습니다.
위의 식은 라인 총 비트수를 32bit(4byte==DWORD)으로 나누어(나머지는 무조건 1로 올립니다.) 필요한 DWORD값을 계산하여 4를 곱하면 파일에서 한 라인이 차지하는 바이트 수가 나옵니다. 그러면 이 수에 원하는 라인의 수를 곱하여 로 데이터 시작위치를 더하면 원하는 라인의 첫 픽셀의 파일오프셋이 계산됩니다.
bmp화일의 경우
헤더가 있고
사용하는 색의 사이즈에 따라서
파레트가 있는 경우가 있고 없는 경우가 있고
그리고 파레트가 있는 경우는 그 파레트를 지시하고 있는 인덱스데이타
파레트가 없는 경우는 rgb값이 저장되어 있습니다.
여기서 파레트란 bmp데이타의 양을 줄이기 위해 색값을 미리 지정해 둔 것이지요
예를들어 일곱가지 무지개 색을 사용해서 100*100크기의 그림을 그리는 경우를 생각해 보도록 하죠.
우선 색을 표현하는데는 RGB 각각 1바이트씩 3바이트와 추가로1바이트(4바이트 맞추기 위해? 오래되서 기억이 가물가물..)로 4바이트가 필요합니다.
그럼 파레트를 사용하지 않는 경우는
---------------------------------------------
헤더의 바이트수 + 픽셀수(100*100)*4
---------------------------------------------
이번에는 파레트에를 사용할 경우를 봅시다.
파레트에는
빨 주 노 초 파 남 보의 순의로 필요한 색을 파레트에 저장해 두고..
데이터에는 이 필요한 색의 순서를 지정하는 방식이므로
7개의 순서를 표현하려면 3비트면 충분하죠?
계산의 편의를 위해 걍 인덱스 데이타를 1바이트식 잡으면
------------------------------------------------
헤더의 바이트수 + 색의수(7)*4 + 픽셀수(100*100)*1
------------------------------------------------
훨씬 줄어 들었죠?
그럼 그림을 뒤집으려면 어떻게 하면 될까요?
당연히 데이타 부분만 뒤집어 주면 됩니다.
bmp데이타는
실제 보이는 그림에서의
가장 윗줄의 픽셀들이 데이타의 아래쪽에 저장되어 있고
가장 아랫줄의 픽셀들이 데이타의 위쪽에 저장되어 있습니다.
즉
1a 1b 1c
2a 2b 2c
3a 3b 3c
4a 4b 4c
5a 5b 5c
라고 보이는 그림의 실제 데이타는
5a 5b 5c
4a 4b 4c
3a 3b 3c
2a 2b 2c
1a 1b 1c
로 저장되어 있습니다.
이때 1a와 1c는 바뀌여 있지 않습니다.
단지 줄만 바뀌여 있을 따름입니다.
데이타의 줄 위치만 바꾸어 주면 화면은 뒤집힙니다.
단 한 줄을 나타내는 데이타 수를 계산해 주셔야 합니다.
100*100의 그림이라면
한줄을 나타내는 데이타 수는
경우에 따라서 매우 다양히 틀려 지겠지만
100*4바이트가 되겠죠.
// Some bitmaps do not have the sizeimage field calculated
// Ferret out these cases and fix 'em.
if (nsizeimage == 0)
{
nsizeimage = ((((nwidth*nbitcount)+31) & ~31 ) >> 3);
nsizeimage *= nheight;
System.out.println("nsizeimage (backup) is"+nsizeimage);
}
----
I paint objects as I think them, not as I see them. atie's minipage
그냥 line 단위로 뒤집으면 되지 않을까요 ㅡㅡ; 어차피 low-dat
그냥 line 단위로 뒤집으면 되지 않을까요 ㅡㅡ; 어차피 low-data인데 ㅎㅎ
옛날에 pcx-_-; 같은걸로 게임 만들때 상하,좌우,대각선, 뭐 이런거 대칭 함수 만들었던 기억이 -_-;;
-------------------------
The universe is run by the complex interweaving of three elements: matter, energy, and enlightened self-interest.
- G'kar, Babylon 5
원래 비트맵은 bottom-up 이 디폴트 입니다.1라인이 botto
원래 비트맵은 bottom-up 이 디폴트 입니다.
1라인이 bottom 이고
마지막라인이 top 이죠.
뿌릴 때 거꾸로 뿌리시면... 안될까요?제 기억이 맞다면 bmp
뿌릴 때 거꾸로 뿌리시면... 안될까요?
제 기억이 맞다면 bmp 파일이 거꾸로 되는 이유가 그 옛날 프로세스들의 비교 연산 비용이 0 을 비교하는 것이 더 싸서 그랬다고 알고 있습니다.
top-down이 -입니다.
여러 헤더가 있습니다.
그중에 BITMAPINFOHEADER 멤버 biHeight의 부호를 반대로 하세요.
자세한 것은
http://msdn.microsoft.com/
___________________________________
Less is More (Robert Browning)
Re: top-down이 -입니다.
그걸 지원하는 이미지 뷰어가 그리 많지는 않을겁니다..
(예전에 해본바에 따르면 =3=33)
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...
http://mytears.org ~(~_~)~
나 한줄기 바람처럼..
[quote="futari"]그냥 line 단위로 뒤집으면 되지 않을까요
어디서 줏어들은 제 알량한 지식으로는, BMP는 거의 raw data에 가깝긴하지만 순수한 raw data는 아니기 때문에 그냥 읽어들여서 곧바로 뒤집으시면 안된다고 알고 있습니다. BMP는 raw data에 BMP 헤더를 붙여준 형태라서, 일단 어디까지가 헤더인지를 찾아내서 그 부분 외의 나머지를 뒤집으셔야 할 것 같습니다.
(그런데, 바로 이 'BMP의 헤더가 어디까지인지 알아내기'가 생각보다 간단치 않다더군요. :?)
--
자본주의, 자유민주주의 사회에서는 결국 자유마저 돈으로 사야하나보다.
사줄테니 제발 팔기나 해다오. 아직 내가 "사겠다"고 말하는 동안에 말이다!
제가 아는 바로는..헤더에 어디부터가 실제 이미지인지 offset이 나
제가 아는 바로는..헤더에 어디부터가 실제 이미지인지 offset이 나와 있습니다..
DDB의 경우는 전혀 아는 바 없지만..
DIB의 경우 헤더에..
처음 2바이트는 매직 넘버,
다음 4바이트는 BMP 파일의 크기,
다음 4바이트는 빈 공간.,
그 다음 4바이트에 실제 영상정보가 있는 오프셋 입니다..
BMP파일의 끝에서부터 위에 있는 오프셋까지..
뒤에서 부터 읽어서 출력하시면 됩니다..
예전에 BMP 출력하는 루틴을 만든 경험이 있어서;;
하드에 코드가 남아있길래...오래만에 훑어봤네요..^^
Emerging the World!
뒤집히는 게 endian이랑 관계 있는 걸까요?
뒤집히는 게 endian이랑 관계 있는 걸까요?
[quote="차리서"][quote="futari"]그냥 line 단위로
많이 쓰이는 포맷인데 헤더가 어디까지인지 알기 힘들게 만들지야 않았겠지요 ^^;
물론 depth에 따라서 point bit 수도 다를테고 resolution에 따라서 point 수도 다를테지만, 헤더에 그정도 정보야 다 있겠지요 ^^;
그냥 자동으로 헤더 계산해서 사용하는 대칭 출력 메쏘드를 만들어서 출력할때 뒤집어 출력... 하면 되지 않을까용.
자세한 파일 포맷들은 역시나 www.wotsit.org 같은곳을 ㅎㅎ
-------------------------
The universe is run by the complex interweaving of three elements: matter, energy, and enlightened self-interest.
- G'kar, Babylon 5
BMP
BMP 파일은 BITMAPFILEHEADER와 BITMAPINFOHEADER로 구성됩니다.
1) BMP파일을 읽어서 가장 앞에 BITMAPFILEHEADER가 있고 바로 뒤에 BITMAPINFOHEADER가 이어집니다.
2) BITMAPFILEHEADER의 bfOffBits 부분이 이미지가 있는 위치입니다.
3) 이미지를 처리하실때 scanline 단위로 하면 되고 BMP 파일의 스캔라인은 4의 배수 크기입니다.
4) BITMAPINFOHEADER의 biWidth, biBitCount 를 사용해서 스캔라인을 계산하면 되지만 계산된 값을 4의 배수로 조정해 줘야 합니다.
5) 제가 사용하는 공식입니다.
(((pBMIH->biBitCount) * (pBMIH->biWidth) + 31) >> 5) << 2;
6) 각각의 스캔라인의 위치는 BfOffBits와 스캔라인의 크기로 알 수 있으므로 BMP파일의 가장 마지막 스캔라인부터 읽어 내면 Bottom-up을 top-down으로 바꿀 수 있습니다.
Re: BMP
이 공식이 어떻게 되는 건지 설명을 부탁드려도 될까요? 이해할 수가 없어서..
Heejoon Lee
Re: BMP
이미지의 최소 단위는 픽셀입니다.
픽셀을 표현하는데 몇 비트를 사용하는냐에 따라 표현할 수 있는 색이 결정됩니다.
스캔라인은 CRT 모니터의 특성에서 만들어진 말로 픽셀이 가로로 이어져 만들어진 한줄을 의미합니다.
예를들어 645*480 이미지에 8비트 칼라를 사용한다면
640 * 8 / 8 = 645Bytes... 물론 4의 배수는 아니죠.
BMP에선 644Bytes가 되야 합니다.(4의 배수로 만들어 남는 공간에는 0이 들어갑니다.)
(((pBMIH->biBitCount) * (pBMIH->biWidth) + 31) >> 5) << 2;
(((8 * 641) + 31) / 32) * 2 = 644가 나옵니다.
꽤 오래전에 만들어 놓은거라...(몇년 됐습니다.)
지금 다시 보니까.. 좀 황당하군요.
(((pBMIH->biBitCount) * (pBMIH->biWidth) + 31) >> 3
이 더 간단한것 같군요.
8비트 칼라 : ((8 * 641) + 31) / 8 = 644
24비트 칼라 : ((24 * 641) + 31) / 8 = 1926
1비트 칼라 : ((1 * 641) + 31) / 8 = 84
이녀석이 더 간단한것 같습니다.
((pBMIH->biBitCount * pBMIH->biWidth) + 31) >> 3
Re: BMP
MSDN의 샘플에 나와 있는 코드는 다음과 같습니다.
((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
코드의 효용성은 알아서 판단하시구요, 이해는 아랫 코드가 더 쉬울 겁니다.
일반적인 경우라면 colorbit가 하나의 픽셀이 요구하는 bit라고 이해하시면 되구요, 그러니 사이즈를 byte로 표현하려면, colorbit * width / 8입니다. 하지만 여기서 simpid님께서 말씀하신 4byte alignment가 적용됩니다.
따라서, 1bit라도 커지면 +4byte를 하는 효과때문에 (4*8-1)을 더해주는 겁니다.
예를 들어 2bit color에서 width의 크기가 28이라면, 위의 공식에 따라, scanline의 크기는 7byte가 아니라, 8byte가 된다는 겁니다.
Re: BMP
이 공식은 반드시 4의 배수를 만들지 못합니다.
(((pBMIH->biBitCount * pBMIH->biWidth) + 31) >> 3) & ~3
이렇게 하면 몰라도요....
Re: BMP
BMP는 한라인이 저장될때 DWORD단위로 패딩되게 되어 있습니다.
위의 식은 라인 총 비트수를 32bit(4byte==DWORD)으로 나누어(나머지는 무조건 1로 올립니다.) 필요한 DWORD값을 계산하여 4를 곱하면 파일에서 한 라인이 차지하는 바이트 수가 나옵니다. 그러면 이 수에 원하는 라인의 수를 곱하여 로 데이터 시작위치를 더하면 원하는 라인의 첫 픽셀의 파일오프셋이 계산됩니다.
저는 이렇게 하기도 합니다.
머나먼 땅으로 우리 동무가 이제 떠나간다네.
고향의 바람이 불어와 동무 뒤를 따르고
사랑스러운 도시가 푸른 이내 속에서 사라지네.
정든 집, 푸른 동산, 부드러운 눈길도...
Re: BMP
그렇군요.
그래서 전에 제가 처음에 개발했던 코드가
(((pBMIH->biBitCount) * (pBMIH->biWidth) + 31) >> 5) << 2;
였나 봅니다.
몇년만에 봤던 코드라... 왜 이럴까 싶어 간단하게 고쳐본건데...
2번에 걸쳐 쉬프트 했던 이유가 있었군요.
제가 만들고 기억못했군요.. ^^;
허접한 경험입니다.
bmp화일의 경우
헤더가 있고
사용하는 색의 사이즈에 따라서
파레트가 있는 경우가 있고 없는 경우가 있고
그리고 파레트가 있는 경우는 그 파레트를 지시하고 있는 인덱스데이타
파레트가 없는 경우는 rgb값이 저장되어 있습니다.
여기서 파레트란 bmp데이타의 양을 줄이기 위해 색값을 미리 지정해 둔 것이지요
예를들어 일곱가지 무지개 색을 사용해서 100*100크기의 그림을 그리는 경우를 생각해 보도록 하죠.
우선 색을 표현하는데는 RGB 각각 1바이트씩 3바이트와 추가로1바이트(4바이트 맞추기 위해? 오래되서 기억이 가물가물..)로 4바이트가 필요합니다.
그럼 파레트를 사용하지 않는 경우는
---------------------------------------------
헤더의 바이트수 + 픽셀수(100*100)*4
---------------------------------------------
이번에는 파레트에를 사용할 경우를 봅시다.
파레트에는
빨 주 노 초 파 남 보의 순의로 필요한 색을 파레트에 저장해 두고..
데이터에는 이 필요한 색의 순서를 지정하는 방식이므로
7개의 순서를 표현하려면 3비트면 충분하죠?
계산의 편의를 위해 걍 인덱스 데이타를 1바이트식 잡으면
------------------------------------------------
헤더의 바이트수 + 색의수(7)*4 + 픽셀수(100*100)*1
------------------------------------------------
훨씬 줄어 들었죠?
그럼 그림을 뒤집으려면 어떻게 하면 될까요?
당연히 데이타 부분만 뒤집어 주면 됩니다.
bmp데이타는
실제 보이는 그림에서의
가장 윗줄의 픽셀들이 데이타의 아래쪽에 저장되어 있고
가장 아랫줄의 픽셀들이 데이타의 위쪽에 저장되어 있습니다.
즉
1a 1b 1c
2a 2b 2c
3a 3b 3c
4a 4b 4c
5a 5b 5c
라고 보이는 그림의 실제 데이타는
5a 5b 5c
4a 4b 4c
3a 3b 3c
2a 2b 2c
1a 1b 1c
로 저장되어 있습니다.
이때 1a와 1c는 바뀌여 있지 않습니다.
단지 줄만 바뀌여 있을 따름입니다.
데이타의 줄 위치만 바꾸어 주면 화면은 뒤집힙니다.
단 한 줄을 나타내는 데이타 수를 계산해 주셔야 합니다.
100*100의 그림이라면
한줄을 나타내는 데이타 수는
경우에 따라서 매우 다양히 틀려 지겠지만
100*4바이트가 되겠죠.
[code:1]/*******************************
걍...
읽어 들인 값들을 위와 같이 뒤집고 좌우를 바꿔서 해결을 했습니다.
이미지 파일은 96x16x4, BMP 파일입니다.
혹시라도 다음에 하시는 분 참고라도 하시라고...-_-ㅋ
그리고 많은 답변글들 감사드립니다...^^
<어떠한 역경에도 굴하지 않는 '하양 지훈'>
#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);
java에선 이렇게...
http://www.javaworld.com/javaworld/javatips/jw-javatip43.html
밑에 인용된 것 외에도 헤더 정보를 어떻게 읽는지 보실 수 있습니다.
----
I paint objects as I think them, not as I see them.
atie's minipage
biHeight 부호를 -로 주니 바로 해결되네요...
저같은 경우 biHeight의 부호를 -로 바꾸어주고 해결했습니다.
댓글 달기