2010. 6. 1. 12:48ㆍ2010년/프로젝트
기본적으로 비트맵의 기본정보를 오른쪽 상단에 적어주고 왼쪽 상단에 그림을 띄우게 했다.
사실 우리가 윈도우에 익숙해진 아니 길들어져있기때문에 모든 파일을 형식을 잘 모른다.
윈도우에 생성되는 파일은 대부분 PE이다 그리고 비트맵 파일 같은경우도 마찬가지이다.
그래서 파일의 특징은 처음 거의 54바이트까지는 비트맵에 대한 정보가 들어있다. 예를 들어 첫 2바이트는 Magic Number라해서 비트맵이라는것을 알려주기위해서 BM이 들어가있고(아스키코드로 66 77이다)3 번째 바이트에 파일의 크기가 가로크기 세로크기 압축유무 비트수라든지 실질적인 비트맵의 시작주소까지 들어가있다.
비트맵의 시작주소를 알게 되면 그다음부터는 하나의 픽셀로 저장된다. 54번째부터 55 56 번째 바이트까지 색의 3요소인 RGB 거꾸로 54번째 Blue 55번째 Green 56번째 Red로 3바이트씩 픽셀하나와 색상이 나와이있다.
그래서 한픽셋을 하나씩 대화상자에 찍어줘야하고 위치는 위에서 아래가 아닌
왼쪽 아래부터 오른쪽 위에 까지 찍어나간다.
-Default-
-WorkSpace-
-Resource View-
이제소스 코드를 하나씩 보자
=Main.cpp=
#include <windows.h>//API함수들의 원형과 사용하는 상수들이 정의 되어 있다.
#include "MsgProc.h"
//전역변수 선언
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LPCTSTR lpszClass = TEXT("First"); //const char * //lpszClass : 윈도우 클래스를 정의하는데 사용
HINSTANCE g_hInst; //전역변수
typedef struct DMESSAGEMAP //대화상자에 정보를 넘겨주기위한 구조체
{
UINT iMessage;
BOOL (*lpfnMsgProc)(HWND,WPARAM,LPARAM);
}DMESSAGEMAP;
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lPSZCmdParam, int nCmdShow)
{//엔트리포인트는 main()이 아니라 WinMain(),이다.
//윈도우를 만들고 화면에 표시하기만 할 뿐, 대부분의 일은 아래의 함수에서 이루어진다.
//WinMain에서 하는 가장 중요한 일은 메인 윈도우를 만드는 일이다.
//메인윈도우를 대신해서 기본적으로 대화상자를 메인으로 잡아서 생성했다.
DialogBox(g_hInst,MAKEINTRESOURCE(IDD_DIALOG1),NULL,AboutDlgProc);
}
//사용자와 시스템이 보내오는 메시지를 처리하는 함수. (운영체제에 의해 호출)
BOOL CALLBACK AboutDlgProc(HWND hDlg,UINT iMessage, WPARAM wParam,LPARAM lParam)
{
int i;
static DMESSAGEMAP dMessageMaps[]=
{
{WM_INITDIALOG,OnInitDialog}, //iMessage를 처리하기위한 대화상자에
{WM_COMMAND,OnDlgCommand}, //INIDIALOG,COMMAND, PAINT를 각각함수로 구현
{WM_PAINT,OnPaintDlg}
};
for(i=0;i<sizeof(dMessageMaps)/sizeof(dMessageMaps[0]);++i)
{
if(dMessageMaps[i].iMessage==iMessage)
return (*dMessageMaps[i].lpfnMsgProc)(hDlg,wParam,lParam);
}
return FALSE;
}
함수와윈도우 생성에 대한 간단한 내용만 있다 실질적인 내용은 MsgProc.cpp에 있다.
=MsgProc.h=
#ifndef __MSGPROC_H_ // MSGPROC.h 파일이 있는지 검사
#define __MSGPROC_H_
#include <windows.h> //API함수들의 원형과 사용하는 상수들이 정의 되어 있다.
#include "resource.h" //만들어지 resurce대한 정의
//main,cpp에서 바꾼 WM_PAINT WM_COMMAND 대한 함수의 정의
BOOL CALLBACK AboutDlgProc(HWND,UINT,WPARAM,LPARAM);
BOOL OnInitDialog(HWND, WPARAM, LPARAM);
BOOL OnDlgCommand(HWND, WPARAM, LPARAM);
BOOL OnPaintDlg(HWND , WPARAM , LPARAM );
extern HINSTANCE g_hInst; //중복선언을 피하기 위해 선언
#endif
=resource.h=
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by rc.rc
//
#define IDD_DIALOG1 101 //대화상자
#define IDR_MENU1 102 //메뉴
#define IDC_EDIT1 1001
#define IDC_EDIT2 1002
#define IDC_EDIT3 1003
#define IDC_EDIT4 1004
#define IDC_EDIT5 1005
#define IDC_EDIT6 1006
#define IDC_EDIT7 1007
#define IDC_EDIT8 1008
#define IDC_EDIT9 1009
#define IDC_EDIT10 1010
#define IDC_EDIT11 1011
#define IDC_EDIT12 1012
#define IDC_EDIT13 1013
#define IDC_NEW 1014
#define IDC_90 1015
#define IDC_OK 1016
#define IDC_180 1017
#define IDC_BC 1018
#define ID_40001 40001
#define ID_40002 40002
#define ID_40003 40003
#define ID_40004 40004
#define ID_40005 40005
#define ID_40006 40006
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40007
#define _APS_NEXT_CONTROL_VALUE 1015
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
resource같은경우는 자동으로 만들어주기때문에 추가되는내용이 없다.
=MsgProc=
#include "MsgProc.h"
#define BSIZE 20000000 //사진 파일 크기
char buf[BSIZE+1]; //비트맵 파일들어갈 장소
HANDLE hFile; //open할 파일을 넣을 핸들
TCHAR tt[128]; //간단한 BM을 찍기위한 배열
TCHAR *bb={TEXT("ALL")}; //used color값이0이면 ALL을 찍기위함
int *result; //4바이트 단위로 찍기위함 int포인터
short *sRe; //2바이트 단위로 찍기위한 short포인터
DWORD dwRead; //4바이트 크기
HDC hdc; //대화상자 DC
HDC MemDC; //메모리DC
PAINTSTRUCT ps; //WM_PAINT로 저장할 구조체
int iwidth; // 사진의 가로길이
int iheight; // 사진의 세로길이
int abc=0; // 사진 회전에 필요한 간단한 변수
int BLCL=0; // 사진 흑백 칼라 지정할 간단한 변수
//int basu=1;
OPENFILENAME OFN; //파일을 열기위한 구조체 OFN선언
TCHAR lpstrFile[MAX_PATH]; //충반한 길이의 버퍼제공하기위해 입력받는 파일명을 MAX_PATH(260)크기만큼선언
void vopen(HWND hDlg) //파일을 열기위한 함수 생성
{
memset(&OFN,0,sizeof(OPENFILENAME));//처음에 디포르로놓기위하여 0으로 메모리셋을함
OFN.lStructSize = sizeof(OPENFILENAME); //구조체의 크기를 지정
OFN.hwndOwner = hDlg;//윈도우 대화상자핸들들을 지정
OFN.lpstrFilter = TEXT("모든 파일(*.*)\0*.*\0"); //필터들이며 open받을 파일의 형식을 지정
OFN.lpstrFile = lpstrFile;//파일이름 에디트에 처음 나타낼 문자열지정..최종적으로 선택한 파일의전체경로반환
OFN.nMaxFile = MAX_PATH; //lpstrFile의 길이를 지정 최소는 256
if(GetOpenFileName(&OFN) != 0) //파일을 열기 성공시에 아래 실행
{
hFile = CreateFile(OFN.lpstrFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
//OPENFILENAME에 저장되어있는 hFile핸들에 넣어준다.
}
if(INVALID_HANDLE_VALUE !=hFile)
{
ReadFile(hFile,buf,BSIZE,&dwRead,NULL); //hFile핸들에 들어있는비트맵정보를
//BSIZE크기만큼 buf에 넣는다.
wsprintf(tt,TEXT("%c%c"),buf[0],buf[1]); //일단 buf[0]buf[1]에 내용을 tt에 넣는다. BM이들어간다.
}
else //hFile핸들 값이 실패시 에러 메시지 출력...
{
wsprintf(tt,TEXT("Error"));
}
SetWindowText(hDlg,tt);
//************************************************************************
//***************************실질적인 출력부분****************************
//************************************************************************
SetDlgItemText(hDlg,IDC_EDIT1,tt); //Magic 넘버 출력 비트맵이기때문에 BM이 찍힌다.
result=(int *)(&buf[2]);
//파일 크기 출력
SetDlgItemInt(hDlg,IDC_EDIT2,(*result),FALSE);
//이미지 가로크기는 int *로 넣고 IDC_EDIT2출력
result=(int *)(&buf[18]);
iwidth=(*result); //iwidth에 대입
SetDlgItemInt(hDlg,IDC_EDIT3,(*result),FALSE);
//이미지 세로크기 IDC_EDIT3에 출력
result=(int *)(&buf[22]);
iheight=(*result); //iheight에대입
SetDlgItemInt(hDlg,IDC_EDIT4,(*result),FALSE);
//비트맵의플레인수 출력(항상1)
sRe=(short *)(&buf[26]);
SetDlgItemInt(hDlg,IDC_EDIT5,*(sRe),FALSE);
//비트 수 출력(24)
sRe=(short *)(&buf[28]);
SetDlgItemInt(hDlg,IDC_EDIT6,*(sRe),FALSE);
//압축 유무 출력
result=(int *)(&buf[30]);
SetDlgItemInt(hDlg,IDC_EDIT7,*(result),FALSE);
//비트맵 크기 출력
result=(int *)(&buf[34]);
SetDlgItemInt(hDlg,IDC_EDIT8,*(result),FALSE);
//미터당 가로 해상도
result=(int *)(&buf[38]);
SetDlgItemInt(hDlg,IDC_EDIT9,*(result),FALSE);
//미터당 세로 해상도
result=(int *)(&buf[42]);
SetDlgItemInt(hDlg,IDC_EDIT10,*(result),FALSE);
//used color와 중요하게 색상 사용유무 없으면 ALL 출력
result=(int *)(&buf[46]);
if(0!=(*result))
{
SetDlgItemInt(hDlg,IDC_EDIT11,*(result),FALSE);
}
else
{
SetDlgItemText(hDlg,IDC_EDIT11,bb);
}
result=(int *)(&buf[50]);
if(0!=(*result))
{
SetDlgItemInt(hDlg,IDC_EDIT12,*(result),FALSE);
}
else
{
SetDlgItemText(hDlg,IDC_EDIT12,bb);
}
// 실질적 데이터 시작주소 (보통 54)
result=(int *)(&buf[10]);
SetDlgItemInt(hDlg,IDC_EDIT13,*(result),FALSE);
BLCL=0; //초기값으로 칼라를 0을 줌
InvalidateRect(hDlg,NULL,TRUE); //WM_PAINT로 전달
CloseHandle(hFile); //핸들종료
}
void vprint()
{
int icnt;
int cout;
int ib=54; //실질적인 데이터 시작값
if(abc%4==0) //90도회전하기전에 출력
{
for(icnt=iheight;0<icnt;--icnt)
{
for(cout=0;iwidth>cout;++cout)
{
//픽셀한개씩 메모리 DC화면에 X좌표는 cout Y좌표는 icnt 색상은 buf안에 54,55,56d을사용
SetPixel(MemDC,cout,icnt,RGB(buf[ib+2],buf[ib+1],buf[ib]));
//buf 3증가해서 다음색상을 지정
ib=ib+3;
}
}
}
else if(abc%4==1) //90도회전버튼 한번 눌렸을때
{
for(icnt=iheight;0<icnt;--icnt)
{
for(cout=0;iwidth>cout;++cout)
{ //X좌표와 Y좌표만 변경
SetPixel(MemDC,icnt,cout,RGB(buf[ib+2],buf[ib+1],buf[ib]));
ib=ib+3;
}
}
}
else if(abc%4==2) //90도회전버튼 두번 눌렷을때
{
for(icnt=0;iheight>icnt;++icnt) // 화면이 거꾸로이기때문에 가로길이 세로길이 for변경
{
for(cout=0;iwidth>cout;++cout)
{
SetPixel(MemDC,cout,icnt,RGB(buf[ib+2],buf[ib+1],buf[ib]));
ib=ib+3;
}
}
}
else if(abc%4==3) //90도 회전 버튼 세번 눌렀을대
{
for(icnt=0;iheight>icnt;++icnt) //세로 크기만큼 가로크기 만큼 변경하고
{
for(cout=iwidth;0<cout;--cout)
{
//출력픽셀로 가로 세로 변경
SetPixel(MemDC,icnt,cout,RGB(buf[ib+2],buf[ib+1],buf[ib]));
ib=ib+3;
}
}
}
}
void hprint() //가로 길이가 홀수 일때와 짝수일때에 따라 픽셀 수조정하는 비트맵
{ //위 vprint()와 나머지는 같음
int icnt;
int cout;
int ib=54;
if(abc%4==0)
{
for(icnt=iheight;0<icnt;--icnt)
{
for(cout=0;iwidth>=cout;++cout)
{
SetPixel(MemDC,cout,icnt,RGB(buf[ib+2],buf[ib+1],buf[ib]));
ib=ib+3;
}
}
}
else if(abc%4==1)
{
for(icnt=iheight;0<icnt;--icnt)
{
for(cout=0;iwidth>=cout;++cout)
{
SetPixel(MemDC,icnt,cout,RGB(buf[ib+2],buf[ib+1],buf[ib]));
ib=ib+3;
}
}
}
else if(abc%4==2)
{
for(icnt=0;iheight>icnt;++icnt)
{
for(cout=0;iwidth>=cout;++cout)
{
SetPixel(MemDC,cout,icnt,RGB(buf[ib+2],buf[ib+1],buf[ib]));
ib=ib+3;
}
}
}
else if(abc%4==3)
{
for(icnt=0;iheight>icnt;++icnt)
{
for(cout=iwidth;0<=cout;--cout)
{
SetPixel(MemDC,icnt,cout,RGB(buf[ib+2],buf[ib+1],buf[ib]));
ib=ib+3;
}
}
}
}
void blackC() //흑백모드 비트맵 이미지를 처리 지정
{
int icnt;
int cout;
int ib=54;
if(abc%4==0)
{
for(icnt=iheight;0<icnt;--icnt)
{
for(cout=0;iwidth>=cout;++cout)
{
//기본적으로 RGB의 값은 다같아버리면 회색으로 출력되므로 중간값을기준으로 다같게 지정
SetPixel(MemDC,cout,icnt,RGB(buf[ib+1],buf[ib+1],buf[ib+1]));
ib=ib+3;
}
}
}
else if(abc%4==1)
{
for(icnt=iheight;0<icnt;--icnt)
{
for(cout=0;iwidth>=cout;++cout)
{
SetPixel(MemDC,icnt,cout,RGB(buf[ib+1],buf[ib+1],buf[ib+1]));
ib=ib+3;
}
}
}
else if(abc%4==2)
{
for(icnt=0;iheight>icnt;++icnt)
{
for(cout=0;iwidth>=cout;++cout)
{
SetPixel(MemDC,cout,icnt,RGB(buf[ib+1],buf[ib+1],buf[ib+1]));
ib=ib+3;
}
}
}
else if(abc%4==3)
{
for(icnt=0;iheight>icnt;++icnt)
{
for(cout=iwidth;0<=cout;--cout)
{
SetPixel(MemDC,icnt,cout,RGB(buf[ib+1],buf[ib+1],buf[ib+1]));
ib=ib+3;
}
}
}
}
void blackSC()
{
int icnt;
int cout;
int ib=54;
if(abc%4==0)
{
for(icnt=iheight;0<icnt;--icnt)
{
for(cout=0;iwidth>cout;++cout)
{
SetPixel(MemDC,cout,icnt,RGB(buf[ib+1],buf[ib+1],buf[ib+1]));
ib=ib+3;
}
}
}
else if(abc%4==1)
{
for(icnt=iheight;0<icnt;--icnt)
{
for(cout=0;iwidth>cout;++cout)
{
SetPixel(MemDC,icnt,cout,RGB(buf[ib+1],buf[ib+1],buf[ib+1]));
ib=ib+3;
}
}
}
else if(abc%4==2)
{
for(icnt=0;iheight>icnt;++icnt)
{
for(cout=0;iwidth>cout;++cout)
{
SetPixel(MemDC,cout,icnt,RGB(buf[ib+1],buf[ib+1],buf[ib+1]));
ib=ib+3;
}
}
}
else if(abc%4==3)
{
for(icnt=0;iheight>icnt;++icnt)
{
for(cout=iwidth;0<cout;--cout)
{
SetPixel(MemDC,icnt,cout,RGB(buf[ib+1],buf[ib+1],buf[ib+1]));
ib=ib+3;
}
}
}
}
BOOL OnInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
return TRUE;
}
BOOL OnDlgCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
//버튼의 클릭과 메뉴 클릭 지정 함수
switch(LOWORD(wParam))
{
case ID_40001: //메뉴의 파일열기 선택시 vopen()함수 호출
vopen(hDlg);
break;
case IDCANCEL://대화상자 X버튼 클릭시 메시지띄우고 종료
if(MessageBox(hDlg,TEXT("종료하시겠습니까"),TEXT("알림"),MB_OKCANCEL)==IDOK)
{
EndDialog(hDlg,IDCANCEL);
}
else
{
break;
}
case IDC_NEW: //새로고침 버튼 클릭시 회전을 0도로 변경
abc=0;
InvalidateRect(hDlg,NULL,TRUE);
break;
case IDC_90: //한번 클릭시마다 abc값을 변경해서 이미지 회전 변경
abc++;
InvalidateRect(hDlg,NULL,TRUE);
break;
case IDC_180: //180도버튼은 abc값이 2번띄는거랑 같기에 지정
abc=abc+2;
InvalidateRect(hDlg,NULL,TRUE);
break;
case IDC_BC: //흑백과 칼라를 지정 BLCD%2가 0이면 칼라 1이면 흑백
BLCL++;
InvalidateRect(hDlg,NULL,TRUE);
break;
case ID_40003: //메뉴의 닫기 버튼 클릭시 메시지박스 실행
if(MessageBox(hDlg,TEXT("종료하시겠습니까"),TEXT("알림"),MB_OKCANCEL)==IDOK)
{
EndDialog(hDlg,IDOK);
}
else
{
break;
}
}
return FALSE;
}
BOOL OnPaintDlg(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
hdc=BeginPaint(hDlg,&ps); //PAINTSTRUCT 내용과 hDlg값의 화면을 hdc로 지정
HBITMAP MyBitmap,OldBitmap; //비트맵을 보여줄 메모리DC와 화면DC을 설정하기위해 설정
MemDC=CreateCompatibleDC(hdc); //화면에 DC을 그대로 MemDC로 메모리에 똑같이 복사.
if(abc%2==0) //화면이 0도나 180도일경우 화면DC을 메모리DC에제대로 복사
{
MyBitmap=CreateCompatibleBitmap(hdc,iwidth,iheight);
}else if(abc%2==1) //화면이 90도나 270도일경우 화면DC의 가로와 세로길이 변경후 복사
{
MyBitmap=CreateCompatibleBitmap(hdc,iheight,iwidth);
}
OldBitmap=(HBITMAP)SelectObject(MemDC,MyBitmap); //OldBitmap에 기존DC 복사
if(iwidth%2==0) //가로길이가 짝수에따라서 출력형태 변경
{
if(BLCL%2==1)
{
blackSC();
}
else
{
vprint();
}
}
else
{
if(BLCL%2==1)
{
blackC();
}
else
{
hprint();
}
}
if(abc%2==0) //회전후 출력시 0도 180도일경우 그대로 출력
{
BitBlt(hdc,70,70,iwidth,iheight,MemDC,0,0,SRCCOPY);
}
else if(abc%2==1) //회전후 출력이 80도나 270도일경우 가로 세로 변경해서 출력
{
BitBlt(hdc,70,70,iheight,iwidth,MemDC,0,0,SRCCOPY);
}
SelectObject(MemDC,OldBitmap); //메모리 MyBitmap을 OldBitmap으로 변경
DeleteObject(MyBitmap); //메모리 오브젝트 삭제
DeleteDC(MemDC); //메모리 DC 삭제
EndPaint(hDlg,&ps); //PAINT 종료
return 0;
}
=파일=
'2010년 > 프로젝트' 카테고리의 다른 글
Total SoftBank (0) | 2012.12.17 |
---|---|
영상처리 프로젝트 (0) | 2010.07.02 |
RFID 주차관리시스템(팀프로젝트) (0) | 2010.06.22 |
-두더지게임- (0) | 2010.04.26 |
도서관리프로그램 (0) | 2010.04.14 |