Click here to Skip to main content
15,868,419 members
Articles / Desktop Programming / MFC
Article

Conversion of Enhanced Metafile to Bitmap and viceversa

Rate me:
Please Sign up or sign in to vote.
4.78/5 (45 votes)
23 Oct 2003CPOL4 min read 223.4K   9.1K   56   33
An article on conversion of EMF file to Bitmap file format and BMP to EMF

Sample Image - ConvertEMFToBMP.jpg

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;

//call the convert function
BOOL bRet = conv.ConvertEMFToBMP(m_strEMF,m_strBMP,m_chkScale);

ConvertEMFToBMP takes three parameters:

//    m_strEMF - path and file name of EMF file to be converted
//    m_strBMP - path and file name of BMP file 
//    m_chkScale - boolean. If this is false, EMF is converted to 
//            BMP in original size.
//            If this is true, the image is scaled to preset size 
//            in the code (explained below)

Example:

CConvertEMFToBMP conv;

//call the convert function
BOOL bRet = conv.ConvertEMFToBMP("D:\temp\Sample.emf",
        "D:\temp\sample.bmp",false);

To Convert a BMP to EMF:

CConvertEMFToBMP conv;
   //call the convert function
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;

//call the convert function
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.
  1. Create a window which is invisible, of any size
    //Create an invisible window
    HWND hWnd = CreateWindow("#32770","NULL",~WS_VISIBLE,0,0,
            100,100,NULL,NULL,NULL,0);
    
  2. Get the DC of the window
    //Get the DC of the Window
    HDC dc = ::GetDC(hWnd);
    
  3. Get the handle to the emf file and get the EMF header
    //Get the Handle from the enhanced metafile
    hemf = ::GetEnhMetaFile(strFileName);
    
    // Get the header from the enhanced metafile.
    ZeroMemory( &emh, sizeof(ENHMETAHEADER) );
    emh.nSize = sizeof(ENHMETAHEADER);
    if( GetEnhMetaFileHeader( hemf,
             sizeof( ENHMETAHEADER ), &emh ) == 0 )
    {
        DeleteEnhMetaFile( hemf );
        return FALSE;
    }
    
  4. Get the width and height of the EMF
    //Declare variables for calculation of metafile rect
    RECT    rect;
    float    PixelsX, PixelsY, MMX, MMY;
    
    float fAspectRatio;
    long lWidth,lHeight;
    
    // Get the characteristics of the output device.
    PixelsX = (float)GetDeviceCaps( dc, HORZRES );
    PixelsY = (float)GetDeviceCaps( dc, VERTRES );
    MMX = (float)GetDeviceCaps( dc, HORZSIZE );
    MMY = (float)GetDeviceCaps( dc, VERTSIZE );
    
    // Calculate the rect in which to draw the metafile based on the
    // intended size and the current output device resolution.
    // Remember that the intended size is given in 0.01 mm units, so
    // convert those to device units on the target device.
    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));
    
    //Calculate the Width and Height of the metafile
    lWidth = (long)((float)(abs(rect.left - rect.right)));
    lHeight =(long)((float)(abs(rect.top-rect.bottom )));
    
  5. 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 miniature option is ON, change
                  //the width and height accordingly
    {
        if(fAspectRatio > 1 ) //width is more than height
        {
            //Make width as constant and calculate Height
            lWidth = X_MINIATUREFRAME;
            lHeight = (long)((float)Y_MINIATUREFRAME / fAspectRatio);
    
        }
        else //width is less than height(or equal to height)
        {
            //Make Height as constant and calculate Width
            lHeight = Y_MINIATUREFRAME;
            lWidth = (long)((float)X_MINIATUREFRAME * fAspectRatio);
        }
    }
    
  6. Create a Memory DC compatible to WindowDC
    memDC=::CreateCompatibleDC(dc);
    
  7. Create a bitmap compatible to Window DC
    bitmap = ::CreateCompatibleBitmap(dc,lWidth,lHeight);
    
  8. Select the bitmap into the Mem DC
    ::SelectObject(memDC,bitmap);
    
  9. Paint the background of the DC to White
    SetBackColorToWhite(memDC);
    
  10. 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();
    
  11. 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 );
    
        // Create the palette
        pal = ::CreatePalette(pLP );
    
        delete[] pLP;
    }
    
  12. Convert the bitmap to a DIB (refer to the download for full source code)
    HANDLE hDIB = DDBToDIB( bitmap, BI_RGB, pal );
    
  13. Write DIB to file (refer to the download for full source code)
    WriteDIB((char*)strBMPFile, hDIB );
    
  14. Clean up. Destroy the window and return true
    DeleteEnhMetaFile( hemf );
    ::DestroyWindow(hWnd);
    

Bitmap to EMF

I 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
  1. Load the bitmap from file to get the bitmap handle
    hBmp = (HBITMAP*)::LoadImage(NULL,pszBMPFile,IMAGE_BITMAP,0,0,
            LR_CREATEDIBSECTION|LR_LOADFROMFILE);
    
  2. Get the BITMAP structure to get the bmp's height and width
    GetObject(hBmp, sizeof(BITMAP), &bm );
    
  3. Create MemDC
    hdcMem =::CreateCompatibleDC(GetDC(NULL));
    
  4. Select the BMP into the DC
    SelectObject(hdcMem, hBmp);
    
  5. Create EMF and get the emf DC
    HDC emfdc = CreateEnhMetaFile(hdcMem, pszEMFFile, NULL,
          "Created by Pravarakhya");
    
  6. Blit from BMF DC to EMF DC
    BitBlt(emfdc,0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
    
  7. Close the EMF file
    ::CloseEnhMetaFile(emfdc);
    

Points of Interest

Converting 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 )

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Pravarakhya is from Hyderabad,India and has completed 27 revolutions round the sun! His main interests include .net and MFC/VC++/COM programming. He is also interested in various design methodologies and agile methods.

Comments and Discussions

 
QuestionBrilliant but ... Pin
Michael B Pliam17-Apr-15 8:10
Michael B Pliam17-Apr-15 8:10 
QuestionRegarding porting this code to Android Pin
sunneversets5-Nov-11 1:50
sunneversets5-Nov-11 1:50 
Generaldevice doesn't support a palette Pin
deb200529-Nov-10 7:11
deb200529-Nov-10 7:11 
GeneralThe following code will convert from all formats (including emf) to anything except emf and wmf. Pin
Keith Yerian25-May-08 4:00
Keith Yerian25-May-08 4:00 
GeneralRe: Also - if you wish to resize during the conversion.... Pin
Keith Yerian25-May-08 4:06
Keith Yerian25-May-08 4:06 
AnswerThe perfect solution for .NET programmers EMF -> BMP Pin
Elmue9-Jun-17 8:52
Elmue9-Jun-17 8:52 
GeneralIn lieu of email... Pin
Hal Berman7-Dec-07 10:09
Hal Berman7-Dec-07 10:09 
GeneralConvertEMFtoBMP fails on Windows XP with mono colored EMF Pin
26-Jun-05 8:08
suss26-Jun-05 8:08 
Generalthe diagnosis was to fast and wrong Pin
Member 181767126-Jun-05 8:36
Member 181767126-Jun-05 8:36 
GeneralRe: the diagnosis was to fast and wrong Pin
Pravarakhya26-Jun-05 9:25
Pravarakhya26-Jun-05 9:25 
General bitmap = :: CreateCompatibleBitmap(dc,lWidth,lHeight); Pin
Ziggy Short21-Feb-05 5:55
Ziggy Short21-Feb-05 5:55 
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?
GeneralEMF to WMF conversion Pin
Sanjay Saini14-Feb-05 7:02
Sanjay Saini14-Feb-05 7:02 
Generalwhy the picture I converted from bmp is not more legible Pin
tongji_200227-Sep-04 0:58
tongji_200227-Sep-04 0:58 
GeneralRe: why the picture I converted from bmp is not more legible Pin
Pravarakhya28-Sep-04 11:18
Pravarakhya28-Sep-04 11:18 
GeneralRe: why the picture I converted from bmp is not more legible Pin
tongji_200228-Sep-04 16:19
tongji_200228-Sep-04 16:19 
QuestionI confuse why the picture I converted from bmp is not more legible? Pin
tongji_200227-Sep-04 0:56
tongji_200227-Sep-04 0:56 
GeneralResize a metafile Pin
Doron Ben-Ari9-Sep-04 8:48
Doron Ben-Ari9-Sep-04 8:48 
GeneralRe: Resize a metafile Pin
Pravarakhya10-Sep-04 1:38
Pravarakhya10-Sep-04 1:38 
Generalbmp to dxf file Pin
Tapas Mondal17-Aug-04 19:57
Tapas Mondal17-Aug-04 19:57 
GeneralRe: bmp to dxf file Pin
Pravarakhya19-Aug-04 6:29
Pravarakhya19-Aug-04 6:29 
GeneralPlease Rate my Article Pin
Pravarakhya4-May-04 4:36
Pravarakhya4-May-04 4:36 
QuestionBMP->WMF is it possible ? Pin
SP6NIN30-Apr-04 2:05
SP6NIN30-Apr-04 2:05 
GeneralBMP->EMF Locked EMF, DeleteEnhMetaFile Pin
SP6NIN30-Apr-04 1:56
SP6NIN30-Apr-04 1:56 
GeneralWIN98, BMP->EMF, error 2 in CreateEnhMetaFile Pin
SP6NIN29-Apr-04 23:41
SP6NIN29-Apr-04 23:41 
GeneralLeak resource in win98 Pin
anhsl17-Mar-04 14:38
anhsl17-Mar-04 14:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.