source: liacs/MIR2010/SourceCode/cximage/ximawmf.cpp@ 185

Last change on this file since 185 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 14.4 KB
RevLine 
[95]1/*
2*********************************************************************
3 * File: ximawmf.cpp
4 * Purpose: Windows Metafile Class Loader and Writer
5 * Author: Volker Horch - vhorch@gmx.de
6 * created: 13-Jun-2002
7 *
8 * Note: If the code below works, i wrote it.
9 * If it doesn't work, i don't know who wrote it.
10*********************************************************************
11 */
12
13/*
14*********************************************************************
15 Note by Author:
16*********************************************************************
17
18 Metafile Formats:
19 =================
20
21 There are 2 kinds of Windows Metafiles:
22 - Standard Windows Metafile
23 - Placeable Windows Metafile
24
25 A StandardWindows Metafile looks like:
26 - Metafile Header (MEATAHEADER)
27 - Metafile Records
28
29 A Placeable Metafile looks like:
30 - Aldus Header (METAFILEHEADER)
31 - Metafile Header (METAHEADER)
32 - Metafile Records
33
34 The "Metafile Header" and the "Metafile Records" are the same
35 for both formats. However, the Standard Metafile does not contain any
36 information about the original dimensions or x/y ratio of the Metafile.
37
38 I decided, to allow only placeable Metafiles here. If you also want to
39 enable Standard Metafiles, you will have to guess the dimensions of
40 the image.
41
42*********************************************************************
43 Limitations: see ximawmf.h
44 you may configure some stuff there
45*********************************************************************
46*/
47
48#include "ximawmf.h"
49
50#if CXIMAGE_SUPPORT_WMF && CXIMAGE_SUPPORT_WINDOWS
51
52////////////////////////////////////////////////////////////////////////////////
53#if CXIMAGE_SUPPORT_DECODE
54////////////////////////////////////////////////////////////////////////////////
55bool CxImageWMF::Decode(CxFile *hFile, long nForceWidth, long nForceHeight)
56{
57 if (hFile == NULL) return false;
58
59 HENHMETAFILE hMeta;
60 HDC hDC;
61 int cx,cy;
62
63 //save the current position of the file
64 long pos = hFile->Tell();
65
66 // Read the Metafile and convert to an Enhanced Metafile
67 METAFILEHEADER mfh;
68 hMeta = ConvertWmfFiletoEmf(hFile, &mfh);
69 if (hMeta) { // ok, it's a WMF
70
71/////////////////////////////////////////////////////////////////////
72// We use the original WMF size information, because conversion to
73// EMF adjusts the Metafile to Full Screen or does not set rclBounds at all
74// ENHMETAHEADER emh;
75// UINT uRet;
76// uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile
77// sizeof(ENHMETAHEADER), // size of buffer, in bytes
78// &emh); // address of buffer to receive data
79// if (!uRet){
80// DeleteEnhMetaFile(hMeta);
81// return false;
82// }
83// // calculate size
84// cx = emh.rclBounds.right - emh.rclBounds.left;
85// cy = emh.rclBounds.bottom - emh.rclBounds.top;
86/////////////////////////////////////////////////////////////////////
87
88 // calculate size
89 // scale the metafile (pixels/inch of metafile => pixels/inch of display)
90 // mfh.inch already checked to be <> 0
91
92 hDC = ::GetDC(0);
93 int cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);
94 int cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);
95 ::ReleaseDC(0, hDC);
96
97 cx = (mfh.inch/2 + (mfh.bbox.right - mfh.bbox.left) * cx1) / mfh.inch;
98 cy = (mfh.inch/2 + (mfh.bbox.bottom - mfh.bbox.top) * cy1) / mfh.inch;
99
100 } else { // maybe it's an EMF...
101
102 hFile->Seek(pos,SEEK_SET);
103
104 ENHMETAHEADER emh;
105 hMeta = ConvertEmfFiletoEmf(hFile, &emh);
106
107 if (!hMeta){
108 strcpy(info.szLastError,"corrupted WMF");
109 return false; // definitively give up
110 }
111
112 // ok, it's an EMF; calculate canvas size
113 cx = emh.rclBounds.right - emh.rclBounds.left;
114 cy = emh.rclBounds.bottom - emh.rclBounds.top;
115
116 // alternative methods, sometime not so reliable... [DP]
117 //cx = emh.szlDevice.cx;
118 //cy = emh.szlDevice.cy;
119 //
120 //hDC = ::GetDC(0);
121 //float hscale = (float)GetDeviceCaps(hDC, HORZRES)/(100.0f * GetDeviceCaps(hDC, HORZSIZE));
122 //float vscale = (float)GetDeviceCaps(hDC, VERTRES)/(100.0f * GetDeviceCaps(hDC, VERTSIZE));
123 //::ReleaseDC(0, hDC);
124 //cx = (long)((emh.rclFrame.right - emh.rclFrame.left) * hscale);
125 //cy = (long)((emh.rclFrame.bottom - emh.rclFrame.top) * vscale);
126 }
127
128 if (info.nEscape == -1) { // Check if cancelled
129 head.biWidth = cx;
130 head.biHeight= cy;
131 info.dwType = CXIMAGE_FORMAT_WMF;
132 DeleteEnhMetaFile(hMeta);
133 strcpy(info.szLastError,"output dimensions returned");
134 return true;
135 }
136
137 if (!cx || !cy) {
138 DeleteEnhMetaFile(hMeta);
139 strcpy(info.szLastError,"empty WMF");
140 return false;
141 }
142
143 if (nForceWidth) cx=nForceWidth;
144 if (nForceHeight) cy=nForceHeight;
145 ShrinkMetafile(cx, cy); // !! Otherwise Bitmap may have bombastic size
146
147 HDC hDC0 = ::GetDC(0); // DC of screen
148 HBITMAP hBitmap = CreateCompatibleBitmap(hDC0, cx, cy); // has # colors of display
149 hDC = CreateCompatibleDC(hDC0); // memory dc compatible with screen
150 ::ReleaseDC(0, hDC0); // don't need anymore. get rid of it.
151
152 if (hDC){
153 if (hBitmap){
154 RECT rc = {0,0,cx,cy};
155 int bpp = ::GetDeviceCaps(hDC, BITSPIXEL);
156
157 HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap);
158
159 // clear out the entire bitmap with windows background
160 // because the MetaFile may not contain background information
161 DWORD dwBack = XMF_COLOR_BACK;
162#if XMF_SUPPORT_TRANSPARENCY
163 if (bpp == 24) dwBack = XMF_COLOR_TRANSPARENT;
164#endif
165 DWORD OldColor = SetBkColor(hDC, dwBack);
166 ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
167 SetBkColor(hDC, OldColor);
168
169 //retrieves optional palette entries from the specified enhanced metafile
170 PLOGPALETTE plogPal;
171 PBYTE pjTmp;
172 HPALETTE hPal;
173 int iEntries = GetEnhMetaFilePaletteEntries(hMeta, 0, NULL);
174 if (iEntries) {
175 if ((plogPal = (PLOGPALETTE)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
176 sizeof(DWORD) + sizeof(PALETTEENTRY)*iEntries )) == NULL) {
177 DeleteObject(hBitmap);
178 DeleteDC(hDC);
179 DeleteEnhMetaFile(hMeta);
180 strcpy(info.szLastError,"Cancelled");
181 return false;
182 }
183
184 plogPal->palVersion = 0x300;
185 plogPal->palNumEntries = (WORD) iEntries;
186 pjTmp = (PBYTE) plogPal;
187 pjTmp += 4;
188
189 GetEnhMetaFilePaletteEntries(hMeta, iEntries, (PPALETTEENTRY)pjTmp);
190 hPal = CreatePalette(plogPal);
191 GlobalFree(plogPal);
192
193 SelectPalette(hDC, hPal, FALSE);
194 RealizePalette(hDC);
195 }
196
197 // Play the Metafile into Memory DC
198 BOOL bRet = PlayEnhMetaFile(hDC, // handle to a device context
199 hMeta, // handle to an enhanced metafile
200 &rc); // pointer to bounding rectangle
201
202 SelectObject(hDC, hBitmapOld);
203 DeleteEnhMetaFile(hMeta); // we are done with this one
204
205 if (info.nEscape) { // Check if cancelled
206 DeleteObject(hBitmap);
207 DeleteDC(hDC);
208 strcpy(info.szLastError,"Cancelled");
209 return false;
210 }
211
212 // the Bitmap now has the image.
213 // Create our DIB and convert the DDB into DIB
214 if (!Create(cx, cy, bpp, CXIMAGE_FORMAT_WMF)) {
215 DeleteObject(hBitmap);
216 DeleteDC(hDC);
217 return false;
218 }
219
220#if XMF_SUPPORT_TRANSPARENCY
221 if (bpp == 24) {
222 RGBQUAD rgbTrans = { XMF_RGBQUAD_TRANSPARENT };
223 SetTransColor(rgbTrans);
224 }
225#endif
226 // We're finally ready to get the DIB. Call the driver and let
227 // it party on our bitmap. It will fill in the color table,
228 // and bitmap bits of our global memory block.
229 bRet = GetDIBits(hDC, hBitmap, 0,
230 (UINT)cy, GetBits(), (LPBITMAPINFO)pDib, DIB_RGB_COLORS);
231
232 DeleteObject(hBitmap);
233 DeleteDC(hDC);
234
235 return (bRet!=0);
236 } else {
237 DeleteDC(hDC);
238 }
239 } else {
240 if (hBitmap) DeleteObject(hBitmap);
241 }
242
243 DeleteEnhMetaFile(hMeta);
244
245 return false;
246}
247
248/**********************************************************************
249 Function: CheckMetafileHeader
250 Purpose: Check if the Metafileheader of a file is valid
251**********************************************************************/
252BOOL CxImageWMF::CheckMetafileHeader(METAFILEHEADER *metafileheader)
253{
254 WORD *pw;
255 WORD cs;
256 int i;
257
258 // check magic #
259 if (metafileheader->key != 0x9ac6cdd7L) return false;
260
261 // test checksum of header
262 pw = (WORD *)metafileheader;
263 cs = *pw;
264 pw++;
265 for (i = 0; i < 9; i++) {
266 cs ^= *pw;
267 pw++;
268 }
269
270 if (cs != metafileheader->checksum) return false;
271
272 // check resolution
273 if ((metafileheader->inch <= 0) || (metafileheader->inch > 2540)) return false;
274
275 return true;
276}
277
278/**********************************************************************
279 Function: ConvertWmfFiletoEmf
280 Purpose: Converts a Windows Metafile into an Enhanced Metafile
281**********************************************************************/
282HENHMETAFILE CxImageWMF::ConvertWmfFiletoEmf(CxFile *fp, METAFILEHEADER *metafileheader)
283{
284 HENHMETAFILE hMeta;
285 long lenFile;
286 long len;
287 BYTE *p;
288 METAHEADER mfHeader;
289 DWORD seekpos;
290
291 hMeta = 0;
292
293 // get length of the file
294 lenFile = fp->Size();
295
296 // a placeable metafile starts with a METAFILEHEADER
297 // read it and check metafileheader
298 len = fp->Read(metafileheader, 1, sizeof(METAFILEHEADER));
299 if (len < sizeof(METAFILEHEADER)) return (hMeta);
300
301 if (CheckMetafileHeader(metafileheader)) {
302 // This is a placeable metafile
303 // Convert the placeable format into something that can
304 // be used with GDI metafile functions
305 seekpos = sizeof(METAFILEHEADER);
306 } else {
307 // Not a placeable wmf. A windows metafile?
308 // at least not scaleable.
309 // we could try to convert, but would loose ratio. don't allow this
310 return (hMeta);
311
312 //metafileheader->bbox.right = ?;
313 //metafileheader->bbox.left = ?;
314 //metafileheader->bbox.bottom = ?;
315 //metafileheader->bbox.top = ?;
316 //metafileheader->inch = ?;
317 //
318 //seekpos = 0;
319 // fp->Seek(0, SEEK_SET); // rewind
320 }
321
322 // At this point we have a metaheader regardless of whether
323 // the metafile was a windows metafile or a placeable metafile
324 // so check to see if it is valid. There is really no good
325 // way to do this so just make sure that the mtType is either
326 // 1 or 2 (memory or disk file)
327 // in addition we compare the length of the METAHEADER against
328 // the length of the file. if filelength < len => no Metafile
329
330 len = fp->Read(&mfHeader, 1, sizeof(METAHEADER));
331 if (len < sizeof(METAHEADER)) return (hMeta);
332
333 if ((mfHeader.mtType != 1) && (mfHeader.mtType != 2)) return (hMeta);
334
335 // Length in Bytes from METAHEADER
336 len = mfHeader.mtSize * 2;
337 if (len > lenFile) return (hMeta);
338
339 // Allocate memory for the metafile bits
340 p = (BYTE *)malloc(len);
341 if (!p) return (hMeta);
342
343 // seek back to METAHEADER and read all the stuff at once
344 fp->Seek(seekpos, SEEK_SET);
345 lenFile = fp->Read(p, 1, len);
346 if (lenFile != len) {
347 free(p);
348 return (hMeta);
349 }
350
351 // the following (commented code) works, but adjusts rclBound of the
352 // Enhanced Metafile to full screen.
353 // the METAFILEHEADER from above is needed to scale the image
354
355// hMeta = SetWinMetaFileBits(len, p, NULL, NULL);
356
357 // scale the metafile (pixels/inch of metafile => pixels/inch of display)
358
359 METAFILEPICT mfp;
360 int cx1, cy1;
361 HDC hDC;
362
363 hDC = ::GetDC(0);
364 cx1 = ::GetDeviceCaps(hDC, LOGPIXELSX);
365 cy1 = ::GetDeviceCaps(hDC, LOGPIXELSY);
366
367 memset(&mfp, 0, sizeof(mfp));
368
369 mfp.mm = MM_ANISOTROPIC;
370 mfp.xExt = 10000; //(metafileheader->bbox.right - metafileheader->bbox.left) * cx1 / metafileheader->inch;
371 mfp.yExt = 10000; //(metafileheader->bbox.bottom - metafileheader->bbox.top) * cy1 / metafileheader->inch;
372 mfp.hMF = 0;
373
374 // in MM_ANISOTROPIC mode xExt and yExt are in MM_HIENGLISH
375 // MM_HIENGLISH means: Each logical unit is converted to 0.001 inch
376 //mfp.xExt *= 1000;
377 //mfp.yExt *= 1000;
378 // ????
379 //int k = 332800 / ::GetSystemMetrics(SM_CXSCREEN);
380 //mfp.xExt *= k; mfp.yExt *= k;
381
382 // fix for Win9x
383 while ((mfp.xExt < 6554) && (mfp.yExt < 6554))
384 {
385 mfp.xExt *= 10;
386 mfp.yExt *= 10;
387 }
388
389 hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);
390
391 if (!hMeta){ //try 2nd conversion using a different mapping
392 mfp.mm = MM_TEXT;
393 hMeta = SetWinMetaFileBits(len, p, hDC, &mfp);
394 }
395
396 ::ReleaseDC(0, hDC);
397
398 // Free Memory
399 free(p);
400
401 return (hMeta);
402}
403/////////////////////////////////////////////////////////////////////
404HENHMETAFILE CxImageWMF::ConvertEmfFiletoEmf(CxFile *pFile, ENHMETAHEADER *pemfh)
405{
406 HENHMETAFILE hMeta;
407 long iLen = pFile->Size();
408
409 // Check the header first: <km>
410 long pos = pFile->Tell();
411 long iLenRead = pFile->Read(pemfh, 1, sizeof(ENHMETAHEADER));
412 if (iLenRead < sizeof(ENHMETAHEADER)) return NULL;
413 if (pemfh->iType != EMR_HEADER) return NULL;
414 if (pemfh->dSignature != ENHMETA_SIGNATURE) return NULL;
415 //if (pemfh->nBytes != (DWORD)iLen) return NULL;
416 pFile->Seek(pos,SEEK_SET);
417
418 BYTE* pBuff = (BYTE *)malloc(iLen);
419 if (!pBuff) return (FALSE);
420
421 // Read the Enhanced Metafile
422 iLenRead = pFile->Read(pBuff, 1, iLen);
423 if (iLenRead != iLen) {
424 free(pBuff);
425 return NULL;
426 }
427
428 // Make it a Memory Metafile
429 hMeta = SetEnhMetaFileBits(iLen, pBuff);
430
431 free(pBuff); // finished with this one
432
433 if (!hMeta) return NULL; // oops.
434
435 // Get the Enhanced Metafile Header
436 UINT uRet = GetEnhMetaFileHeader(hMeta, // handle of enhanced metafile
437 sizeof(ENHMETAHEADER), // size of buffer, in bytes
438 pemfh); // address of buffer to receive data
439
440 if (!uRet) {
441 DeleteEnhMetaFile(hMeta);
442 return NULL;
443 }
444
445 return (hMeta);
446}
447////////////////////////////////////////////////////////////////////////////////
448#endif //CXIMAGE_SUPPORT_DECODE
449////////////////////////////////////////////////////////////////////////////////
450#if CXIMAGE_SUPPORT_ENCODE
451/////////////////////////////////////////////////////////////////////
452bool CxImageWMF::Encode(CxFile * hFile)
453{
454 if (hFile == NULL) return false;
455 strcpy(info.szLastError, "Save WMF not supported");
456 return false;
457}
458#endif // CXIMAGE_SUPPORT_ENCODE
459/////////////////////////////////////////////////////////////////////
460
461/**********************************************************************
462Function: ShrinkMetafile
463Purpose: Shrink the size of a metafile to be not larger than
464 the definition
465**********************************************************************/
466void CxImageWMF::ShrinkMetafile(int &cx, int &cy)
467{
468 int xScreen = XMF_MAXSIZE_CX;
469 int yScreen = XMF_MAXSIZE_CY;
470
471 if (cx > xScreen){
472 cy = cy * xScreen / cx;
473 cx = xScreen;
474 }
475
476 if (cy > yScreen){
477 cx = cx * yScreen / cy;
478 cy = yScreen;
479 }
480}
481
482#endif // CIMAGE_SUPPORT_WMF
483
Note: See TracBrowser for help on using the repository browser.