Fast way to display large images
Hi gurus!!
I am working with a large images (280 Mb aprox) in BMP format.
I can print a image on DC using StretchDIBits and it works fine.
I want to save in a buffer the content of the DC (after the image was printed) because if part of the dialog is invalidate (down or move the dialog) I can print again in small time.
What is the best way?
Thanks in advance!!!
Re: Fast way to display large images
Hi!
Perhaps the ask is not very clear...
Step 1.- Read BMP file:
IN .H FILE:
Code:
class CTrasformaDlg : public CDialog
{
// Construcción
public:
CTrasformaDlg(CWnd* pParent = NULL); // Constructor estándar
// Datos del cuadro de diálogo
enum { IDD = IDD_TRASFORMA_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // Compatibilidad con DDX/DDV
// Implementación
protected:
HICON m_hIcon;
// Funciones de asignación de mensajes generadas
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnDestroy();
afx_msg void OnBnClickedButtonLoadbmp();
CString szBmpFile;
CString szEcwFile;
HWND hndWnd;
// BMP Completo
BYTE *pBits;
BITMAPINFOHEADER infoHeader;
int nBitsPixel, nHeight, nPlanos, nWidth, nImgSize;
CRect rBmp;
HDC hDC;
};
IN .CPP FILE:
Code:
void CTrasformaDlg::OnBnClickedButtonLoadbmp()
{
// TODO: Agregue aquÃ* su código de controlador de notificación de control
CFileDialog fDlg(TRUE, _T("*.bmp"), 0, 4|2, _T("Ficheros BMP (*.bmp)|*.bmp||"), this);
fDlg.DoModal();
szBmpFile = fDlg.GetPathName();
if(szBmpFile == "") return;
char sNombre[500];
WideCharToMultiByte(CP_ACP, NULL, szBmpFile, -1, sNombre, 500, NULL, NULL);
FILE *pf = fopen(sNombre, "rb");
nWidth = 0;
nHeight = 0;
nBitsPixel = 0;
nPlanos = 0;
int nOffsetImg = 0;
nImgSize = 0;
fseek(pf, 10L, SEEK_SET);
fread(&nOffsetImg, 4, 1, pf);
fseek(pf, 34L, SEEK_SET);
fread(&nImgSize, 4, 1, pf);
fseek(pf, 18L, SEEK_SET);
fread(&nWidth, 4, 1, pf);
fseek(pf, 22L, SEEK_SET);
fread(&nHeight, 4, 1, pf);
fseek(pf, 26L, SEEK_SET);
fread(&nPlanos, 2, 1, pf);
fseek(pf, 28L, SEEK_SET);
fread(&nBitsPixel, 2, 1, pf);
pBits = (BYTE *) malloc(nImgSize);
memset(pBits, 0, nImgSize);
fseek(pf, nOffsetImg, SEEK_SET);
fread(pBits, nImgSize, 1, pf);
fclose(pf);
hndWnd = ::GetDlgItem(this->GetSafeHwnd(), IDC_STATIC_IMG);
::GetClientRect(hndWnd, &rBmp);
memset(&infoHeader, 0, sizeof(BITMAPINFOHEADER));
infoHeader.biBitCount = nBitsPixel;
infoHeader.biCompression = BI_RGB;
infoHeader.biHeight = nHeight;
infoHeader.biPlanes = nPlanos;
infoHeader.biWidth = nWidth;
infoHeader.biSize = sizeof(BITMAPINFOHEADER);
infoHeader.biSizeImage = nImgSize;
OnPaint();
}
void CTrasformaDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // Contexto de dispositivo para dibujo
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Centrar icono en el rectángulo de cliente
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Dibujar el icono
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
Dibuja();
}
Step 2.- Print the image into DC:
Code:
void CTrasformaDlg::Dibuja(void) {
hDC = ::GetDC(hndWnd);
BITMAPINFO bInfo;
memset(&bInfo, 0, sizeof(BITMAPINFO));
bInfo.bmiHeader = infoHeader;
::SetStretchBltMode(hDC, HALFTONE);
int nLines = ::StretchDIBits(
hDC,
0,
0,
rBmp.Width(),
rBmp.Height(),
0,
0,
rBmp.Width(),
rBmp.Height(),
(void **)pBits,
&bInfo,
DIB_RGB_COLORS,SRCCOPY);
::DeleteDC(hDC);
}
....
Now I have the image loaded in memory and printed in the window. I want to save the printed image in a buffer like a primary image was saved.
It is quite clear?:confused::confused:
Thanks!!
Re: Fast way to display large images
You have already done half of the work I think. Something like this will do the trick.
Code:
CDC pDC = GetDC();
CRect Rect;
GetWindowRect(&Rect);
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap m_Bitmap;
m_Bitmap.CreateCompatibleBitmap(pDC,Rect.Width(),Rect.Height());
CBitmap *pOldBmp = MemDC.SelectObject(&m_Bitmap);
MemDC.BitBlt(0,0,Rect.Width(),Rect.Height(),pDC,Rect.left,Rect.top,SRCCOPY);
MemDC.SelectObject(pOldBmp);
now m_Bitmap holds the image of the pDC.
BITMAP myBitmap;
m_Bitmap.GetBitmap(&myBitmap);
myBitmap holds the image structure. and you're done.
Re: Fast way to display large images
That's a really huge image. Odds are, you don't need to see the whole thing at once, or if you do, you'll be zoomed out.
This suggests that mipmapping the image and/or breaking it up into tiles may allow you to redraw it more quickly.