1 #ifdef EMF
2 /*
3 Copyright (c) 2001 Bengt-Arne Fjellner All rights reserved.
4
5 Distributed by Free Software Foundation, Inc.
6
7 This file is part of HP2xx.
8
9 HP2xx is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
11 to anyone for the consequences of using it or for whether it serves any
12 particular purpose or works at all, unless he says so in writing. Refer
13 to the GNU General Public License, Version 2 or later, for full details.
14
15 Everyone is granted permission to copy, modify and redistribute
16 HP2xx, but only under the conditions described in the GNU General Public
17 License. A copy of this license is supposed to have been
18 given to you along with HP2xx so you can know your rights and
19 responsibilities. It should be in a file named COPYING. Among other
20 things, the copyright notice and this notice must be preserved on all
21 copies.
22
23 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24 */
25
26 /* to_emf.c: Converter to Windows Enhanced meta file format+printer for windows;
27 ** And windows preview
28 ** tested with visualc 6.0 and c++builder 5.0
29 ** known to work under win98 and win2000
30 **
31 ** 01/10/15 V 1.00 BAF Derived from to_eps.c to create Enhanced MetaFile
32 ** 01/10/17 V 1.01 BAF Added Windows Print
33 ** 01/10/17 V 1.02 BAF Added Windows Preview
34 ** 01/10/23 V 1.04 BAF Updated to 3.4.1
35 ** 01/11/25 V 1.05 BAF Updated to 3.4.1b
36 ** 02/06/?? V 1.06 ??? Support for EMF under UNIX
37 ** 02/07/05 V 1.07 BAF Fixup for UNIX support and a little cleanup
38 */
39
40 #ifndef EMF
41 #error Compiling to_emf.c without having defined EMF. this is meaningless.
42 #endif
43
44
45 #ifdef UNIX
46 #include <emf.h>
47 #else
48 #include <windows.h>
49 #undef ERROR
50 #undef NUMPENS
51 #ifdef NOERROR
52 #undef NOERROR
53 #endif
54 #endif
55
56
57 #include <stdio.h>
58 #include <math.h>
59 #include "bresnham.h"
60 #include "hp2xx.h"
61 #include "pendef.h"
62 #include "lindef.h"
63
64 extern void reset_tmpfile(void); // in hpgl.c
65
66
67 typedef struct { // for use by preview Dialog
68 const GEN_PAR *pg;
69 const OUT_PAR *po;
70 } PGPO;
71
72 #define PRINT 128 // Message number for print menu
73 #define MARGIN 20 // How wide Empty box around it
74
75 static int lines = 0, moves = 0; // counters to show how "difficult" this plot is
76
77 //*******************************************************************
78 // move dont draw
emf_move_to(HPGL_Pt * ppt,HANDLE outDC)79 static void emf_move_to(HPGL_Pt * ppt, HANDLE outDC)
80 {
81 MoveToEx(outDC, (int) (ppt->x), (int) (ppt->y), NULL);
82 moves++;
83 }
84
85
86 //*******************************************************************
87 // new_pen
88 static void
emf_new_pen(PEN_W pensize,double red,double green,double blue,HPGL_Pt * ppt,HANDLE outDC)89 emf_new_pen(PEN_W pensize, double red, double green, double blue,
90 HPGL_Pt * ppt, HANDLE outDC)
91 {
92 HANDLE pen;
93 emf_move_to(ppt, outDC);
94 if (pensize > 0.)
95 pen =
96 CreatePen(PS_SOLID, (int) (5. * pensize),
97 RGB((int) red, (int) green, (int) blue));
98 else
99 pen =
100 CreatePen(PS_NULL, (int) (5. * pensize),
101 RGB((int) red, (int) green, (int) blue));
102
103 DeleteObject(SelectObject(outDC, pen));
104 }
105
106 //*******************************************************************
107 // Possibly draw dependent on mode
emf_line_to(HPGL_Pt * ppt,char mode,HANDLE outDC)108 static void emf_line_to(HPGL_Pt * ppt, char mode, HANDLE outDC)
109 {
110 if (mode == 'D') {
111 LineTo(outDC, (int) (ppt->x), (int) (ppt->y));
112 lines++;
113 } else {
114 MoveToEx(outDC, (int) (ppt->x), (int) (ppt->y), NULL);
115 moves++;
116 }
117 }
118
119 //*******************************************************************
120 //draw an invisible box around the area so that the metafile gets the size
emf_init(const OUT_PAR * po,HANDLE outDC)121 static void emf_init(const OUT_PAR * po, HANDLE outDC)
122 {
123 long left, right, low, high;
124 low = (int) (po->ymin / 40 - MARGIN);
125 high = (int) (po->ymax + MARGIN);
126 high = (long) ((po->ymin / 40 + po->height));
127 left = (int) ((po->xmin / 40 - MARGIN));
128 right = (int) po->xmax + MARGIN;
129 right = (long) ((po->xmin / 40 + po->width));
130 MoveToEx(outDC, left, low, NULL);
131 LineTo(outDC, right, low);
132 LineTo(outDC, right, high);
133 LineTo(outDC, left, high);
134 LineTo(outDC, left, low);
135 }
136
137
138
139 //*******************************************************************
140 // command loop over tmp_file
plotit(HANDLE outDC,const GEN_PAR * pg,const OUT_PAR * po)141 static int plotit(HANDLE outDC, const GEN_PAR * pg, const OUT_PAR * po)
142 {
143 PlotCmd cmd;
144 HPGL_Pt pt1 = { 0 };
145 int pen_no = 0, pencolor = 0, err = 0;
146 PEN_W pensize;
147 pensize = pt.width[DEFAULT_PEN_NO]; /* Default pen */
148 pencolor = pt.color[DEFAULT_PEN_NO];
149 emf_new_pen(0, pt.clut[pencolor][0], // no draw pen
150 pt.clut[pencolor][1], pt.clut[pencolor][2], &pt1,
151 outDC);
152
153 emf_init(po, outDC); // invisible boundingbox
154 emf_new_pen(pensize, pt.clut[pencolor][0], pt.clut[pencolor][1],
155 pt.clut[pencolor][2], &pt1, outDC);
156
157 /**
158 ** Command loop: While temporary file not empty: process command.
159 **/
160
161 while ((cmd = PlotCmd_from_tmpfile()) != CMD_EOF) {
162 switch (cmd) {
163 case NOP:
164 break;
165 case SET_PEN:
166 if ((pen_no = fgetc(pg->td)) == EOF) {
167 PError("Unexpected end of temp. file: ");
168 err = ERROR;
169 goto emf_exit;
170 }
171 pensize = pt.width[pen_no];
172 pencolor = pt.color[pen_no];
173 emf_new_pen(pensize, pt.clut[pencolor][0],
174 pt.clut[pencolor][1],
175 pt.clut[pencolor][2], &pt1, outDC);
176 break;
177 case DEF_PW: // DEFine penwidth
178 if (!load_pen_width_table(pg->td)) {
179 PError("Unexpected end of temp. file");
180 err = ERROR;
181 goto emf_exit;
182 }
183 break;
184 case DEF_PC: //DEFpen color
185 err = load_pen_color_table(pg->td);
186 if (err < 0) {
187 PError("Unexpected end of temp. file");
188 err = ERROR;
189 goto emf_exit;
190 }
191 if (err == pencolor)
192 pencolor *= -1; /*current pen changed */
193 break;
194 case DEF_LA:
195 if (load_line_attr(pg->td) < 0) {
196 PError("Unexpected end of temp. file");
197 err = ERROR;
198 goto emf_exit;
199 }
200 break;
201 case MOVE_TO: // Moveto
202
203 HPGL_Pt_from_tmpfile(&pt1);
204 if (pensize != 0)
205 emf_move_to(&pt1, outDC);
206 break;
207 case DRAW_TO: // Draw line
208 HPGL_Pt_from_tmpfile(&pt1);
209 if (pensize != 0)
210 emf_line_to(&pt1, 'D', outDC);
211 break;
212 case PLOT_AT:
213 HPGL_Pt_from_tmpfile(&pt1);
214 if (pensize != 0) {
215 emf_line_to(&pt1, 'M', outDC);
216 emf_line_to(&pt1, 'D', outDC);
217 }
218 break;
219 default:
220 Eprintf("Illegal cmd in temp. file!");
221 err = ERROR;
222 goto emf_exit;
223 }
224 }
225 /* Finish up */
226 emf_exit:
227 {
228 HANDLE old =
229 SelectObject(outDC, GetStockObject(BLACK_PEN));
230 DeleteObject(old);
231 }
232 return err;
233 }
234
235 #ifndef UNIX
236 //*******************************************************************
237 // helper to set scaling for print/preview
SetScale(HDC dc,int uthei,int utwi,const OUT_PAR * po)238 static void SetScale(HDC dc, int uthei, int utwi, const OUT_PAR * po)
239 {
240 int width, height, mul, div;
241 float yfact, xfact;
242 long left, right, low, high;
243 low = (int) (po->ymin - MARGIN);
244 high = (int) (po->ymax + MARGIN);
245 left = (int) po->xmin - MARGIN;
246 right = (int) po->xmax + MARGIN;
247
248 width = right - left;
249 height = high - low;
250 //to this point only used dest coords
251 yfact = uthei / (float) height;
252 xfact = utwi / (float) width;
253 SetMapMode(dc, MM_ANISOTROPIC);
254 if (fabs(yfact) < fabs(xfact)) {
255 div = height;
256 mul = uthei;
257 } else {
258 div = width;
259 mul = utwi;
260 }
261
262 SetViewportExtEx(dc, mul, -mul, NULL); // size mult
263 SetWindowExtEx(dc, div, div, NULL); // size divisor
264 SetWindowOrgEx(dc, left, high, NULL); // where was origo
265 SetViewportOrgEx(dc, 0, 0, NULL); // where do i want origo
266 }
267
268 //*******************************************************************
269 // Mesage handler for Preview Dialog.
270 static INT_PTR CALLBACK
Preview(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)271 Preview(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
272 {
273 static const GEN_PAR *pg;
274 static const OUT_PAR *po;
275 static int first = 1;
276
277 switch (message) {
278 case WM_INITDIALOG:
279 {
280 HMENU meny;
281 PGPO *p = (PGPO *) lParam;
282 po = p->po; // save them for print/draw later on
283 pg = p->pg;
284 SetWindowText(hDlg, "Preview Enter to close");
285 meny = GetSystemMenu(hDlg, 0);
286 // add print item to bottom of system menu
287 InsertMenu(meny, (unsigned) -1, MF_BYPOSITION,
288 PRINT, "Print");
289 }
290 return TRUE;
291 case WM_SIZE:
292 InvalidateRect(hDlg, 0, TRUE); // redraw all
293 return TRUE;
294
295 case WM_SYSCOMMAND:
296 if (LOWORD(wParam) == PRINT) {
297 reset_tmpfile(); //rewind so i can reuse the data (in hpgl.c)
298 to_emp(pg, po);
299 return TRUE;
300 }
301 return FALSE;
302
303 case WM_COMMAND:
304 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
305 EndDialog(hDlg, LOWORD(wParam));
306 return TRUE;
307 }
308 break;
309 case WM_PAINT:
310 {
311 RECT rt;
312 PAINTSTRUCT ps;
313 HDC dc;
314 dc = BeginPaint(hDlg, &ps);
315 GetClientRect(hDlg, &rt);
316 SetScale(dc, rt.bottom, rt.right, po);
317
318 reset_tmpfile(); //rewind so i can redraw it in hpgl.c
319 plotit(dc, pg, po);
320 EndPaint(hDlg, &ps);
321 if (first) {
322 Eprintf("\nWaiting for preview to end\n");
323 first = 0;
324 }
325 }
326 return TRUE;
327 case WM_ERASEBKGND: // fix white background
328 {
329 RECT rt;
330 GetClientRect(hDlg, &rt);
331 rt.bottom += 1;
332 rt.right += 1;
333 FillRect((HDC) wParam, &rt,
334 GetStockObject(WHITE_BRUSH));
335 }
336 return TRUE;
337 }
338 return FALSE;
339 }
340
341 //*******************************************************************
342 // everything above is local
343 // here starts the part that is visible from outside
344 //*******************************************************************
345
346 /**
347 ** Higher-level interface: Windows print it (-m emp)
348 **/
to_emp(const GEN_PAR * pg,const OUT_PAR * po)349 int to_emp(const GEN_PAR * pg, const OUT_PAR * po)
350 {
351 DEVMODE *dev;
352 PRINTDLG pd;
353 DOCINFO di = { 0 };
354
355 int xpix, ypix; //DPI
356
357 int yprinter, xprinter, err;
358 // Initialize PRINTDLG
359 ZeroMemory(&pd, sizeof(PRINTDLG));
360 pd.lStructSize = sizeof(PRINTDLG);
361 pd.hwndOwner = NULL;
362 pd.hDevMode = NULL; // Don't forget to free or store hDevMode
363 pd.hDevNames = NULL; // Don't forget to free or store hDevNames
364 pd.Flags = PD_RETURNDEFAULT; // gives default printer
365 pd.nCopies = 1;
366 pd.nFromPage = 0xFFFF;
367 pd.nToPage = 0xFFFF;
368 pd.nMinPage = 1;
369 pd.nMaxPage = 0xFFFF;
370
371 PrintDlg(&pd); // first call to fill devmode struct from default printer
372
373 dev = GlobalLock(pd.hDevMode);
374
375 //Auto orient paper
376 if (fabs(po->xmax - po->xmin) < fabs(po->ymax - po->ymin))
377 dev->dmOrientation = DMORIENT_PORTRAIT;
378 else
379 dev->dmOrientation = DMORIENT_LANDSCAPE;
380 GlobalUnlock(pd.hDevMode);
381 pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
382
383 // now check which printer he wants
384 if (PrintDlg(&pd) != TRUE)
385 return 0;
386
387 Eprintf("\n\n- Printing it -\n");
388 GlobalFree(pd.hDevMode);
389 GlobalFree(pd.hDevNames);
390
391 xprinter = GetDeviceCaps(pd.hDC, HORZRES); // papper width in pixels
392 yprinter = GetDeviceCaps(pd.hDC, VERTRES); // height in pixels
393 xpix = GetDeviceCaps(pd.hDC, LOGPIXELSX); // DPI x to be checked
394 ypix = GetDeviceCaps(pd.hDC, LOGPIXELSY); // DPI y
395 // the following code is an attempt to compensate for printers with different
396 // X and y resolution ( Not tested !!!)
397 if (xpix < ypix) {
398 xprinter = (int) (xprinter * ((float) xpix) / ypix);
399 } else if (xpix > ypix) {
400 yprinter = (int) (yprinter * ((float) ypix) / xpix);
401 }
402 SetScale(pd.hDC, yprinter, xprinter, po);
403
404 di.cbSize = sizeof(DOCINFO);
405 di.lpszDocName = "HPGL File";
406
407 // Begin a print job by calling the StartDoc function.
408 StartDoc(pd.hDC, &di);
409
410 // Inform the driver that the application is about to begin
411 // sending data.
412 StartPage(pd.hDC);
413
414 err = plotit(pd.hDC, pg, po);
415 EndPage(pd.hDC);
416 EndDoc(pd.hDC);
417
418 DeleteDC(pd.hDC);
419 if (!pg->quiet) {
420 Eprintf("\nlines=%d moves=%d", lines, moves);
421 Eprintf("\n");
422 }
423 return err;
424 }
425
426 /**
427 ** Higher-level interface: Windows Preview (-m pre or nothing)
428 **/
to_emw(const GEN_PAR * pg,const OUT_PAR * po)429 int to_emw(const GEN_PAR * pg, const OUT_PAR * po)
430 {
431 PGPO par;
432 PWORD p;
433 LPDLGTEMPLATE templ;
434 p = (PWORD) GlobalAlloc(GPTR, sizeof(DLGTEMPLATE) + 8);
435 templ = (LPDLGTEMPLATE) p;
436 // Memory is already zeroed so i dont set zeroes
437 // Start to fill in the dlgtemplate information, addressing by WORDs.
438 templ->style =
439 WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION |
440 WS_SYSMENU | WS_THICKFRAME;
441 templ->cx = 480; // size in "dialog units"
442 templ->cy = 320;
443 // since i allocated 8 extra bytes i have menu=0 class=0 title=0
444 // which means no menu standard dialog and no title
445 // i fix title in WM_INIT and background by WM_ERASEBKGND
446 par.pg = pg;
447 par.po = po;
448 DialogBoxIndirectParam(0, templ, 0, Preview, (LPARAM) & par);
449 GlobalFree(GlobalHandle(p));
450
451 return 0;
452 }
453 #endif /*notdef UNIX */
454
455 /**
456 ** Higher-level interface: Output Enhanced META File format (-m emf)
457 **/
to_emf(const GEN_PAR * pg,const OUT_PAR * po)458 int to_emf(const GEN_PAR * pg, const OUT_PAR * po)
459 {
460 HANDLE outDC;
461 int err = 0;
462 if (!pg->quiet)
463 Eprintf("\n\n- Writing emf code to \"%s\"\n",
464 *po->outfile == '-' ? "stdout" : po->outfile);
465
466 /* Init. */
467
468 if (*po->outfile != '-') {
469 if ((outDC =
470 CreateEnhMetaFile(NULL, po->outfile, NULL,
471 "hp2xx\0\0")) == 0) {
472 PError("hp2xx (emf)");
473 return ERROR;
474 }
475 } else {
476 PError("hp2xx (Cant send metafile to stdout emf)");
477 return ERROR;
478 }
479 SetMapMode(outDC, MM_ANISOTROPIC);
480 SetViewportExtEx(outDC, 10, -10, NULL); // size mult
481 err = plotit(outDC, pg, po);
482 CloseEnhMetaFile(outDC);
483
484 if (!pg->quiet) {
485 Eprintf("\nlines=%d moves=%d", lines, moves);
486 Eprintf("\n");
487 }
488 return err;
489 }
490
491 #endif
492