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.
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",GENE RIC_READ|G ENERIC_WRI TE,0,0,OPE N_EXISTING ,0,NULL);
hFileMapping= CreateFileMapping( hFile,NULL,PAGE_READWRITE, 0,0,0 );
CString s;
GetLastErrorStr( s );
pBMFH= (BITMAPFILEHEADER*)MapView OfFile( 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,D IB_RGB_COL ORS, &pBits, hFileMapping, dwOffset );
if (hBmp == 0 ) {
MessageBox("CreateDIBSecti on 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 );
}
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",GENE
hFileMapping= CreateFileMapping( hFile,NULL,PAGE_READWRITE,
CString s;
GetLastErrorStr( s );
pBMFH= (BITMAPFILEHEADER*)MapView
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--
}
HDC dc= CreateCompatibleDC(NULL);
void* pBits= 0;
HBITMAP hBmp= CreateDIBSection(dc,pBMI,D
if (hBmp == 0 ) {
MessageBox("CreateDIBSecti
}
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;
//------------------------
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 );
}
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
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
ASKER
Okay, I think it's tough while interesting, it's worth a study :)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
>>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
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
I will take my words back. Sorry
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