紧急求援--BMP图像显示问题

faquirhu 2002-12-04 08:13:38
我是VC++初学者,现正在写一个程序,要求将一个BMP格式的图像文件显示出来,只知道文件路径,不能用MFC,也不能用LoadIamge函数,一句话,就是要涉及对图像文件内部数据的处理,还望各位大虾多多指教!!!!
...全文
30 点赞 收藏 14
写回复
14 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
duwenyong 2002-12-16
BOOL CTestsdiView::ShowBmp(HDC hdc, char *strFileName, int xDst, int yDst, int dxDst, int dyDst)
{
FILE *fp;
BITMAPFILEHEADER bf;
LPBITMAPINFOHEADER lpbi;
DWORD dwImgSize;
int w,h;

if((fp=fopen(strFileName,"rb"))==NULL)
{
AfxMessageBox("File open error");
return FALSE;
}
fread(&bf,1,14,fp);
dwImgSize=bf.bfSize-14;
lpbi=(LPBITMAPINFOHEADER)malloc(dwImgSize);
fread(lpbi,1,dwImgSize,fp);
fclose(fp);
lpbi->biCompression=0;

w=dxDst;
h=dyDst;
if(lpbi->biWidth<dxDst) w=lpbi->biWidth;
if(lpbi->biHeight<dxDst) h=lpbi->biHeight;
HDRAWDIB hdd;
hdd=DrawDibOpen();
if(hdd==NULL)
return FALSE;
if(!DrawDibDraw(hdd,hdc,0,0,w,h,lpbi,NULL,0,0,lpbi->biWidth,lpbi->biHeight,NULL))
{
AfxMessageBox("DrawDibDraw error");
DrawDibClose(hdd);
return FALSE;
}
DrawDibClose(hdd);
return TRUE;
}
example:
/* HDC hdc=::GetDC(GetSafeHwnd());
ShowBmp(hdc,"f:\\test1.bmp",0,0,384/3,288/3);
::ReleaseDC(GetSafeHwnd(),hdc);
*/
回复
faquirhu 2002-12-10
非常感谢大家的参与与解答,尤其是“分儿,我来了”、“半尾鱼”和“BlueNights",请你们告诉我怎样结贴,给你们加分,我将尽快给你们送分,实际这个问题我上星期就已经解决了,只是不知道怎样结贴,我自定义了两个函数LoadBMP和DrawDIB ,代码在下面,我现在又遇到了新难题,要在一个窗体中同时显示多副图像,且还不是一次打开的,一次只能打开一个,最后将所有图像以256像素或其他格式保存到一个文件。我觉得保存应该不难,关键是把多个不一块打开且数目不确定的文件同时显示,我至今没有什么好办法,我可以在不同的位置显示图像,但每当显示下一个图像时,前一个将消失,一次只能显示一个,尽管不会出现位置重复,我将在提交一个问题,还望诸位大虾参与,并多多指教!



HGLOBAL CBitMapOpView::LoadBMP( CPalette *pPal )
{

HANDLE hFile;
int n;
n=Bmpname.Replace("\\", "\\\\");


// Open the existing file.

hFile = CreateFile( Bmpname, // open the BitMap file
GENERIC_READ,
0, // not share
NULL, // no security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template

//fail to open file
if (hFile == INVALID_HANDLE_VALUE)
{
return NULL;
}

BITMAPFILEHEADER bmfHeader;
DWORD nFileLen,dwBytesRead;
nFileLen = GetFileSize (hFile, NULL) ; //get the length of the file


// Read file header
if(!ReadFile(hFile, (LPSTR)&bmfHeader, sizeof(bmfHeader), &dwBytesRead, NULL) ||
dwBytesRead != sizeof(bmfHeader))
return NULL;


// File type should be 'BM'
if (bmfHeader.bfType != ((WORD) ('M' << 8) | 'B'))
return NULL;

HGLOBAL hDIB = ::GlobalAlloc(GMEM_FIXED, nFileLen);
if (hDIB == 0)
return NULL;

// Read the remainder of the bitmap file.
if(!ReadFile(hFile, (LPSTR)hDIB, nFileLen - sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL) ||
dwBytesRead != nFileLen - sizeof(BITMAPFILEHEADER))
{
::GlobalFree(hDIB);
return NULL;
}



BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;

//nColors is the factual color num
int nColors = bmInfo.bmiHeader.biClrUsed ?
bmInfo.bmiHeader.biClrUsed : 1 << bmInfo.bmiHeader.biBitCount;


// Create the palette

UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];

pLP->palVersion = 0x300; //version number
pLP->palNumEntries = nColors;

//create color matrix
for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed;
pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen;
pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}

pPal->CreatePalette( pLP );
delete[] pLP;
CloseHandle(hFile);// Close the files.
return hDIB;
}

bool CBitMapOpView::DrawDIB( CDC* pDC, HGLOBAL hDIB, CPalette *pPal )
{
LPVOID lpDIBBits; // Pointer to DIB bits
bool bsuccess = false;

//Check hDIB,if hDIB is null,exit the function
if(hDIB == NULL)
return bsuccess;

BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB ;

//nColors is the factual color num
int nColors = bmInfo.bmiHeader.biClrUsed ?
bmInfo.bmiHeader.biClrUsed : 1 << bmInfo.bmiHeader.biBitCount;

//16 bit or 24 bit or 32 bit clearly color
if( bmInfo.bmiHeader.biBitCount > 8 )
lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
bmInfo.bmiHeader.biClrUsed) +
((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));

//Other color
else
lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);

// select the palette into a device context and realize it
if( pPal && (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) )
{
pDC->SelectPalette(pPal, FALSE);
pDC->RealizePalette();
}

//draw bmp
::SetDIBitsToDevice(pDC->m_hDC, // hDC
0, // DestX
0, // DestY
bmInfo.bmiHeader.biWidth, // nDestWidth
bmInfo.bmiHeader.biHeight, // nDestHeight
0, // SrcX
0, // SrcY
0, // nStartScan
bmInfo.bmiHeader.biHeight, // nNumScans
lpDIBBits, // lpBits
(LPBITMAPINFO)hDIB, // lpBitsInfo
DIB_RGB_COLORS); // wUsage

bsuccess = true;
return bsuccess;

}
回复
BlueNights 2002-12-10
我正在做的作业也是这个,也许可以交流一下:
1.你说要使用BMP文件,说明是用设备无关的DIB位图。MFC中是不提供DIB类的,
所以若要进行DIB位图的处理,最好是自己定义一个DIB类。
2.如果只是显示的话,不定义DIB类当然也没关系。
这时需要做以下件事:

1)在程序文档类中加入:
一个公有数据成员:
HANDLE m_hDIB;
说明:指向DIB数据块的内存句柄
重载以下函数:
BOOL CMyDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if(!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
m_hDIB=LoadDIB(lpszPathName);
if(m_hDIB==NULL)
{
return FALSE;
}
SetPathName(lpszPathName);
SetModifiedFlag(FALSE);
return TRUE;
}
CMyDoc是你的程序中自动生成的DOC类
上面调用的LoadDIB函数需要自己编写
HANDLE CMyDoc::LoadDIB(LPTSTR lpFileName)
参数lpFileName---指向文件名字符串的指针
返回值HANDLE---指向DIB数据缓冲区的句柄
说明:将指定的DIB文件读入内存
这个函数的代码可以参考楼上的DibFileLoad()
他返回的HDIB应该就是一个HANDlE吧
这样就完成了文件的载入。
2)在程序视图类类中加入:
一个数据成员:
CRECT m_rectDIB;
说明:用来存储位图的位置,尺寸信息
重载以下函数:

void CMyScrollView::OnInitialUpdate()
{
CScrollView::OnInitialUpDate();
CMyDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
CSize sizeTotal;
if(pDoc->m_hDIB!=NULL)
{
LPBITMAPINFOHEADER lpDIB=
(LPBITMAPINFOHEADER)GlobalLock(pDoc->m_hDIB);
m_rectDIB.left=0;
m_rectDIB.top=0;
sizeTotal.cx=m_rectDIB.right=
((LPBITMAPINFOHEADER)lpDIB)->biwidth;
sizeTotal.cy=m_rectDIB.bottom=
((LPBITMAPINFOHEADER)lpDIB)->biHeight;
GlobalUnlock(pDoc->m_hDIB);
}
else
{
m_rectDIB.SetRectEmpty();
sizeTotal.cx=sizeTotal.cy=100;
}
SetScrollSizes(MM_TEXT,sizeTotal);
}
说明:1这里使用CScrollView类而不是CView类是为了满足大图片的要求
2因为OninitialUpdate函数会在文件装入后自动被调用,所以可在
这儿进行一些预处理

void CMyScrollView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(pDoc->m_hDIB==NULL)
return;
PaintDIB(pDC->GetSafeHdc(),m_rectDIB,pDoc->m_hDIB,m_rectDIB,
NULL,SRCCOPY);
说明:
PaintDIB需自己编写,定义如下:
BOOL CMyScrollView::PaintDIB(HDC hDC,LPRECT lpDCRect,HANDLE hDIB,
LPRECT lpDIBRect,HPALETTE hPal,DWORD dwRop)
参数:
hDC---显示DIB的设备上下文句柄
lpDCRect---设备中显示DIB的矩形区域
dDIB---存储DIB数据缓冲区的内存块句柄
lpDIBRect---要显示的DIB矩形区域
hPal---用以显示DIB的调色板句柄
dwRop---显示DIB的ROP模式
具体可参考楼上的DisplayDib()函数
这样就可以完成图形显示

但还有一个问题:
就是我们还没对调色板进行处理,所以显示的图像不一定符合要求。
(系统调色板只有20色)调色板的问题下次再交流吧。

3.如果你有什么好的资料和原码,希望也可以提供给我。谢谢。
最后推荐你一本书---周长发的<<visual c++.net图像处理编程>>
上边有不少图形处理算法。

回复
aprilofeyes 2002-12-08
还有一部分没给你,下面一并贴出来

case WM_USER_CREATEPAL://SendMessage (hwnd,WM_USER_CREATEPAL, TRUE, 0) ;

if (hdib)
{
hdc = GetDC (hwnd) ;

if (!(RC_PALETTE & GetDeviceCaps (hdc, RASTERCAPS)))
{
PaletteMenu (hMenu, IDM_PAL_NONE) ;
}
else if (hPalette = DibPalDibTable (hdib))
{
PaletteMenu (hMenu, IDM_PAL_DIBTABLE) ;
}
else if (hPalette = CreateHalftonePalette (hdc))
{
fHalftonePalette = TRUE ;
PaletteMenu (hMenu, IDM_PAL_HALFTONE) ;
}
ReleaseDC (hwnd, hdc) ;

if ((BOOL) wParam)
hBitmap = DibCopyToDdb (hdib, hwnd, hPalette) ;
}
return 0 ;

case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;

if (hPalette)
{
SelectPalette (hdc, hPalette, FALSE) ;
RealizePalette (hdc) ;
}
if (hBitmap)
{
DisplayDib (hdc,
fHalftonePalette ? DibBitmapHandle (hdib) : hBitmap,
iHscroll, iVscroll,
cxClient, cyClient,
wShow, fHalftonePalette) ;
}
EndPaint (hwnd, &ps) ;
return 0 ;

case WM_QUERYNEWPALETTE:
if (!hPalette)
return FALSE ;

hdc = GetDC (hwnd) ;
SelectPalette (hdc, hPalette, FALSE) ;
RealizePalette (hdc) ;
InvalidateRect (hwnd, NULL, TRUE) ;

ReleaseDC (hwnd, hdc) ;
return TRUE ;

case WM_PALETTECHANGED:
if (!hPalette || (HWND) wParam == hwnd)
break ;

hdc = GetDC (hwnd) ;
SelectPalette (hdc, hPalette, FALSE) ;
RealizePalette (hdc) ;
UpdateColors (hdc) ;

ReleaseDC (hwnd, hdc) ;
break ;

case WM_DESTROY:
if (hdib)
DibDelete (hdib) ;

if (hBitmap)
DeleteObject (hBitmap) ;

if (hPalette)
DeleteObject (hPalette) ;

PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

int DisplayDib (HDC hdc, HBITMAP hBitmap, int x, int y,
int cxClient, int cyClient,
WORD wShow, BOOL fHalftonePalette)
{
BITMAP bitmap ;
HDC hdcMem ;
int cxBitmap, cyBitmap, iReturn ;

GetObject (hBitmap, sizeof (BITMAP), &bitmap) ;
cxBitmap = bitmap.bmWidth ;
cyBitmap = bitmap.bmHeight ;

SaveDC (hdc) ;

if (fHalftonePalette)
SetStretchBltMode (hdc, HALFTONE) ;
else
SetStretchBltMode (hdc, COLORONCOLOR) ;

hdcMem = CreateCompatibleDC (hdc) ;
SelectObject (hdcMem, hBitmap) ;

switch (wShow)
{
case IDM_SHOW_NORMAL:
if (fHalftonePalette)
iReturn = StretchBlt (hdc, 0, 0,
min (cxClient, cxBitmap - x),
min (cyClient, cyBitmap - y),
hdcMem, x, y,
min (cxClient, cxBitmap - x),
min (cyClient, cyBitmap - y),
SRCCOPY);
else
iReturn = BitBlt (hdc, 0, 0,
min (cxClient, cxBitmap - x),
min (cyClient, cyBitmap - y),
hdcMem, x, y, SRCCOPY) ;
break ;

case IDM_SHOW_CENTER:
if (fHalftonePalette)
iReturn = StretchBlt (hdc, (cxClient - cxBitmap) / 2,
(cyClient - cyBitmap) / 2,
cxBitmap, cyBitmap,
hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY);
else
iReturn = BitBlt (hdc, (cxClient - cxBitmap) / 2,
(cyClient - cyBitmap) / 2,
cxBitmap, cyBitmap,
hdcMem, 0, 0, SRCCOPY) ;
break ;

case IDM_SHOW_STRETCH:
iReturn = StretchBlt (hdc, 0, 0, cxClient, cyClient,
hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY) ;
break ;

case IDM_SHOW_ISOSTRETCH:
SetMapMode (hdc, MM_ISOTROPIC) ;
SetWindowExtEx (hdc, cxBitmap, cyBitmap, NULL) ;
SetViewportExtEx (hdc, cxClient, cyClient, NULL) ;
SetWindowOrgEx (hdc, cxBitmap / 2, cyBitmap / 2, NULL) ;
SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;

iReturn = StretchBlt (hdc, 0, 0, cxBitmap, cyBitmap,
hdcMem, 0, 0, cxBitmap, cyBitmap, SRCCOPY) ;
break ;
}
DeleteDC (hdcMem) ;
RestoreDC (hdc, -1) ;
return iReturn ;
}
我想这样应该可以了
回复
faquirhu 2002-12-06
谢谢上面这位大虾,您的代码我觉的只能把文件打开,并把数据读出来,但并不能在窗口中显示出来,不过同样谢谢您
回复
aprilofeyes 2002-12-06
上面代码很清晰,我没有加注释,祝你好运
回复
aprilofeyes 2002-12-06
case WM_COMMAND:
iConvert = 0 ;

switch (LOWORD (wParam))
{
case IDM_FILE_OPEN:

// Show the File Open dialog box

if (!GetOpenFileName (&ofn))
return 0 ;

// If there's an existing DIB and palette, delete them

SendMessage (hwnd, WM_USER_DELETEDIB, 0, 0) ;

// Load the DIB into memory

SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
ShowCursor (TRUE) ;

hdib = DibFileLoad (szFileName) ;

ShowCursor (FALSE) ;
SetCursor (LoadCursor (NULL, IDC_ARROW)) ;

// Reset the scroll bars

SendMessage (hwnd, WM_USER_SETSCROLLS, TRUE, 0) ;

// Create the palette and DDB

SendMessage (hwnd, WM_USER_CREATEPAL, TRUE, 0) ;

if (!hdib)
{
MessageBox (hwnd, TEXT ("Cannot load DIB file!"),
szAppName, MB_OK | MB_ICONEXCLAMATION) ;
}
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
上面是消息处理部分,下面是
HDIB DibFileLoad (const TCHAR * szFileName)
{
BITMAPFILEHEADER bmfh ;
BITMAPINFO * pbmi ;
BOOL bSuccess ;
DWORD dwInfoSize, dwBitsSize, dwBytesRead ;
HANDLE hFile ;
HDIB hDib ;

// Open the file: read access, prohibit write access

hFile = CreateFile (szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) ;

if (hFile == INVALID_HANDLE_VALUE)
return NULL ;

// Read in the BITMAPFILEHEADER

bSuccess = ReadFile (hFile, &bmfh, sizeof (BITMAPFILEHEADER),
&dwBytesRead, NULL) ;

if (!bSuccess || (dwBytesRead != sizeof (BITMAPFILEHEADER))
|| (bmfh.bfType != * (WORD *) "BM"))
{
CloseHandle (hFile) ;
return NULL ;
}
// Allocate memory for the information structure & read it in

dwInfoSize = bmfh.bfOffBits - sizeof (BITMAPFILEHEADER) ;

if (NULL == (pbmi = malloc (dwInfoSize)))
{
CloseHandle (hFile) ;
return NULL ;
}

bSuccess = ReadFile (hFile, pbmi, dwInfoSize, &dwBytesRead, NULL) ;

if (!bSuccess || (dwBytesRead != dwInfoSize))
{
CloseHandle (hFile) ;
free (pbmi) ;
return NULL ;
}
// Create the DIB

hDib = DibCreateFromInfo (pbmi) ;
free (pbmi) ;

if (hDib == NULL)
{
CloseHandle (hFile) ;
return NULL ;
}
// Read in the bits

dwBitsSize = bmfh.bfSize - bmfh.bfOffBits ;

bSuccess = ReadFile (hFile, ((PDIBSTRUCT) hDib)->pBits,
dwBitsSize, &dwBytesRead, NULL) ;
CloseHandle (hFile) ;

if (!bSuccess || (dwBytesRead != dwBitsSize))
{
DibDelete (hDib) ;
return NULL ;
}
return hDib ;
}
我想满足你的要求了,使用API,没有用loadimage
回复
zyl910 2002-12-05
SetDIBitsToDevice
回复
sitai 2002-12-05
强烈关注,最好能给出流程,越详细越好,分不够我给
回复
faquirhu 2002-12-05
上面这位大虾,您提供的网站确实让我学到了一些东西,您能告诉我应怎样处理这些数据才能让它在屏幕上显示出来
回复
zyl910 2002-12-05
http://www.csdn.net/develop/Read_Article.asp?Id=12484
http://asp.6to23.com/iseesoft/devdoc/imgdoc/bmp_fileformat.htm
回复
faquirhu 2002-12-05
哪怕给个思路也行呀
回复
wwwqqq 2002-12-04
用CBitmap
回复
hglcsdn 2002-12-04
先看看BITMAPHEADINFO和BITMAPFILEINFO结构
回复
相关推荐
发帖
图形处理/算法
创建于2007-09-28

1.9w+

社区成员

VC/MFC 图形处理/算法
申请成为版主
帖子事件
创建了帖子
2002-12-04 08:13
社区公告
暂无公告