|

Introduction
I have come across loads of libraries which convert images from one format to other, but most of them are confined to conversion between raster formats like BMP, JPG, GIF etc., This article explains a class which encapsulates the functionality of converting a vector file format (EMF) to raster file format (BMP). Once an EMF is converted to BMP raster file format, it can then be converted to any other format using the freely available libraries like CxImage.
Background
I had this problem of converting an EMF to BMP when I was doing my earlier project. I have searched a lot for help but couldn't find any except that many people asking similar question in discussion groups. I thought I should share this solution with others and wrote my first article to Code project. I hope it will be useful to you.
Using the code
Using this code is very simple. Just instantiate the class and call the convert function like this: CConvertEMFToBMP conv;
BOOL bRet = conv.ConvertEMFToBMP(m_strEMF,m_strBMP,m_chkScale);
ConvertEMFToBMP takes three parameters:
Example: CConvertEMFToBMP conv;
BOOL bRet = conv.ConvertEMFToBMP("D:\temp\Sample.emf",
"D:\temp\sample.bmp",false);
To Convert a BMP to EMF: CConvertEMFToBMP conv;
BOOL bRet = conv.ConvertBMPToEMF(m_strBMP,m_strEMF);
ConvertBMPToEMF takes two paramters:
m_strBMP - path and file name of BMP file to be converted
m_strEMF - path and file name of EMF file
Example: CConvertEMFToBMP conv;
BOOL bRet = conv.ConvertBMPToEMF("D:\temp\Sample.bmp",
"D:\temp\sample.emf",false);
How Does it Work?There is no straight forward technique to convert an EMF to BMP. ConvertEMFToBMP converts an EMF to Bitmap by playing the metafile in the MemoryDC and then getting the DIB bits and storing them in the bitmap format. To get the memory DC, an invisible window is created and destroyed at the end of conversion. alternatively, the source code can be modified to take the hwnd to the ConvertEMFToBMP function. The scale image option scales the image to a fixed size #defined in the source code. This can also be modified so as to scale as per the user passed parameter. I have used only API functions so as to make the code light avoiding the MFC DLLs. The following is the step by step explanation of core logic of conversion.
- Create a window which is invisible, of any size
HWND hWnd = CreateWindow("#32770","NULL",~WS_VISIBLE,0,0,
100,100,NULL,NULL,NULL,0);
- Get the DC of the window
HDC dc = ::GetDC(hWnd);
- Get the handle to the emf file and get the EMF header
hemf = ::GetEnhMetaFile(strFileName);
ZeroMemory( &emh, sizeof(ENHMETAHEADER) );
emh.nSize = sizeof(ENHMETAHEADER);
if( GetEnhMetaFileHeader( hemf,
sizeof( ENHMETAHEADER ), &emh ) == 0 )
{
DeleteEnhMetaFile( hemf );
return FALSE;
}
- Get the width and height of the EMF
RECT rect;
float PixelsX, PixelsY, MMX, MMY;
float fAspectRatio;
long lWidth,lHeight;
PixelsX = (float)GetDeviceCaps( dc, HORZRES );
PixelsY = (float)GetDeviceCaps( dc, VERTRES );
MMX = (float)GetDeviceCaps( dc, HORZSIZE );
MMY = (float)GetDeviceCaps( dc, VERTSIZE );
rect.top = (int)((float)(emh.rclFrame.top) *
PixelsY / (MMY*100.0f));
rect.left = (int)((float)(emh.rclFrame.left) *
PixelsX / (MMX*100.0f));
rect.right = (int)((float)(emh.rclFrame.right) *
PixelsX / (MMX*100.0f));
rect.bottom = (int)((float)(emh.rclFrame.bottom) *
PixelsY / (MMY*100.0f));
lWidth = (long)((float)(abs(rect.left - rect.right)));
lHeight =(long)((float)(abs(rect.top-rect.bottom )));
- If the image needs to be scaled, modify the width and height as per the aspect ratio
fAspectRatio = (float)lWidth/(float)lHeight;
if(bScaleImage)
{
if(fAspectRatio > 1 )
{
lWidth = X_MINIATUREFRAME;
lHeight = (long)((float)Y_MINIATUREFRAME / fAspectRatio);
}
else
{
lHeight = Y_MINIATUREFRAME;
lWidth = (long)((float)X_MINIATUREFRAME * fAspectRatio);
}
}
- Create a Memory DC compatible to WindowDC
memDC=::CreateCompatibleDC(dc);
- Create a bitmap compatible to Window DC
bitmap = ::CreateCompatibleBitmap(dc,lWidth,lHeight);
- Select the bitmap into the Mem DC
::SelectObject(memDC,bitmap);
- Paint the background of the DC to White
SetBackColorToWhite(memDC);
- Now play the enhanced metafile into the memory DC; ignore its return value it may be false even if successful
PlayEnhMetaFile(memDC,hemf,&rect);
DWORD dwRet = GetLastError();
- Create logical palette if device support a palette
HPALETTE pal;
if( GetDeviceCaps(dc,RASTERCAPS) & RC_PALETTE )
{
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries =
GetSystemPaletteEntries( dc, 0, 255, pLP->palPalEntry );
pal = ::CreatePalette(pLP );
delete[] pLP;
}
- Convert the bitmap to a DIB (refer to the download for full source code)
HANDLE hDIB = DDBToDIB( bitmap, BI_RGB, pal );
- Write DIB to file (refer to the download for full source code)
WriteDIB((char*)strBMPFile, hDIB );
- Clean up. Destroy the window and return true
DeleteEnhMetaFile( hemf );
::DestroyWindow(hWnd);
Bitmap to EMFI have added a new functionality of converting the BMP to EMF. Following is the step by step process for converting a BMP file to EMF File. This code is based on the comment submitted by Gernot Frisch
- Load the bitmap from file to get the bitmap handle
hBmp = (HBITMAP*)::LoadImage(NULL,pszBMPFile,IMAGE_BITMAP,0,0,
LR_CREATEDIBSECTION|LR_LOADFROMFILE);
- Get the
BITMAP structure to get the bmp's height and width GetObject(hBmp, sizeof(BITMAP), &bm );
- Create MemDC
hdcMem =::CreateCompatibleDC(GetDC(NULL));
- Select the BMP into the DC
SelectObject(hdcMem, hBmp);
- Create EMF and get the emf DC
HDC emfdc = CreateEnhMetaFile(hdcMem, pszEMFFile, NULL,
"Created by Pravarakhya");
- Blit from BMF DC to EMF DC
BitBlt(emfdc,0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
- Close the EMF file
::CloseEnhMetaFile(emfdc);
Points of InterestConverting a vector format to raster format has a lot of advantages, one of them is that the image can be used over the web when it is converted to JPG or GIF. One more advantage is that the vector images can be scaled down without losing the quality. So any huge EMF can be brought down to a miniature thumbnail image which can be used over web. In our earlier project, we wanted to create a thumbnail of huge Visio Diagrams (of around 4000 sq inches!), when we saved the diagram as 100X100 pixels bitmap, we were losing quality and image was not acceptable. We then found this solution of saving the diagram as EMF and then scaling it down to 100X100 pixels bitmap. This miniature is as good as its bigger one without any loss of quality.
History
- 18 Oct 2003 - Version 1.0 Initial Release
- 24 Oct 2003 - Version 2.0
- Removed the Window Creation code (Thanks to Paolo Messina)
- Added the BMP to EMF functionality (Thanks to Gernot Frisch )
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 29 (Total in Forum: 29) (Refresh) | FirstPrevNext |
|
 |
|
|
Public Shared Sub Convert(ByVal FromSpec As String, ByVal IntoSpec As String) Dim Pic As New PictureBox: Pic.Image = System.Drawing.Image.FromFile(FromSpec,True) Pic.Image.Save(IntoSpec) End Sub
Note: If no encoder exists for the file format of the image, the Portable Network Graphics (PNG) encoder is used. When you use the Save method to save a graphic image as a Windows Metafile Format (WMF) or Enhanced Metafile Format (EMF) file, the resulting file is saved as a Portable Network Graphics (PNG) file. This behavior occurs because the GDI+ component of the .NET Framework does not have an encoder that you can use to save files as .wmf or .emf files.
Saving the image to the same file it was constructed from is not allowed and throws an exception.
Keith Alan Yerian
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Public Shared Sub Convert(ByVal FromSpec As String, ByVal IntoSpec As String, ByVal WidthInPixels As Integer) Dim Pic As New PictureBox: Pic.Image = System.Drawing.Image.FromFile(FromSpec,True) Dim HeightInPixels As Integer = cInt(Pic.Image.Height * WidthInPixels / Pic.Image.Width) Dim TargetBounds As New Rectangle(0,0,WidthInPixels,HeightInPixels) Dim Bitmap As New Bitmap(WidthInPixels,HeightInPixels) Pic.Width = WidthInPixels Pic.Height = HeightInPixels Pic.SizeMode = PictureBoxSizeMode.StretchImage Pic.DrawToBitmap(BitMap, TargetBounds) Bitmap.Save(IntoSpec) End Sub
Keith Alan Yerian
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I can't find an email address for you so I can't send you an email to say that I'm using this utility in a commercial application as the source code requests. So, I'll say thank you here and just mention that I'm using the code in an ActiveX control so that I can save an enhanced metafile that's on the clipboard to a bitmap file.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
sorry, the problem didn't depend on my dualmonitor configuration
neverthless I had to change the code, to get a valid "pal" variable:
ConvertEMFToBMP.cpp line 356 to 369 // if( GetDeviceCaps(dc,RASTERCAPS) & RC_PALETTE ) // { if body code ... // }
it seems to be needed, even if the EMF is mono colored.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I'm getting a problem with "not enough memory" ERROR_NOT_ENOUGH_MEMORY being returned for CreateCompatibleBitmap. Is there a work around? Can I limit the number of colours?
|
| Sign In·View Thread·PermaLink | 1.36/5 (6 votes) |
|
|
|
 |
|
|
I have developed a program for converting EMF to WMF format. But the converted file is not opening up in Centura Team Builder. Working fine with windows. Pls help.
|
| Sign In·View Thread·PermaLink | 1.33/5 (2 votes) |
|
|
|
 |
|
|
I think the emf files is smaller and more legible than bmp files,so I want to convert a bmp file to a emf file.But I did not get a more legible picture with emf format,and the file has a same length with the source file (bmp).Is somebody tell why?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
1. Emf files can only be as legible as their original bmp files. its the bmp information only that is converted to emf, so the legibility is same. 2. Emf is not a compressed file format, so you should not expect a less file size.
If you are looking for a more legible image with less file size you should go for image enhancement and compression algorithms which are actually image processing techiniques instead of looking for format conversion.
Hope I have answered your questions. Pravar
Pravar My Image Processing Article! Rate it!!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thank you very much for your answering my question.Now I know the point. Somebody told me that emf is a more legible format.But now I know it is wrong. But I suspose if I save the data in the screen to a emf file in the beginning as I saved to a bmp file,is it more legible? I will try.
Thank you.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I think the emf files is smaller and more legible than bmp files,so I want to convert a bmp file to a emf file.But I did not get a more legible picture with emf format,and the file has a same length with the source file (bmp).Is somebody tell why?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
If I have a metafile which is bigger then one page, and I want to programmatically resize it to fit into the page.... how do I do this (assuming I know the resulting page size or have some kind of %zoom in mind).
Thanks !
|
| Sign In·View Thread·PermaLink | 1.00/5 (2 votes) |
|
|
|
 |
|
|
a metafile is a vector image and can be played onto any size that you specify. since a metafile doesnt hold any size information there is no question of resizing a metafile. To answer your question, just use PlayEnhMetafile and specify your page size.
Pravar
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
 |
|
|
Is it possible to add some modification to BMP->EMF code, to get the conversion from BMP to WMF (placeble format)?
I would like to have a possibility to create a WMF file in similar manner as EMF file and/or copy the WMF to clipboard.
I have no sufficient GDI & C++ knowledge to do it myself. But I was able to adapt the Pravarakhya's idea into my CA-Visual Objects and I was very satisfied that I could transform C++ code into my language.
Thank you Pravarakhya for your valuable stuff.
Regards, Marek
|
| Sign In·View Thread·PermaLink | 3.50/5 (2 votes) |
|
|
|
 |
|
|
During some tests I found that after CloseEnhMetaFile(), the created EMF file is locked and can not be deleted. When I created another EMF file, then both file were locked, etc. The files could be unlocked and deleted only when the whole application is closed.
I found in WIN SDK the following information: ---------------- When the application no longer needs the enhanced metafile handle, it should release the handle by calling the DeleteEnhMetaFile function. ----------------
So I added DeleteEnhMetaFile() and now the file is not locked and can be deleted soon after creation.
I hope this information will be usefull,
Regards, Marek
|
| Sign In·View Thread·PermaLink | 4.00/5 (1 vote) |
|
|
|
 |
|
|
Hello,
I tried BMP->EMF converting and it works for W2K and XP.
I could not reach success in WIN98, only. I receive null pointer from CreateEnhMetaFile(). The GetLastErorr() gives the error code = 2. It means ERROR_FILE_NOT_FOUND.
I've noticed also a GDI memory leak in WIN98, which is caused probably with the above error.
I am not an expert in GDI or C++. So, I am unable to resolve it myself. I hope that somebody can help me.
Marek
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I have a problem when read EMF file to a image list control. It work good in Win2K/XP, but in Win98, it cause leak resource. It is because the PlayEnhMetaFile funtion but I can not find any replacement Can you help me Thank in advance 
Do Tuan Anh
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello,
I could create a transparent image from a edit box content and show it in a frame, but it exeeds to out of that frame while edit box content is too large. So i need to controll that bmp only in that frame. How i can show it inside that frame by propotionally change the height and width of that bmp.
If you have any idea or refference please maile me ranjithepost@yahoo.co.in
Thanks in advance Ranjith
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You can resize the bitmap with many of the image processing libraries like CxImage. Take care while you resize your bitmaps, since yours is a bitmap containing text, the text could be lost if you resize the image.
Thanks and Regards, Pravarakhya
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
bool MakeFromBMP(BITMAP* bmp) { HBITMAP handle; HDC hdcMem; hdcMem =::CreateCompatibleDC(GetDC(NULL)); handle = ::CreateBitmapIndirect(bmp); SelectObject(hdcMem, handle);
HDC emfdc = CreateEnhMetaFile(NULL, NULL, NULL, "EMF\0..\0\0");
BitBlt(emfdc, 0, 0, bmp->bmWidth, bmp->bmHeight, hdcMem, 0, 0, SRCCOPY); this->m_Meta = ::CloseEnhMetaFile(emfdc); return true; }
|
| Sign In·View Thread·PermaLink | 4.63/5 (5 votes) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|