C++/Exporting GDI drawings to WMF/EMF file or clipboard.
I am working on application that draws its processing nodes(actual data processing funtions) as flow chart showing functions as rectangular nodes and arrow lines respresenting links between diff functions showing the inputs and outputs of the nodes. Nodes have textual title.
Now i want to export this GDI drawings to windows metafiles (enhanced metafiles) and clipboard so that it can be used by other applications as wmf image.
I havent done this before but i think there is a way to created metafile device context (or create enhanced metafiles using current ref device context of the drawing area). I would appriciate further guidance in this regard.
Is it the case that while drawing into metafile the reference device context state has to be stored before creating metafile device context???? And later it must be restored to undone any changes made happens to it while drawing in metafile??? I have no clear idea abt it :(
zaheer , Thank you for your question.
I apologize for not responding sooner. I have been very busy. I hope you will forgive me.
A metafile is a list of records. Each record represents one GDI operation (resulting from a GDI function call), such as Rectangle or BitBlt, operating on a GDI Device Context.
Metafile records can be copied to the Clipboard (use the CST_ENHMETAFILE (or the older CF_METAFILEPICT) format code).
Here is sample code from the MSDN Library for creating a metafile on disk from a Device Context:
Creating an Enhanced Metafile
This section contains an example that demonstrates the creation of an enhanced metafile that is stored on a disk, using a filename specified by the user.
The example uses a device context for the application window as the reference device context. (The system stores the resolution data for this device in the enhanced-metafile's header.) The application retrieves a handle identifying this device context by calling the GetDC function.
The example uses the dimensions of the application's client area to define the dimensions of the picture frame. Using the rectangle dimensions returned by theGetClientRect function, the application converts the device units to .01-millimeter units and passes the converted values to the CreateEnhMetaFile function.
The example displays a Save As common dialog box that enables the user to specify the filename of the new enhanced metafile. The system appends the three-character .EMF extension to this filename and passes the name to the CreateEnhMetaFile function.
The example also embeds a text description of the picture in the enhanced-metafile header. This description is specified as a resource in the string table of the application's resource file. However, in a working application, this string would be retrieved from a custom control in a common dialog box or from a separate dialog box displayed solely for this purpose.
// Obtain a handle to a reference device context.
hdcRef = GetDC(hWnd);
// Determine the picture frame dimensions.
// iWidthMM is the display width in millimeters.
// iHeightMM is the display height in millimeters.
// iWidthPels is the display width in pixels.
// iHeightPels is the display height in pixels
iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE);
iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE);
iWidthPels = GetDeviceCaps(hdcRef, HORZRES);
iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
// Retrieve the coordinates of the client
// rectangle, in pixels.
// Convert client coordinates to .01-mm units.
// Use iWidthMM, iWidthPels, iHeightMM, and
// iHeightPels to determine the number of
// .01-millimeter units per pixel in the x-
// and y-directions.
rect.left = (rect.left * iWidthMM * 100)/iWidthPels;
rect.top = (rect.top * iHeightMM * 100)/iHeightPels;
rect.right = (rect.right * iiWidthMM * 100)/iWidthPels;
rect.bottom = (rect.bottom * iHeightMM * 100)/iHeightPels;
// Load the filename filter from the string table.
// Replace the '%' separators that are embedded
// between the strings in the string-table entry
// with '\0'.
for (i=0; szFilter[i]!='\0'; i++)
if (szFilter[i] == '%')
szFilter[i] = '\0';
// Load the dialog title string from the table.
// Initialize the OPENFILENAME members.
szFile = '\0';
Ofn.lStructSize = sizeof(OPENFILENAME);
Ofn.hwndOwner = hWnd;
Ofn.lpstrFilter = szFilter;
Ofn.nMaxFile = sizeof(szFile);
Ofn.lpstrFileTitle = szFileTitle;
Ofn.nMaxFileTitle = sizeof(szFileTitle);
Ofn.lpstrInitialDir = (LPSTR)NULL;
Ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;
Ofn.lpstrTitle = szTitle;
// Display the Filename common dialog box. The
// filename specified by the user is passed
// to the CreateEnhMetaFile function and used to
// store the metafile on disk.
// Load the description from the string table.
// Replace the '%' string separators that are
// embedded between strings in the string-table
// entry with '\0'.
for (i=0; szDescription[i]!='\0'; i++)
if (szDescription[i] == '%')
szDescription[i] = '\0';
// Create the metafile device context.
hdcMeta = CreateEnhMetaFile(hdcRef,
// Release the reference device context.
Thankyou very much for your reply. Its ok with me even if you would have never reply :) because i know its not easy for you people here at allexperts.com to take time out of your busy schedule. I appriciate your willingness to help people at no cost.
Mean while i had already gone through the example at msdn this means. but the few confusions are there:
1. The thing i am not getting is that after creating EMF(DC) will there be any effect on REF-DC as application has to redraw whole thing into EMF DC to be saved in a file. So i am not sure abt this relation between both DC's. I mean what will ahppened to already drawn graphics on the screen? will they get changed? should i store the state of REF DC before creating metafile DC?
2.In my application there is zoom functionality implemented. And every time i run my application with different input data the drawn graph(flow chart) could be of different sizes. Some time its fully visible because its small enough and some time it get hidden because of its large size and cant be visible in available client area. To create meatfile dc we have to inform it abt the size of image we want to store ( that will be size of meta file). Question is how to calculate exact rectangular(bounding box) area of drawing that need to be saved. Same question goes for zoomed(in/out) drawing.
1. A DC represents a drawn image. When you draw on a DC, the GDI records are saved while the image is drawn. So you should not need two DCs to draw to a window and then save the image in a .wmf file.
2. If you are displaying your entire large image, and the image is cut off due to a rectangular Region or other reason, there is probably no need to compute a bounding box. The wmf output is an exact replica of the drawn image. So when your app loads the .wmf file and displays it, the image will be cut off in the same way. If you open the .wmf file using a regular viewing program, you may be able to view the entire image, not just the part that your app showed.
Your questions may be getting too detailed for me, since I have never used metafiles. I suggest that you post this question at www.experts-exchange.com, which is more advanced than allexperts.com.