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