To display a huge image... how to do it?

Posted on 2002-06-16
Last Modified: 2013-11-20
I want to display a huge image (usually over 1G), I cannot load it to memory because of its huge size. The only way is to display a portion of the image, then pan it. Do you have any idea about how to to make it run well? Can I use "FileMapping"? Thanks a lot for your opinion, I appreciate it.
Question by:VCFan
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
LVL 49

Expert Comment

ID: 7083124
Yes, it appears that you can use FileMapping.  It  involves using CreateFileMapping and MapViewOfFile and there is a trick having to do with forcing the dibsection data to be aligned on a DWORD boundary.  

Alas, I can't find a pat answer for you.  Perhaps someone else can locate some sample code.  If you up the points, I'll take a whack at it.

-- Dan

Author Comment

ID: 7083159
Sure, I am waiting for your further help. :)
LVL 49

Expert Comment

ID: 7084493
OK Here's a FIRST DRAFT -- it is for testing purposes ONLY:

THere is a big problem that I'm not certain how to attack:  The image area (the bits) do not normally end up on a DWORD-aligned boundary -- and that is a requirement for using the CreateDIBSection API which seems to be the logical way to attack this problem.

As a proof-of-concept, I just added an offset so that the bits are aligned (I had to make the images shorter to avoid a related error).  The result is that I can access the data, but it is color-shifted (RGB RGB RGB is interpetted as GBR GBR GBR).  

Note: I woked on a 2MB file (the largest I could find!) and the girl looks like one of those Intel 'bluemen' lol.

This code shows how to do the file mapping and so forth and actually displays a specified portion of a large bitmap.  I'd like you to try it and single-step through the code. and examine all variables ate each step.  Perhaps you can see something different.

Do you have access to the program that creates these whopping GB+ files?  Is there anything on on earth that can read them?  If you have access to the program, you could add a couple of filler bytes ate one place in the file and the work would be done.

Otherwise, I'll need to either shift the entire file forward by 2 bytes (probably not feasible) or do manual operations of copying subsets of the data into a temporary buffer.  That much coding will take me hours...


void GetLastErrorStr( CString& sDest );
HBITMAP GetImgSubSet( HBITMAP hbmSrc, RECT* prcSrc, BITMAPINFO* pBMI, void* pBits ) ;

void CD06Dlg::OnButton1()
      HANDLE            hFile;
      HANDLE            hFileMapping;
      BITMAPINFO*       pBMI;    // bfOffBits is not divisible by 4.

      hFile=        CreateFile( "C:\\temp\\large.bmp",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,NULL);
      hFileMapping= CreateFileMapping( hFile,NULL,PAGE_READWRITE,0,0,0 );

      CString s;
      GetLastErrorStr( s );

      pBMFH= (BITMAPFILEHEADER*)MapViewOfFile( hFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);  // entire file
      pBMI=  (BITMAPINFO*)     (pBMFH+1);

      GetLastErrorStr( s );

      DWORD dwOffset= pBMFH->bfOffBits;

      if ( (dwOffset & 3 ) != 0 ) {
            MessageBox("Problem mapping: bit data not dword-aligned!" );
            int nAdjust= dwOffset % 4;  // usually 2
            dwOffset += nAdjust;
            pBMI->bmiHeader.biHeight--; // discared last scanline for this test

      HDC dc= CreateCompatibleDC(NULL);

      void* pBits=    0;

      HBITMAP hBmp= CreateDIBSection(dc,pBMI,DIB_RGB_COLORS, &pBits, hFileMapping, dwOffset );
      if (hBmp == 0 ) {
            MessageBox("CreateDIBSection failed!" );
      GetLastErrorStr( s );  // useless

      int nWidth= pBMIH->biWidth;
      int nHigh=  pBMIH->biHeight;

      RECT rc= {100,100,400,400 };
      static HBITMAP hBmpNew= GetImgSubSet( hBmp, &rc, pBMI, pBits) ;

      m_ctlBmpShow.SetBitmap( hBmpNew );

      CloseHandle( hFile ); // or just exit the testing program

HBITMAP GetImgSubSet( HBITMAP hbmSrc, RECT* prcSrc, BITMAPINFO* zpBMI, void* pBits )
      HWND hWnd= AfxGetMainWnd()->m_hWnd;
      int nHigh= prcSrc->bottom - prcSrc->top;
      int nWide= prcSrc->right  - prcSrc->left;

      //---------------------------- create the destination bitmap
      HDC hDCMem= ::CreateCompatibleDC( NULL );
      HBITMAP hBmp= NULL;
      HDC hDC= ::GetDC( hWnd );
      hBmp= CreateCompatibleBitmap( hDC, nWide, nHigh );
      ::ReleaseDC( hWnd, hDC );

      HGDIOBJ hOldBmp= SelectObject( hDCMem, hBmp );

      BITMAP rBmp;
      GetObject( hbmSrc, sizeof(BITMAP), &rBmp );

      GetObject( hbmSrc, sizeof(DIBSECTION), &rDS );

      int nScansCopied=
            StretchDIBits( hDCMem,
            0,0,                       // dest location
            nWide, nHigh,              // dest size
            prcSrc->left, prcSrc->top, // src Location
            nWide, nHigh,              // src size

      ::SelectObject( hDCMem, hOldBmp );
      ::DeleteObject( hDCMem );

      return( hBmp );
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Author Comment

ID: 7084858
Hello Dan, thanks a lot for your help. I tried your code, some of which is ingenious, but it failed at "MapViewOfFile" cuz I used a whopping image file (over 900M) which made it memory insufficient. How could I get it over?
LVL 49

Expert Comment

ID: 7085427
On second thought, this may not work.  I can't find a single reference about how to handle this.

How are most of these bitmaps laid out?  Very wide and not too tall?   Is there someplace I could download one for testing?

If the monster BMP file is certain to be a DIB with standard 24-bit color, it is possible to just open the file and read in carefully-selected chunks of it to form a DIBSection in RAM.  From that, I could extract a specified rectangle and return an HBITMAP of it.

If you bump the points again, I'll take a crack at that.

-- Dan

Author Comment

ID: 7085957
Okay, I think it's tough while interesting, it's worth a study :)
LVL 49

Accepted Solution

DanRollins earned 300 total points
ID: 7094930
This version processes the image data by seeking around in the file -- it never tries to load the entire file at once.

You can make this a lot faster in several ways:

1) No need to create a new DIBSection each time.  Just create it once and pass it into the (modified) GetImgSubset() fn.

2) Create a larger 'cache' DIB (say 2000x1000) then pan around in that (use BitBlit orStretchDiBits to copy part of it to the screen) until you get near the edge, then read the file for another chunk.

3) When the viewer has panned to the edge, there is no need to re-read the whole cache image.  For instance, when the user is near the right side of the 'cache' move the image data to the right and fill in the 'hole' with data from the file.  As the user keeps moving, new data is there for viewing.

4) Updating the cache DIB could be done in a worker thread.  You could keep track of how close the user is coming to the edge and be ready with a new cach DIB when it is needed (so the user does not need to wait).

HBITMAP GetImgSubset( CFile& cfBmp, CRect& rc )
                      //  only needs to be sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFO)
     BYTE buf[1000];  //  but handy for eyeball check
     cfBmp.Seek(0, CFile::begin);
     cfBmp.Read(buf, 1000); // Read header info TBD: check error

     BITMAPINFO*       pBMI=  (BITMAPINFO*)     (pBMFH+1);    

     DWORD nBitsFileOffset= pBMFH->bfOffBits;  // first RGB (x,y)=(0,0) is here

     int nSrcWide= pBMI->bmiHeader.biWidth;
     int nSrcHigh= pBMI->bmiHeader.biHeight;

     int nSrcBytesPerLine= ((nSrcWide * 3)+3) & 0xfffffffc;  // divible by 4

     int nDstWide= rc.Width();
     int nDstHigh= rc.Height();

     pBMI->bmiHeader.biHeight= -nDstHigh;  // fixes upside-down-ness
     pBMI->bmiHeader.biWidth=  nDstWide;

     //---------------------------------- create the destination bitmap
     void* pBits=    0;
     HWND    hWnd=   AfxGetMainWnd()->m_hWnd;
     HDC     hDC=    ::GetDC( hWnd );
     HBITMAP hbmRet= CreateDIBSection( hDC, pBMI,DIB_RGB_COLORS, &pBits, 0,0 );
     ::ReleaseDC( hWnd, hDC );

     if ( hbmRet == 0 ) {
          AfxMessageBox("CreateDIBSection failed!" );
     GetObject( hbmRet, sizeof(DIBSECTION), &rDS );
     int nDstBytesPerLine= rDS.dsBm.bmWidthBytes;

     BYTE* pDstBits= (BYTE*)pBits;
     for (int y=; y<rc.bottom; y++ ) {
          int j= (nSrcHigh-1) - y;   // fixes upside-down-ness
          int nFileOffset= nBitsFileOffset + (j*nSrcBytesPerLine);

          nFileOffset += rc.left * 3;

          cfBmp.Seek( nFileOffset, CFile::begin);
          cfBmp.Read( pDstBits, nDstBytesPerLine );
          pDstBits += nDstBytesPerLine;
     return( hbmRet );

CRect   m_rc;
CFile   m_cfBmp;

void CBigBmpDlg::OnButton1()
     m_cfBmp.Open( "C:\\temp\\large.bmp", CFile::modeRead );
     m_rc= CRect(0,0, 500,500 );
     m_hBmp= GetImgSubset( m_cfBmp, m_rc );
     m_ctlBmpShow.SetBitmap( m_hBmp );

void CBigBmpDlg::OnRight()

     m_hBmp= GetImgSubset( m_cfBmp, m_rc );
     m_ctlBmpShow.SetBitmap( m_hBmp );

void CBigBmpDlg::OnDown()

     m_hBmp= GetImgSubset( m_cfBmp, m_rc );
     m_ctlBmpShow.SetBitmap( m_hBmp );

Author Comment

ID: 7098998
Dan, thank you for your hard working, I appreciate it. I think your answer meet my requirement basically, I will improve it by myself. Thanks. Chances are I will have more questions in the future, please give me your Email address in order to let you know that I have new questions about a display of big image. :) Thanks again!
LVL 49

Expert Comment

ID: 7099248
I worked many hours to help you for free.  I solved a problem that no other expert would touch.  A problem that is considered impossible to solve.  Then you give me a B!
>>please give me your Email address in order to let you know that I have new questions

This has made me laugh quite hard.  My side hurts.

-- Dan

Author Comment

ID: 7099697
I am so sorry, Dan. I don't know much of this website and I must give you an "A" if I can choose again.

I will take my words back. Sorry

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video Micro Tutorial shows how to password-protect PDF files with free software. Many software products can do this, such as Adobe Acrobat (but not Adobe Reader), Nuance PaperPort, and Nuance Power PDF, but they are not free products. This vide…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question