.메타 삽입

메타 파일은 비트맵과는 달리 확대를 해도 모양을 유지하는 벡터 포맷의 그래픽 파일이다. 외부 파일에서 읽어 오는 것이므로 비트맵을 삽입하는 방법과 거의 유사한 방법으로 삽입할 있다. 메타 파일을 삽입하는 다음 함수를 작성한다.

 

void InsertMeta(int x,int y)

{

   OPENFILENAME OFN;

   char lpstrFile[MAX_PATH]="";

   HANDLE hFile;

   DWORD FileSize, dwRead;

   BYTE *pMeta;

 

   memset(&OFN, 0, sizeof(OPENFILENAME));

   OFN.lStructSize = sizeof(OPENFILENAME);

   OFN.hwndOwner=hWndMain;

   OFN.lpstrFilter="메타 파일\0*.wmf\0모든 파일(*.*)\0*.*\0";

   OFN.lpstrFile=lpstrFile;

   OFN.nMaxFile=256;

   if (GetOpenFileName(&OFN)!=0) {

      hFile=CreateFile(lpstrFile,GENERIC_READ,0,NULL,

          OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

      if (hFile!=INVALID_HANDLE_VALUE) {

          FileSize=GetFileSize(hFile,NULL);

          pMeta=(BYTE *)malloc(FileSize);

          ReadFile(hFile,pMeta,FileSize,&dwRead,NULL);

          CloseHandle(hFile);

          if(*((DWORD *)pMeta) != 0x9ac6cdd7l) {

             free(pMeta);

             return;

          }

          AppendObject(DT_META,x,y,x+100,y+100);

          arObj[arNum-1]->Meta=pMeta;

          arObj[arNum-1]->Len=FileSize;

 

          InvalidateRect(hWndMain,NULL,TRUE);

          NowTool=DT_SELECT;

          NowSel=arNum-1;

      }

   }

}

 

파일 열기 대화상자로 메타 파일의 경로를 입력받아 파일 크기만큼 메모리를 할당하고 pMeta 멤버에 포인터를 넣어 두면 된다. 플레이스블 메타 파일의 경우만 삽입할 있도록 했는데 존재하는 대부분의 메타 파일이 플레이스블이므로 이렇게 해도 지장은 없다. 삽입되는 메타 파일의 크기는 100,100으로 설정했는데 이는 어디까지나 디폴트일 뿐이며 삽입 후에 사용자가 마음대로 크기를 변경할 있다. 마우스 왼쪽 버튼을 누를 함수를 호출하여 메타 파일을 삽입한다.

 

LRESULT OnLButtonDown(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

   ....

   if (NowTool==DT_META) {

      InsertMeta(LOWORD(lParam),HIWORD(lParam));

      return 0;

   }

 

NowTool DT_META 클릭한 위치에 메타 파일을 삽입했다. OnLButtonDown에서 메타 파일을 삽입하는 코드와 비트맵을 삽입하는 코드의 순서는 중요하지 않다. 어차피 NowTool 값을 동시에 가질 수는 없으므로 조건에 맞는 코드만 실행하고 리턴하기 때문이다. 여기까지 작성하면 arObj 메타 객체가 삽입되며 남은 일은 삽입된 메타 파일을 화면에 그리는 것이다. 다음 메타 출력 함수를 작성한다.

 

#pragma pack(push)

#pragma pack(2)

typedef struct

{

   DWORD     dwKey;

   WORD      hmf;

   SMALL_RECT   bbox;

   WORD      wInch;

   DWORD     dwReserved;

   WORD      wCheckSum;

} APMHEADER, *PAPMHEADER;

#pragma pack(pop)

 

void PlayPlaceableMeta(HDC hdc,BYTE *pMeta,int len,RECT *rt)

{

   HENHMETAFILE hEnh;

   PAPMHEADER pHeader=(PAPMHEADER)pMeta;

   METAFILEPICT mp;

 

   if(pHeader->dwKey == 0x9ac6cdd7l) {

      mp.mm = MM_ANISOTROPIC;

      mp.xExt = pHeader->bbox.Right - pHeader->bbox.Left;

      mp.xExt = ( mp.xExt * 2540l ) / (DWORD)(pHeader->wInch);

      mp.yExt = pHeader->bbox.Bottom - pHeader->bbox.Top;

      mp.yExt = ( mp.yExt * 2540l ) / (DWORD)(pHeader->wInch);

      mp.hMF = NULL;

 

      hEnh = SetWinMetaFileBits(len, &(pMeta[sizeof(APMHEADER)]), hdc, &mp);

      PlayEnhMetaFile(hdc,hEnh,rt);

      DeleteEnhMetaFile(hEnh);

   }

}

 

플레이스블 메타 파일을 윈도우즈 API 직접 지원하는 32비트 메타 파일로 바꾼 지정한 사각 영역에 재생했다. OnPaint에서 함수를 호출한다.

 

LRESULT OnPaint(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

   ....

      case DT_META:

          PlayPlaceableMeta(hMemDC,arObj[idx]->Meta,arObj[idx]->Len,&arObj[idx]->rt);

          break;

 

메타 파일의 이미지를 그대로 가지고 있는 Meta멤버와 출력 영역인 rt 멤버를 출력 함수로 전달하기만 하면 위치에 메타 파일이 그려질 것이다. 그외 이동이나 크기 변경, 삭제 등의 처리는 기존 도형과 동일하므로 별도의 코드를 작성하지 않아도 된다.