]> Creatis software - clitk.git/blobdiff - utilities/CxImage/ximawmf.cpp
cosmetic
[clitk.git] / utilities / CxImage / ximawmf.cpp
index 97ebf123db5777780394c89c406d3136c6963b85..1ca308023e235fc3fb7b2c3793d6514227fea4b1 100644 (file)
-/*\r
-*********************************************************************\r
- * File:       ximawmf.cpp\r
- * Purpose:    Windows Metafile Class Loader and Writer\r
- * Author:     Volker Horch - vhorch@gmx.de\r
- * created:    13-Jun-2002\r
- *\r
- * Note:       If the code below works, i wrote it.\r
- *                     If it doesn't work, i don't know who wrote it.\r
-*********************************************************************\r
- */\r
-\r
-/*\r
-*********************************************************************\r
-       Note by Author:\r
-*********************************************************************\r
-\r
-       Metafile Formats:\r
-       =================\r
-\r
-       There are 2 kinds of Windows Metafiles:\r
-       - Standard Windows Metafile\r
-       - Placeable Windows Metafile\r
-\r
-       A StandardWindows Metafile looks like:\r
-       - Metafile Header (MEATAHEADER)\r
-       - Metafile Records \r
-\r
-       A Placeable Metafile looks like:\r
-       - Aldus Header (METAFILEHEADER)\r
-       - Metafile Header (METAHEADER)\r
-       - Metafile Records\r
-\r
-       The "Metafile Header" and the "Metafile Records" are the same\r
-       for both formats. However, the Standard Metafile does not contain any\r
-       information about the original dimensions or x/y ratio of the Metafile.\r
-\r
-       I decided, to allow only placeable Metafiles here. If you also want to\r
-       enable Standard Metafiles, you will have to guess the dimensions of\r
-       the image.\r
-\r
-*********************************************************************\r
-       Limitations:    see ximawmf.h\r
-                                       you may configure some stuff there\r
-*********************************************************************\r
-*/\r
-\r
-#include "ximawmf.h"\r
-\r
-#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#if CXIMAGE_SUPPORT_DECODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-bool CxImageWMF::Decode(CxFile *hFile, long nForceWidth, long nForceHeight)\r
-{\r
-       if (hFile == NULL) return false;\r
-\r
-       HENHMETAFILE    hMeta;\r
-       HDC                             hDC;\r
-       int                             cx,cy;\r
-\r
-       //save the current position of the file\r
-       long pos = hFile->Tell();\r
-\r
-       // Read the Metafile and convert to an Enhanced Metafile\r
-       METAFILEHEADER  mfh;\r
-       hMeta = ConvertWmfFiletoEmf(hFile, &mfh);\r
-       if (hMeta) {    // ok, it's a WMF\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-//     We use the original WMF size information, because conversion to\r
-//     EMF adjusts the Metafile to Full Screen or does not set rclBounds at all\r
-//     ENHMETAHEADER   emh;\r
-//     UINT                    uRet;\r
-//     uRet = GetEnhMetaFileHeader(hMeta,                                      // handle of enhanced metafile \r
-//                                                             sizeof(ENHMETAHEADER),  // size of buffer, in bytes \r
-//                                                             &emh);                                  // address of buffer to receive data  \r
-//     if (!uRet){\r
-//             DeleteEnhMetaFile(hMeta);\r
-//             return false;\r
-//     }\r
-//     // calculate size\r
-//     cx = emh.rclBounds.right - emh.rclBounds.left;\r
-//     cy = emh.rclBounds.bottom - emh.rclBounds.top;\r
-/////////////////////////////////////////////////////////////////////\r
-\r
-               // calculate size\r
-               // scale the metafile (pixels/inch of metafile => pixels/inch of display)\r
-               // mfh.inch already checked to be <> 0\r
-\r
-               hDC = ::GetDC(0);\r
-               int cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);\r
-               int cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);\r
-               ::ReleaseDC(0, hDC);\r
-\r
-               cx = (mfh.inch/2 + (mfh.bbox.right - mfh.bbox.left) * cx1) / mfh.inch;\r
-               cy = (mfh.inch/2 + (mfh.bbox.bottom - mfh.bbox.top) * cy1) / mfh.inch;\r
-\r
-       } else {                // maybe it's an EMF...\r
-\r
-               hFile->Seek(pos,SEEK_SET);\r
-\r
-               ENHMETAHEADER   emh;\r
-               hMeta = ConvertEmfFiletoEmf(hFile, &emh);\r
-\r
-               if (!hMeta){\r
-                       strcpy(info.szLastError,"corrupted WMF");\r
-                       return false; // definitively give up\r
-               }\r
-\r
-               // ok, it's an EMF; calculate canvas size\r
-               cx = emh.rclBounds.right - emh.rclBounds.left;\r
-               cy = emh.rclBounds.bottom - emh.rclBounds.top;\r
-\r
-               // alternative methods, sometime not so reliable... [DP]\r
-               //cx = emh.szlDevice.cx;\r
-               //cy = emh.szlDevice.cy;\r
-               //\r
-               //hDC = ::GetDC(0);\r
-               //float hscale = (float)GetDeviceCaps(hDC, HORZRES)/(100.0f * GetDeviceCaps(hDC, HORZSIZE));\r
-               //float vscale  =  (float)GetDeviceCaps(hDC, VERTRES)/(100.0f * GetDeviceCaps(hDC, VERTSIZE));\r
-               //::ReleaseDC(0, hDC);\r
-               //cx = (long)((emh.rclFrame.right - emh.rclFrame.left) * hscale);\r
-               //cy = (long)((emh.rclFrame.bottom - emh.rclFrame.top) * vscale);\r
-       }\r
-\r
-       if (info.nEscape == -1) {       // Check if cancelled\r
-               head.biWidth = cx;\r
-               head.biHeight= cy;\r
-               info.dwType = CXIMAGE_FORMAT_WMF;\r
-               DeleteEnhMetaFile(hMeta);\r
-               strcpy(info.szLastError,"output dimensions returned");\r
-               return true;\r
-       }\r
-\r
-       if (!cx || !cy) {\r
-               DeleteEnhMetaFile(hMeta);\r
-               strcpy(info.szLastError,"empty WMF");\r
-               return false;\r
-       }\r
-\r
-       if (nForceWidth) cx=nForceWidth;\r
-       if (nForceHeight) cy=nForceHeight;\r
-       ShrinkMetafile(cx, cy);         // !! Otherwise Bitmap may have bombastic size\r
-\r
-       HDC hDC0 = ::GetDC(0);  // DC of screen\r
-       HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); // has # colors of display\r
-       hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen\r
-       ::ReleaseDC(0, hDC0);   // don't need anymore. get rid of it.\r
-\r
-       if (hDC){\r
-               if (hBitmap){\r
-                       RECT rc = {0,0,cx,cy};\r
-                       int bpp = ::GetDeviceCaps(hDC, BITSPIXEL);\r
-\r
-                       HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap);\r
-\r
-                       // clear out the entire bitmap with windows background\r
-                       // because the MetaFile may not contain background information\r
-                       DWORD   dwBack = XMF_COLOR_BACK;\r
-#if XMF_SUPPORT_TRANSPARENCY\r
-                       if (bpp == 24) dwBack = XMF_COLOR_TRANSPARENT;\r
-#endif\r
-                   DWORD OldColor = SetBkColor(hDC, dwBack);\r
-                   ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);\r
-                       SetBkColor(hDC, OldColor);\r
-\r
-                       //retrieves optional palette entries from the specified enhanced metafile\r
-                       PLOGPALETTE plogPal;\r
-                       PBYTE pjTmp; \r
-                       HPALETTE hPal; \r
-                       int iEntries = GetEnhMetaFilePaletteEntries(hMeta, 0, NULL);\r
-                       if (iEntries) { \r
-                               if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, \r
-                                       sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) { \r
-                                       DeleteObject(hBitmap);\r
-                                       DeleteDC(hDC);\r
-                                       DeleteEnhMetaFile(hMeta);\r
-                                       strcpy(info.szLastError,"Cancelled");\r
-                                       return false;\r
-                               } \r
-\r
-                               plogPal->palVersion = 0x300; \r
-                               plogPal->palNumEntries = (WORD) iEntries; \r
-                               pjTmp = (PBYTE) plogPal; \r
-                               pjTmp += 4; \r
-\r
-                               GetEnhMetaFilePaletteEntries(hMeta, iEntries, (PPALETTEENTRY)pjTmp); \r
-                               hPal = CreatePalette(plogPal); \r
-                               GlobalFree(plogPal); \r
-\r
-                               SelectPalette(hDC, hPal, FALSE); \r
-                               RealizePalette(hDC); \r
-                       } \r
-                       \r
-                       // Play the Metafile into Memory DC\r
-                       BOOL bRet = PlayEnhMetaFile(hDC,        // handle to a device context \r
-                                                                       hMeta,  // handle to an enhanced metafile  \r
-                                                                       &rc);   // pointer to bounding rectangle\r
-\r
-                       SelectObject(hDC, hBitmapOld);\r
-                       DeleteEnhMetaFile(hMeta);       // we are done with this one\r
-\r
-                       if (info.nEscape) {     // Check if cancelled\r
-                               DeleteObject(hBitmap);\r
-                               DeleteDC(hDC);\r
-                               strcpy(info.szLastError,"Cancelled");\r
-                               return false;\r
-                       }\r
-\r
-                       // the Bitmap now has the image.\r
-                       // Create our DIB and convert the DDB into DIB\r
-                       if (!Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)) {\r
-                               DeleteObject(hBitmap);\r
-                               DeleteDC(hDC);\r
-                               return false;\r
-                       }\r
-\r
-#if XMF_SUPPORT_TRANSPARENCY\r
-                       if (bpp == 24) {\r
-                               RGBQUAD rgbTrans = { XMF_RGBQUAD_TRANSPARENT };\r
-                               SetTransColor(rgbTrans);\r
-                       }\r
-#endif\r
-                   // We're finally ready to get the DIB. Call the driver and let\r
-                   // it party on our bitmap. It will fill in the color table,\r
-                   // and bitmap bits of our global memory block.\r
-                       bRet = GetDIBits(hDC, hBitmap, 0,\r
-                               (UINT)cy, GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS);\r
-\r
-                       DeleteObject(hBitmap);\r
-                       DeleteDC(hDC);\r
-\r
-                       return (bRet!=0);\r
-               } else {\r
-                       DeleteDC(hDC);\r
-               }\r
-       } else {\r
-               if (hBitmap) DeleteObject(hBitmap);\r
-       }\r
-\r
-       DeleteEnhMetaFile(hMeta);\r
-\r
-       return false;\r
-}\r
-\r
-/**********************************************************************\r
- Function:     CheckMetafileHeader\r
- Purpose:      Check if the Metafileheader of a file is valid\r
-**********************************************************************/\r
-BOOL CxImageWMF::CheckMetafileHeader(METAFILEHEADER *metafileheader)\r
-{\r
-       WORD    *pw;\r
-       WORD    cs;\r
-       int             i;\r
-\r
-       // check magic #\r
-       if (metafileheader->key != 0x9ac6cdd7L) return false;\r
-\r
-       // test checksum of header\r
-       pw = (WORD *)metafileheader;\r
-       cs = *pw;\r
-       pw++;\r
-       for (i = 0; i < 9; i++) {\r
-               cs ^= *pw;\r
-               pw++;\r
-       }\r
-\r
-       if (cs != metafileheader->checksum)     return false;\r
-\r
-       // check resolution\r
-       if ((metafileheader->inch <= 0) || (metafileheader->inch > 2540)) return false;\r
-\r
-       return true;\r
-}\r
-\r
-/**********************************************************************\r
- Function:     ConvertWmfFiletoEmf\r
- Purpose:      Converts a Windows Metafile into an Enhanced Metafile\r
-**********************************************************************/\r
-HENHMETAFILE CxImageWMF::ConvertWmfFiletoEmf(CxFile *fp, METAFILEHEADER *metafileheader)\r
-{\r
-       HENHMETAFILE    hMeta;\r
-       long                    lenFile;\r
-       long                    len;\r
-       BYTE                    *p;\r
-       METAHEADER              mfHeader;\r
-       DWORD                   seekpos;\r
-\r
-       hMeta = 0;\r
-\r
-       // get length of the file\r
-       lenFile = fp->Size();\r
-\r
-       // a placeable metafile starts with a METAFILEHEADER\r
-       // read it and check metafileheader\r
-       len = fp->Read(metafileheader, 1, sizeof(METAFILEHEADER));\r
-       if (len < sizeof(METAFILEHEADER)) return (hMeta);\r
-\r
-       if (CheckMetafileHeader(metafileheader)) {\r
-               // This is a placeable metafile \r
-               // Convert the placeable format into something that can\r
-               // be used with GDI metafile functions \r
-               seekpos = sizeof(METAFILEHEADER);\r
-       } else {\r
-               // Not a placeable wmf. A windows metafile?\r
-               // at least not scaleable.\r
-               // we could try to convert, but would loose ratio. don't allow this\r
-               return (hMeta);\r
-\r
-               //metafileheader->bbox.right = ?;\r
-               //metafileheader->bbox.left = ?;\r
-               //metafileheader->bbox.bottom = ?;\r
-               //metafileheader->bbox.top = ?;\r
-               //metafileheader->inch = ?;\r
-               //\r
-               //seekpos = 0;\r
-               // fp->Seek(0, SEEK_SET);       // rewind\r
-       }\r
-\r
-       // At this point we have a metaheader regardless of whether\r
-       // the metafile was a windows metafile or a placeable metafile\r
-       // so check to see if it is valid. There is really no good\r
-       // way to do this so just make sure that the mtType is either\r
-       // 1 or 2 (memory or disk file) \r
-       // in addition we compare the length of the METAHEADER against\r
-       // the length of the file. if filelength < len => no Metafile\r
-\r
-       len = fp->Read(&mfHeader, 1, sizeof(METAHEADER));\r
-       if (len < sizeof(METAHEADER)) return (hMeta);\r
-\r
-       if ((mfHeader.mtType != 1) && (mfHeader.mtType != 2)) return (hMeta);\r
-\r
-       // Length in Bytes from METAHEADER\r
-       len = mfHeader.mtSize * 2;\r
-       if (len > lenFile) return (hMeta);\r
-\r
-       // Allocate memory for the metafile bits \r
-       p = (BYTE *)malloc(len);\r
-       if (!p) return (hMeta);\r
-\r
-       // seek back to METAHEADER and read all the stuff at once\r
-       fp->Seek(seekpos, SEEK_SET);\r
-       lenFile = fp->Read(p, 1, len);\r
-       if (lenFile != len)     {\r
-               free(p);\r
-               return (hMeta);\r
-       }\r
-\r
-       // the following (commented code)  works, but adjusts rclBound of the\r
-       // Enhanced Metafile to full screen.\r
-       // the METAFILEHEADER from above is needed to scale the image\r
-\r
-//     hMeta = SetWinMetaFileBits(len, p, NULL, NULL);\r
-\r
-       // scale the metafile (pixels/inch of metafile => pixels/inch of display)\r
-\r
-       METAFILEPICT    mfp;\r
-       int cx1, cy1;\r
-       HDC hDC;\r
-\r
-       hDC = ::GetDC(0);\r
-       cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);\r
-       cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);\r
-\r
-       memset(&mfp, 0, sizeof(mfp));\r
-\r
-       mfp.mm = MM_ANISOTROPIC;\r
-       mfp.xExt = 10000; //(metafileheader->bbox.right - metafileheader->bbox.left) * cx1 / metafileheader->inch;\r
-       mfp.yExt = 10000; //(metafileheader->bbox.bottom - metafileheader->bbox.top) * cy1 / metafileheader->inch;\r
-       mfp.hMF = 0;\r
-\r
-       // in MM_ANISOTROPIC mode xExt and yExt are in MM_HIENGLISH\r
-       // MM_HIENGLISH means: Each logical unit is converted to 0.001 inch\r
-       //mfp.xExt *= 1000;\r
-       //mfp.yExt *= 1000;\r
-       // ????\r
-       //int k = 332800 / ::GetSystemMetrics(SM_CXSCREEN);\r
-       //mfp.xExt *= k;        mfp.yExt *= k;\r
-\r
-       // fix for Win9x\r
-       while ((mfp.xExt < 6554) && (mfp.yExt < 6554))\r
-       {\r
-               mfp.xExt *= 10;\r
-               mfp.yExt *= 10;\r
-       }\r
-\r
-       hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);\r
-\r
-       if (!hMeta){ //try 2nd conversion using a different mapping\r
-               mfp.mm = MM_TEXT;\r
-               hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);\r
-       }\r
-\r
-       ::ReleaseDC(0, hDC);\r
-\r
-       // Free Memory\r
-       free(p);\r
-\r
-       return (hMeta);\r
-}\r
-/////////////////////////////////////////////////////////////////////\r
-HENHMETAFILE CxImageWMF::ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh)\r
-{\r
-       HENHMETAFILE    hMeta;\r
-       long iLen = pFile->Size();\r
-\r
-       // Check the header first: <km>\r
-       long pos = pFile->Tell();\r
-       long iLenRead = pFile->Read(pemfh, 1, sizeof(ENHMETAHEADER));\r
-       if (iLenRead < sizeof(ENHMETAHEADER))         return NULL;\r
-       if (pemfh->iType != EMR_HEADER)               return NULL;\r
-       if (pemfh->dSignature != ENHMETA_SIGNATURE)   return NULL;\r
-       //if (pemfh->nBytes != (DWORD)iLen)             return NULL;\r
-       pFile->Seek(pos,SEEK_SET);\r
-\r
-       BYTE* pBuff = (BYTE *)malloc(iLen);\r
-       if (!pBuff)     return (FALSE);\r
-\r
-       // Read the Enhanced Metafile\r
-       iLenRead = pFile->Read(pBuff, 1, iLen);\r
-       if (iLenRead != iLen) {\r
-               free(pBuff);\r
-               return NULL;\r
-       }\r
-\r
-       // Make it a Memory Metafile\r
-       hMeta = SetEnhMetaFileBits(iLen, pBuff);\r
-\r
-       free(pBuff);    // finished with this one\r
-\r
-       if (!hMeta)     return NULL;    // oops.\r
-\r
-       // Get the Enhanced Metafile Header\r
-       UINT uRet = GetEnhMetaFileHeader(hMeta,                         // handle of enhanced metafile \r
-                                                               sizeof(ENHMETAHEADER),  // size of buffer, in bytes \r
-                                                               pemfh);                                 // address of buffer to receive data  \r
-  \r
-       if (!uRet) {\r
-               DeleteEnhMetaFile(hMeta);\r
-               return NULL;\r
-       }\r
-\r
-       return (hMeta);\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif //CXIMAGE_SUPPORT_DECODE\r
-////////////////////////////////////////////////////////////////////////////////\r
-#if CXIMAGE_SUPPORT_ENCODE\r
-/////////////////////////////////////////////////////////////////////\r
-bool CxImageWMF::Encode(CxFile * hFile)\r
-{\r
-       if (hFile == NULL) return false;\r
-       strcpy(info.szLastError, "Save WMF not supported");\r
-       return false;\r
-}\r
-#endif // CXIMAGE_SUPPORT_ENCODE\r
-/////////////////////////////////////////////////////////////////////\r
-\r
-/**********************************************************************\r
-Function:      ShrinkMetafile\r
-Purpose:       Shrink the size of a metafile to be not larger than\r
-                       the definition\r
-**********************************************************************/\r
-void CxImageWMF::ShrinkMetafile(int &cx, int &cy)\r
-{\r
-       int     xScreen = XMF_MAXSIZE_CX;\r
-       int     yScreen = XMF_MAXSIZE_CY;\r
-\r
-       if (cx > xScreen){\r
-               cy = cy * xScreen / cx;\r
-               cx = xScreen;\r
-       }\r
-\r
-       if (cy > yScreen){\r
-               cx = cx * yScreen / cy;\r
-               cy = yScreen;\r
-       }\r
-}\r
-\r
-#endif // CIMAGE_SUPPORT_WMF\r
-\r
+/*
+*********************************************************************
+ * File:       ximawmf.cpp
+ * Purpose:    Windows Metafile Class Loader and Writer
+ * Author:     Volker Horch - vhorch@gmx.de
+ * created:    13-Jun-2002
+ *
+ * Note:       If the code below works, i wrote it.
+ *                     If it doesn't work, i don't know who wrote it.
+*********************************************************************
+ */
+
+/*
+*********************************************************************
+       Note by Author:
+*********************************************************************
+
+       Metafile Formats:
+       =================
+
+       There are 2 kinds of Windows Metafiles:
+       - Standard Windows Metafile
+       - Placeable Windows Metafile
+
+       A StandardWindows Metafile looks like:
+       - Metafile Header (MEATAHEADER)
+       - Metafile Records 
+
+       A Placeable Metafile looks like:
+       - Aldus Header (METAFILEHEADER)
+       - Metafile Header (METAHEADER)
+       - Metafile Records
+
+       The "Metafile Header" and the "Metafile Records" are the same
+       for both formats. However, the Standard Metafile does not contain any
+       information about the original dimensions or x/y ratio of the Metafile.
+
+       I decided, to allow only placeable Metafiles here. If you also want to
+       enable Standard Metafiles, you will have to guess the dimensions of
+       the image.
+
+*********************************************************************
+       Limitations:    see ximawmf.h
+                                       you may configure some stuff there
+*********************************************************************
+*/
+
+#include "ximawmf.h"
+
+#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS
+
+////////////////////////////////////////////////////////////////////////////////
+#if CXIMAGE_SUPPORT_DECODE
+////////////////////////////////////////////////////////////////////////////////
+bool CxImageWMF::Decode(CxFile *hFile, long nForceWidth, long nForceHeight)
+{
+       if (hFile == NULL) return false;
+
+       HENHMETAFILE    hMeta;
+       HDC                             hDC;
+       int                             cx,cy;
+
+       //save the current position of the file
+       long pos = hFile->Tell();
+
+       // Read the Metafile and convert to an Enhanced Metafile
+       METAFILEHEADER  mfh;
+       hMeta = ConvertWmfFiletoEmf(hFile, &mfh);
+       if (hMeta) {    // ok, it's a WMF
+
+/////////////////////////////////////////////////////////////////////
+//     We use the original WMF size information, because conversion to
+//     EMF adjusts the Metafile to Full Screen or does not set rclBounds at all
+//     ENHMETAHEADER   emh;
+//     UINT                    uRet;
+//     uRet = GetEnhMetaFileHeader(hMeta,                                      // handle of enhanced metafile 
+//                                                             sizeof(ENHMETAHEADER),  // size of buffer, in bytes 
+//                                                             &emh);                                  // address of buffer to receive data  
+//     if (!uRet){
+//             DeleteEnhMetaFile(hMeta);
+//             return false;
+//     }
+//     // calculate size
+//     cx = emh.rclBounds.right - emh.rclBounds.left;
+//     cy = emh.rclBounds.bottom - emh.rclBounds.top;
+/////////////////////////////////////////////////////////////////////
+
+               // calculate size
+               // scale the metafile (pixels/inch of metafile => pixels/inch of display)
+               // mfh.inch already checked to be <> 0
+
+               hDC = ::GetDC(0);
+               int cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);
+               int cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);
+               ::ReleaseDC(0, hDC);
+
+               cx = (mfh.inch/2 + (mfh.bbox.right - mfh.bbox.left) * cx1) / mfh.inch;
+               cy = (mfh.inch/2 + (mfh.bbox.bottom - mfh.bbox.top) * cy1) / mfh.inch;
+
+       } else {                // maybe it's an EMF...
+
+               hFile->Seek(pos,SEEK_SET);
+
+               ENHMETAHEADER   emh;
+               hMeta = ConvertEmfFiletoEmf(hFile, &emh);
+
+               if (!hMeta){
+                       strcpy(info.szLastError,"corrupted WMF");
+                       return false; // definitively give up
+               }
+
+               // ok, it's an EMF; calculate canvas size
+               cx = emh.rclBounds.right - emh.rclBounds.left;
+               cy = emh.rclBounds.bottom - emh.rclBounds.top;
+
+               // alternative methods, sometime not so reliable... [DP]
+               //cx = emh.szlDevice.cx;
+               //cy = emh.szlDevice.cy;
+               //
+               //hDC = ::GetDC(0);
+               //float hscale = (float)GetDeviceCaps(hDC, HORZRES)/(100.0f * GetDeviceCaps(hDC, HORZSIZE));
+               //float vscale  =  (float)GetDeviceCaps(hDC, VERTRES)/(100.0f * GetDeviceCaps(hDC, VERTSIZE));
+               //::ReleaseDC(0, hDC);
+               //cx = (long)((emh.rclFrame.right - emh.rclFrame.left) * hscale);
+               //cy = (long)((emh.rclFrame.bottom - emh.rclFrame.top) * vscale);
+       }
+
+       if (info.nEscape == -1) {       // Check if cancelled
+               head.biWidth = cx;
+               head.biHeight= cy;
+               info.dwType = CXIMAGE_FORMAT_WMF;
+               DeleteEnhMetaFile(hMeta);
+               strcpy(info.szLastError,"output dimensions returned");
+               return true;
+       }
+
+       if (!cx || !cy) {
+               DeleteEnhMetaFile(hMeta);
+               strcpy(info.szLastError,"empty WMF");
+               return false;
+       }
+
+       if (nForceWidth) cx=nForceWidth;
+       if (nForceHeight) cy=nForceHeight;
+       ShrinkMetafile(cx, cy);         // !! Otherwise Bitmap may have bombastic size
+
+       HDC hDC0 = ::GetDC(0);  // DC of screen
+       HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); // has # colors of display
+       hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen
+       ::ReleaseDC(0, hDC0);   // don't need anymore. get rid of it.
+
+       if (hDC){
+               if (hBitmap){
+                       RECT rc = {0,0,cx,cy};
+                       int bpp = ::GetDeviceCaps(hDC, BITSPIXEL);
+
+                       HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap);
+
+                       // clear out the entire bitmap with windows background
+                       // because the MetaFile may not contain background information
+                       DWORD   dwBack = XMF_COLOR_BACK;
+#if XMF_SUPPORT_TRANSPARENCY
+                       if (bpp == 24) dwBack = XMF_COLOR_TRANSPARENT;
+#endif
+                   DWORD OldColor = SetBkColor(hDC, dwBack);
+                   ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
+                       SetBkColor(hDC, OldColor);
+
+                       //retrieves optional palette entries from the specified enhanced metafile
+                       PLOGPALETTE plogPal;
+                       PBYTE pjTmp; 
+                       HPALETTE hPal; 
+                       int iEntries = GetEnhMetaFilePaletteEntries(hMeta, 0, NULL);
+                       if (iEntries) { 
+                               if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, 
+                                       sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) { 
+                                       DeleteObject(hBitmap);
+                                       DeleteDC(hDC);
+                                       DeleteEnhMetaFile(hMeta);
+                                       strcpy(info.szLastError,"Cancelled");
+                                       return false;
+                               } 
+
+                               plogPal->palVersion = 0x300; 
+                               plogPal->palNumEntries = (WORD) iEntries; 
+                               pjTmp = (PBYTE) plogPal; 
+                               pjTmp += 4; 
+
+                               GetEnhMetaFilePaletteEntries(hMeta, iEntries, (PPALETTEENTRY)pjTmp); 
+                               hPal = CreatePalette(plogPal); 
+                               GlobalFree(plogPal); 
+
+                               SelectPalette(hDC, hPal, FALSE); 
+                               RealizePalette(hDC); 
+                       } 
+                       
+                       // Play the Metafile into Memory DC
+                       BOOL bRet = PlayEnhMetaFile(hDC,        // handle to a device context 
+                                                                       hMeta,  // handle to an enhanced metafile  
+                                                                       &rc);   // pointer to bounding rectangle
+
+                       SelectObject(hDC, hBitmapOld);
+                       DeleteEnhMetaFile(hMeta);       // we are done with this one
+
+                       if (info.nEscape) {     // Check if cancelled
+                               DeleteObject(hBitmap);
+                               DeleteDC(hDC);
+                               strcpy(info.szLastError,"Cancelled");
+                               return false;
+                       }
+
+                       // the Bitmap now has the image.
+                       // Create our DIB and convert the DDB into DIB
+                       if (!Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)) {
+                               DeleteObject(hBitmap);
+                               DeleteDC(hDC);
+                               return false;
+                       }
+
+#if XMF_SUPPORT_TRANSPARENCY
+                       if (bpp == 24) {
+                               RGBQUAD rgbTrans = { XMF_RGBQUAD_TRANSPARENT };
+                               SetTransColor(rgbTrans);
+                       }
+#endif
+                   // We're finally ready to get the DIB. Call the driver and let
+                   // it party on our bitmap. It will fill in the color table,
+                   // and bitmap bits of our global memory block.
+                       bRet = GetDIBits(hDC, hBitmap, 0,
+                               (UINT)cy, GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS);
+
+                       DeleteObject(hBitmap);
+                       DeleteDC(hDC);
+
+                       return (bRet!=0);
+               } else {
+                       DeleteDC(hDC);
+               }
+       } else {
+               if (hBitmap) DeleteObject(hBitmap);
+       }
+
+       DeleteEnhMetaFile(hMeta);
+
+       return false;
+}
+
+/**********************************************************************
+ Function:     CheckMetafileHeader
+ Purpose:      Check if the Metafileheader of a file is valid
+**********************************************************************/
+BOOL CxImageWMF::CheckMetafileHeader(METAFILEHEADER *metafileheader)
+{
+       WORD    *pw;
+       WORD    cs;
+       int             i;
+
+       // check magic #
+       if (metafileheader->key != 0x9ac6cdd7L) return false;
+
+       // test checksum of header
+       pw = (WORD *)metafileheader;
+       cs = *pw;
+       pw++;
+       for (i = 0; i < 9; i++) {
+               cs ^= *pw;
+               pw++;
+       }
+
+       if (cs != metafileheader->checksum)     return false;
+
+       // check resolution
+       if ((metafileheader->inch <= 0) || (metafileheader->inch > 2540)) return false;
+
+       return true;
+}
+
+/**********************************************************************
+ Function:     ConvertWmfFiletoEmf
+ Purpose:      Converts a Windows Metafile into an Enhanced Metafile
+**********************************************************************/
+HENHMETAFILE CxImageWMF::ConvertWmfFiletoEmf(CxFile *fp, METAFILEHEADER *metafileheader)
+{
+       HENHMETAFILE    hMeta;
+       long                    lenFile;
+       long                    len;
+       BYTE                    *p;
+       METAHEADER              mfHeader;
+       DWORD                   seekpos;
+
+       hMeta = 0;
+
+       // get length of the file
+       lenFile = fp->Size();
+
+       // a placeable metafile starts with a METAFILEHEADER
+       // read it and check metafileheader
+       len = fp->Read(metafileheader, 1, sizeof(METAFILEHEADER));
+       if (len < sizeof(METAFILEHEADER)) return (hMeta);
+
+       if (CheckMetafileHeader(metafileheader)) {
+               // This is a placeable metafile 
+               // Convert the placeable format into something that can
+               // be used with GDI metafile functions 
+               seekpos = sizeof(METAFILEHEADER);
+       } else {
+               // Not a placeable wmf. A windows metafile?
+               // at least not scaleable.
+               // we could try to convert, but would loose ratio. don't allow this
+               return (hMeta);
+
+               //metafileheader->bbox.right = ?;
+               //metafileheader->bbox.left = ?;
+               //metafileheader->bbox.bottom = ?;
+               //metafileheader->bbox.top = ?;
+               //metafileheader->inch = ?;
+               //
+               //seekpos = 0;
+               // fp->Seek(0, SEEK_SET);       // rewind
+       }
+
+       // At this point we have a metaheader regardless of whether
+       // the metafile was a windows metafile or a placeable metafile
+       // so check to see if it is valid. There is really no good
+       // way to do this so just make sure that the mtType is either
+       // 1 or 2 (memory or disk file) 
+       // in addition we compare the length of the METAHEADER against
+       // the length of the file. if filelength < len => no Metafile
+
+       len = fp->Read(&mfHeader, 1, sizeof(METAHEADER));
+       if (len < sizeof(METAHEADER)) return (hMeta);
+
+       if ((mfHeader.mtType != 1) && (mfHeader.mtType != 2)) return (hMeta);
+
+       // Length in Bytes from METAHEADER
+       len = mfHeader.mtSize * 2;
+       if (len > lenFile) return (hMeta);
+
+       // Allocate memory for the metafile bits 
+       p = (BYTE *)malloc(len);
+       if (!p) return (hMeta);
+
+       // seek back to METAHEADER and read all the stuff at once
+       fp->Seek(seekpos, SEEK_SET);
+       lenFile = fp->Read(p, 1, len);
+       if (lenFile != len)     {
+               free(p);
+               return (hMeta);
+       }
+
+       // the following (commented code)  works, but adjusts rclBound of the
+       // Enhanced Metafile to full screen.
+       // the METAFILEHEADER from above is needed to scale the image
+
+//     hMeta = SetWinMetaFileBits(len, p, NULL, NULL);
+
+       // scale the metafile (pixels/inch of metafile => pixels/inch of display)
+
+       METAFILEPICT    mfp;
+       int cx1, cy1;
+       HDC hDC;
+
+       hDC = ::GetDC(0);
+       cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);
+       cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);
+
+       memset(&mfp, 0, sizeof(mfp));
+
+       mfp.mm = MM_ANISOTROPIC;
+       mfp.xExt = 10000; //(metafileheader->bbox.right - metafileheader->bbox.left) * cx1 / metafileheader->inch;
+       mfp.yExt = 10000; //(metafileheader->bbox.bottom - metafileheader->bbox.top) * cy1 / metafileheader->inch;
+       mfp.hMF = 0;
+
+       // in MM_ANISOTROPIC mode xExt and yExt are in MM_HIENGLISH
+       // MM_HIENGLISH means: Each logical unit is converted to 0.001 inch
+       //mfp.xExt *= 1000;
+       //mfp.yExt *= 1000;
+       // ????
+       //int k = 332800 / ::GetSystemMetrics(SM_CXSCREEN);
+       //mfp.xExt *= k;        mfp.yExt *= k;
+
+       // fix for Win9x
+       while ((mfp.xExt < 6554) && (mfp.yExt < 6554))
+       {
+               mfp.xExt *= 10;
+               mfp.yExt *= 10;
+       }
+
+       hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);
+
+       if (!hMeta){ //try 2nd conversion using a different mapping
+               mfp.mm = MM_TEXT;
+               hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);
+       }
+
+       ::ReleaseDC(0, hDC);
+
+       // Free Memory
+       free(p);
+
+       return (hMeta);
+}
+/////////////////////////////////////////////////////////////////////
+HENHMETAFILE CxImageWMF::ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh)
+{
+       HENHMETAFILE    hMeta;
+       long iLen = pFile->Size();
+
+       // Check the header first: <km>
+       long pos = pFile->Tell();
+       long iLenRead = pFile->Read(pemfh, 1, sizeof(ENHMETAHEADER));
+       if (iLenRead < sizeof(ENHMETAHEADER))         return NULL;
+       if (pemfh->iType != EMR_HEADER)               return NULL;
+       if (pemfh->dSignature != ENHMETA_SIGNATURE)   return NULL;
+       //if (pemfh->nBytes != (DWORD)iLen)             return NULL;
+       pFile->Seek(pos,SEEK_SET);
+
+       BYTE* pBuff = (BYTE *)malloc(iLen);
+       if (!pBuff)     return (FALSE);
+
+       // Read the Enhanced Metafile
+       iLenRead = pFile->Read(pBuff, 1, iLen);
+       if (iLenRead != iLen) {
+               free(pBuff);
+               return NULL;
+       }
+
+       // Make it a Memory Metafile
+       hMeta = SetEnhMetaFileBits(iLen, pBuff);
+
+       free(pBuff);    // finished with this one
+
+       if (!hMeta)     return NULL;    // oops.
+
+       // Get the Enhanced Metafile Header
+       UINT uRet = GetEnhMetaFileHeader(hMeta,                         // handle of enhanced metafile 
+                                                               sizeof(ENHMETAHEADER),  // size of buffer, in bytes 
+                                                               pemfh);                                 // address of buffer to receive data  
+  
+       if (!uRet) {
+               DeleteEnhMetaFile(hMeta);
+               return NULL;
+       }
+
+       return (hMeta);
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif //CXIMAGE_SUPPORT_DECODE
+////////////////////////////////////////////////////////////////////////////////
+#if CXIMAGE_SUPPORT_ENCODE
+/////////////////////////////////////////////////////////////////////
+bool CxImageWMF::Encode(CxFile * hFile)
+{
+       if (hFile == NULL) return false;
+       strcpy(info.szLastError, "Save WMF not supported");
+       return false;
+}
+#endif // CXIMAGE_SUPPORT_ENCODE
+/////////////////////////////////////////////////////////////////////
+
+/**********************************************************************
+Function:      ShrinkMetafile
+Purpose:       Shrink the size of a metafile to be not larger than
+                       the definition
+**********************************************************************/
+void CxImageWMF::ShrinkMetafile(int &cx, int &cy)
+{
+       int     xScreen = XMF_MAXSIZE_CX;
+       int     yScreen = XMF_MAXSIZE_CY;
+
+       if (cx > xScreen){
+               cy = cy * xScreen / cx;
+               cx = xScreen;
+       }
+
+       if (cy > yScreen){
+               cx = cx * yScreen / cy;
+               cy = yScreen;
+       }
+}
+
+#endif // CIMAGE_SUPPORT_WMF
+