Link to home
Start Free TrialLog in
Avatar of VCFan
VCFan

asked on

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

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.
Avatar of DanRollins
DanRollins
Flag of United States of America image

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
Avatar of VCFan
VCFan

ASKER

Sure, I am waiting for your further help. :)
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;
      BITMAPFILEHEADER* pBMFH;
      BITMAPINFO*       pBMI;    // bfOffBits is not divisible by 4.
      BITMAPINFOHEADER* pBMIH;

      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

      pBMIH= (BITMAPINFOHEADER*)pBMI;
      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 );

      DeleteDC(dc);
      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 );

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


      BITMAPINFO* pBMI= (BITMAPINFO*)&rDS.dsBmih;
      
      int nScansCopied=
            StretchDIBits( hDCMem,
            0,0,                       // dest location
            nWide, nHigh,              // dest size
            prcSrc->left, prcSrc->top, // src Location
            nWide, nHigh,              // src size
            pBits,
            pBMI,
            DIB_RGB_COLORS,
            SRCCOPY
      );

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

      return( hBmp );
}
Avatar of VCFan

ASKER

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?
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
Avatar of VCFan

ASKER

Okay, I think it's tough while interesting, it's worth a study :)
ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of VCFan

ASKER

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!
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
Avatar of VCFan

ASKER

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