I am creating desktop application using C++
and pure WinApi
. I need to display image that was given to me as SVG
.
Since WinAPI
supports only EMF
files as vector format, I have used Inkscape
to convert the file into EMF
. My graphics design skills are at beginner level, but I have managed to convert SVG
file into EMF
successfully. However, the result is not looking as the original one, it is less "precise" so to say.
If I export the SVG
as PNG
and display it with GDI+
, the result is the same as the original file. Unfortunately I need vector format.
To see exactly what I mean, download SVG
, and EMF
and PNG
that I made here. Just click on Download:test.rar above 5 yellow stars ( see image below ).
Here are the instructions for creating minimal application that reproduces the problem:
1) Create default Win32 project
in Visual Studio
( I use VS 2008, but this shouldn't be the problem );
2) Rewrite WM_PAINT
like this:
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rcClient;
GetClientRect( hWnd, &rcClient );
FillRect( hdc, &rcClient, (HBRUSH)GetStockObject( LTGRAY_BRUSH) );
// put metafile in the same place your app is
HENHMETAFILE hemf = GetEnhMetaFile( L".\\test.emf" );
ENHMETAHEADER emh;
GetEnhMetaFileHeader( hemf, sizeof(emh), &emh );
// rescale metafile, and keep proportion
UINT o_height = emh.rclFrame.bottom - emh.rclFrame.top,
o_width = emh.rclFrame.right - emh.rclFrame.left;
float scale = 0.5;
scale = (float)( rcClient.right - rcClient.left ) / o_width;
if( (float)( rcClient.bottom - rcClient.top ) / o_height < scale )
scale = (float)( rcClient.bottom - rcClient.top ) / o_height;
int marginX = ( rcClient.right - rcClient.left ) - (int)( o_width * scale );
int marginY = ( rcClient.bottom - rcClient.top ) - (int)( o_height * scale );
marginX /= 2;
marginY /= 2;
rcClient.left = rcClient.left + marginX;
rcClient.right = rcClient.right - marginX;
rcClient.top = rcClient.top + marginY;
rcClient.bottom = rcClient.bottom - marginY;
// Draw the picture.
PlayEnhMetaFile( hdc, hemf, &rcClient );
// Release the metafile handle.
DeleteEnhMetaFile(hemf);
EndPaint(hWnd, &ps);
}
break;
3) Add following handlers for WM_SIZE
and WM_ERASEBKGND
just below WM_PAINT
:
case WM_SIZE:
InvalidateRect( hWnd, NULL, FALSE );
return 0L;
case WM_ERASEBKGND:
return 1L;
4) Resize the window to the smallest possible size, and then maximize it.
Notice that the bigger the window gets, the better the image quality is, but the smaller it gets the "less precise" the image gets. I tested this on Windows XP
.
I am asking your help to get the same graphic quality of the EMF file as the original SVG
.
Thank you for your time and efforts. Best regards.
Solved it!
The solution makes much, if not all of the solution I've submitted redundant. I've therefore decided to replace it with this one.
There's a number of things to take into account and a number of concepts that are employed to get the desired result. These include (in no particular order)
I also note that I've used old code to draw the background manually each time the screen is refreshed. A much better approach would be to create a patternBrush once which is then simply copied using the FillRect function. This is much faster than filling the rect with a solid colour and then drawing the lines over the top. I can't be bothered to re-write that part of the code, though I'll include a snippet for reference that I've used in other projects in the past.
Here's a couple of shots of the result I get from the code below:
Here's the code I used to achieve it:
Finally, here's an example of creating a patternBrush for filling the background using the FillRect function. This approach is suitable for any tileable background.
Example of result, created with:
HBRUSH bkBrush = makeCheckerBrush(8, RGB(153,153,153), RGB(102,102,102));