From pkampst=rbugspam at few.vu.nl  Fri Nov  3 11:33:54 2006
From: pkampst=rbugspam at few.vu.nl (pkampst=rbugspam at few.vu.nl)
Date: Fri,  3 Nov 2006 11:33:54 +0100 (CET)
Subject: [Rd] win.metafile() resolution too low (PR#9337)
Message-ID: <20061103103354.D7E5057287@slim.kubism.ku.dk>

Full_Name: Peter Kampstra
Version: 2.4.0
OS: Windows
Submission from: (NULL) (130.37.20.20)


Hi,

If you use win.metafile(), "Save as metafile...", or "Copy as metafile" on
Windows, the metafile is rendered at screen resolution. Therefore, the output of
curves like

win.metafile("resolution.emf")
x=seq(1,10,0.001)
y=1/x
plot(x,y,type="l")
dev.off()

does not look smooth. I tracked the problem down to
https://svn.r-project.org/R/trunk/src/gnuwin32/graphapp/metafile.c , to
    hDC = CreateEnhMetaFile(NULL, strlen(name) ? name : NULL, &wr, 
			    "GraphApp\0\0");
If NULL is passed as reference HDC to this function, the metafile will be at
screen resolution. If you use such a picture in Word/Powerpoint/etc, it is
visible that curved lines are not smooth...

Therefore, I suggest using a printer as the reference HDC instead. The following
function can be used:

/*
 *  Creates a HDC to the best printer to be used as a reference for
CreateEnhMetaFile
 */
HDC createbestmetafilehdc() {
	DWORD				neededsize;
	DWORD				noprinters;
	DWORD				printer;
	LPPRINTER_INFO_5	printerinfo = NULL;
	int					bestres = 0;
	HDC					besthdc = 0;

	EnumPrinters(PRINTER_ENUM_CONNECTIONS|PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0,
&neededsize, &noprinters);
 	printerinfo = (LPPRINTER_INFO_5) malloc(neededsize);

	if (EnumPrinters(PRINTER_ENUM_CONNECTIONS|PRINTER_ENUM_LOCAL, NULL, 5,
(LPBYTE)printerinfo, neededsize, &neededsize, &noprinters)) {
		//init best resolution for hdc=0, which is screen resolution:    
		HDC curhdc = GetDC(NULL);
		if (curhdc) {
			bestres = GetDeviceCaps(curhdc, LOGPIXELSX) + GetDeviceCaps(curhdc,
LOGPIXELSY);
			bestres = ReleaseDC(NULL, curhdc); 
		}

		for (int i = 0; i < noprinters; i++) {
			curhdc = CreateDC("WINSPOOL", printerinfo[i].pPrinterName, NULL, NULL);
			if (curhdc) {
				int curres = GetDeviceCaps(curhdc, LOGPIXELSX) + GetDeviceCaps(curhdc,
LOGPIXELSY);
				if (curres > bestres) {
					if (besthdc)
						DeleteDC(besthdc);
					bestres = curres;
					besthdc = curhdc;
				} else {
					DeleteDC(curhdc);
				}
			}
		}
	}

	free(printerinfo);
	return besthdc;
}

This function can be used like:
	HDC refhdc=createbestmetafilehdc();

	hDC = CreateEnhMetaFile(refhdc, strlen(name) ? name : NULL, &wr, 
			    "GraphApp\0\0");
	if (refhdc)
		DeleteDC(refhdc);

And cppix,ppix, etc. can be calculated like (this is a workaround for buggy
drivers??):
	HDC forhdc=refhdc;
	if (!(forhdc))
		forhdc=GetDC(NULL);                   
	cppix = 25.40 * GetDeviceCaps(forhdc,HORZRES) /
GetDeviceCaps(forhdc,HORZSIZE);
	ppix  = 100 * GetDeviceCaps(forhdc, LOGPIXELSX);
	cppiy = 25.40 * GetDeviceCaps(forhdc, VERTRES) / GetDeviceCaps(forhdc,
VERTSIZE);
	ppiy  = 100 * GetDeviceCaps(forhdc, LOGPIXELSY);
	if (!(refhdc))
		ReleaseDC(NULL,forhdc);

And probably some other changes will be necessary...

Keep up the good work,

Peter Kampstra
pkampst=rbugspam at cs.vu.nl / http://peter.kampstra.net



[Rd] win.metafile() resolution too low (PR#9337)
pkampst=rbugspam at few.vu.nl