VC下显示JPG,BMP,GIF等图像格式(转载)
方法一:用COM组件的 IPicture接口(VC)
方法二:用GDI+(VC)
EVC下显示图片
用COM组件的 IPicture接口(VC)
在OnPaint 或 OnDraw中加入下代码即可 (注意 屏蔽掉 CXXDialog::OnPaint CXX::OnDraw)
dc.SetBkMode( TRANSPARENT );
CFile mFile;
LONG nLength;
//1 打开文件并获得文件的真实大小
if ( mFile.Open( _T( "./res/test.jpg" ),CFile::modeRead )
&&( ( nLength = mFile.GetLength() ) > 0 ) )
{
//2 从堆中分配指定数量字节的一整块,这时系统无法提供零零碎碎的局部或全局的堆
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, nLength );
LPVOID pvData = NULL;
if ( hGlobal != NULL )
{
//3 锁定全局内存对象并返回它的首地址
if ( ( pvData = GlobalLock(hGlobal) ) != NULL )
{
//4 把文件内容读进全局内存对象的地址空间中
mFile.Read( pvData, nLength );
mFile.Close();
//5 GlobalUnlock函数把以GMEM_MOVEABLE方式分配的内存对象的锁定计数器减1
GlobalUnlock( hGlobal );
//6 从全局内存中创建stream对象,第二个参数指定当stream释放时是否自动释放全局内存
IStream *pStm;
CreateStreamOnHGlobal( hGlobal, TRUE, &pStm) ;
//7 创建一个新的picture对象并用stream对象中的内容初始化
IPicture *pPic;
if( SUCCEEDED( OleLoadPicture( pStm, nLength, TRUE, IID_IPicture, (LPVOID*)&pPic ) ) )
{
//8 释放不要的stream对象并清空stream指针
pStm->Release();
pStm=NULL;
OLE_XSIZE_HIMETRIC mWidth;
OLE_YSIZE_HIMETRIC mHeight;
//9 得到picture对象中图片的宽和高
pPic->get_Width( &mWidth );
pPic->get_Height( &mHeight );
CRect rc;
GetClientRect( &rc );
double fX,fY;
//10 GetDeviceCaps(HORZRES)得到屏幕的宽度(单位:像素)
// GetDeviceCaps(HORZSIZE)得到屏幕的宽度(单位:毫米)
fX = (double) dc.GetDeviceCaps(HORZRES) * (double)mWidth / ( (double)dc.GetDeviceCaps( HORZSIZE ) * 100.0 );
fY = (double) dc.GetDeviceCaps(VERTRES) * (double)mHeight / ( (double)dc.GetDeviceCaps( VERTSIZE ) *100.0 );
//11 把图像显示在dc中
if( FAILED( pPic->Render( dc.GetSafeHdc(), 0, 0, (DWORD)fX , (DWORD)fY , 0, mHeight, mWidth, -mHeight, NULL ) ) )
AfxMessageBox( _T("渲染图片失败") );
/*根据背景大小缩放图片
CRect rcClient;
GetClientRect( &rcClient );
BOOL bWidth = rcClient.Width() / fX > rcClient.Height() / fY;
if ( bWidth )
{
if( FAILED( pPic->Render( dc.GetSafeHdc(), 0, 0, (DWORD)rcClient.Width() , (DWORD)rcClient.Width() * fY / fX , 0, mHeight, mWidth, -mHeight, NULL ) ) )
AfxMessageBox( _T("渲染图片失败") );
}
else
{
if( FAILED( pPic->Render( dc.GetSafeHdc(), 0, 0, (DWORD)rcClient.Height() * fX/ fY, (DWORD)rcClient.Height() , 0, mHeight, mWidth, -mHeight, NULL ) ) )
AfxMessageBox( _T("渲染图片失败") );
}
*/
//12 释放不要的picture对象,并把指针清空
pPic->Release();
pPic=NULL;
//13 释放不要的全局内存对象,这个千万别忘了(32位程序不需要这行,系统会自动释放;16位程序一定要)
FreeResource(hGlobal);
}
else
AfxMessageBox( _T("从stream中装载图片失败") );
}
}
else
AfxMessageBox( _T("分配内存失败") );
}
else
AfxMessageBox( _T("打开文件失败") );
用GDI+(VC)
添加Gdiplus.lib到工程中
头文件中添加
#include "Gdiplus.h"
using namespace Gdiplus;
添加类成员变量
GdiplusStartupInput m_gdiPlusInPut;
ULONG_PTR m_gdiPlusToken;
构造函数中初始化GDI+
GdiplusStartup( &m_gdiPlusToken, &m_gdiPlusInPut, NULL );
析构函数中 //销毁GDI+
GdiplusShutdown(gdiplusToken);
OnPaint()中
//CDialog::OnPaint();
CPaintDC dc( this );
//建立图形对象
Graphics mGraphics( dc.GetSafeHdc() );
//装入图像文件
Image img( L"./res/test.jpg", TRUE );
//在指定区域pdestPoints显示图像
/*//根据背景大小按比例缩放
CRect rcClient;
GetClientRect( &rcClient );
BOOL bWidth = rcClient.Width() / img.GetWidth() > rcClient.Height() / img.GetHeight();
if ( bWidth )
{
mGraphics.DrawImage( &img, 0, 0, rcClient.Width(), rcClient.Width() * img.GetHeight() / img.GetWidth() );
}
else
{
mGraphics.DrawImage(&img, 0, 0, rcClient.Height() * img.GetWidth() / img.GetHeight(), rcClient.Height() );
}
//原始大小
mGraphics.DrawImage(&img, 0, 0, img.GetWidth(), img.GetHeight() );
EVC下显示图片:
void CXXDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetBkMode( TRANSPARENT );
CBitmap mBitmap;
mBitmap.Attach( SHLoadImageFile( _T( "./player.jpg" ) ) );
BITMAP mInfo;
mBitmap.GetBitmap( &mInfo );
CDC mPicDC;
mPicDC.CreateCompatibleDC( &dc );
CBitmap* pOldBitmap = mPicDC.SelectObject( &mBitmap );
dc.BitBlt( 0, 0, mInfo.bmWidth, mInfo.bmHeight, &mPicDC, 0, 0, SRCCOPY );
mPicDC.SelectObject( pOldBitmap );
mBitmap.DeleteObject();
}
Image::GetThumbnailImage(但是MSDN中提到:如果图片文件有内嵌的缩略图,那么就提取这个缩略图返回,否则才会缩放原图片)
或者下面的方法(只适合24位色深的格式)
Bitmap * ScaleBitmap(Bitmap * pBitmap,UINT nWidth,UINT nHeight)
{
Bitmap * pTemp = new Bitmap(nWidth,nHeight,pBitmap-> GetPixelFormat());
if( pTemp )
{
Graphics * g = Graphics::FromImage(pTemp);
if( g )
{
// use the best interpolation mode
g-> SetInterpolationMode(InterpolationModeHighQualityBicubic);
g-> DrawImage(pBitmap,0,0,nWidth,nHeight);
delete g;
}
}
return pTemp;
}
从最新的Platform SDK中就可以找到了
如果你用GDI处理的话,就在内存中把JPG转为BMP格式然后再缩放显示,不过JPG转BMP的代码非常复杂,光转换的原理就可以整整写一本书了。
如果用GDI+处理的话,就简单了,windows常用图片格式GDI+都是用同样的方式处理的,可以不去考虑图片的格式
////////////////////
bitmap1,bitmap2,bitmap3 //你要显示的图片用Bitmap bitmap1(L"jpg图片绝对路径");来构造
rect1,rect2,rect3 //图片要缩放到的区域是Rect,而不是Crect
x2,y2,x3,y3 //第二,三张图片要显示的起始位置
////////////////////////////
Graphics graphics(this->GetDC()->m_hDC);
graphics.DrawImage(&bitmap1,rect1,0,0,bitmap1.GetWidth(),bitmap1.GetHeight(),UnitPixel);
graphics.TranslateTransform(x2,y2);
graphics.DrawImage(&bitmap2,rect2,0,0,bitmap2.GetWidth(),bitmap2.GetHeight(),UnitPixel);
graphics.TranslateTransform(x3,y3);
graphics.DrawImage(&bitmap3,rect3,0,0,bitmap3.GetWidth(),bitmap3.GetHeight(),UnitPixel);
VC中如何等比例缩放图像
在放大或缩小图像时,如何能最好的保持图像原态比例来显示呢?下面提供一个涵数可帮你来实现,调用它后,返回的矩形区域既为最佳显示图像大小。
涵数中的第一个参数rcScreen为图像要被显示的矩形大小,第二个参数sizePicture为图像自身大小,第三个参数bCenter为是否居中显示,返回值CRect既为图像最佳显示大小。
涵数如下所示:
CRect RectSizeWithConstantRatio( CRect* rcScreen,
CSize sizePicture,
BOOL bCenter)
{
CRect rect(rcScreen);
double dWidth = rcScreen->Width();
double dHeight = rcScreen->Height();
double dAspectRatio = dWidth/dHeight;
double dPictureWidth = sizePicture.cx;
double dPictureHeight = sizePicture.cy;
double dPictureAspectRatio = dPictureWidth/dPictureHeight;
//If the aspect ratios are the same then the screen rectangle
// will do, otherwise we need to calculate the new rectangle
if (dPictureAspectRatio > dAspectRatio)
{
int nNewHeight = (int)(dWidth/dPictureWidth*dPictureHeight);
int nCenteringFactor = (rcScreen->Height() - nNewHeight) / 2;
rect.SetRect( 0,
nCenteringFactor,
(int)dWidth,
nNewHeight + nCenteringFactor);
}
else if (dPictureAspectRatio < dAspectRatio)
{
int nNewWidth = (int)(dHeight/dPictureHeight*dPictureWidth);
int nCenteringFactor = (rcScreen->Width() - nNewWidth) / 2;
rect.SetRect( nCenteringFactor,
0,
nNewWidth + nCenteringFactor,
(int)(dHeight));
}
return rect;
};
l 此涵数的使用方法如下:
{
……(部分省略)
//得到屏幕大小
CRect rcScreen( 0, 0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN));
//得到图像尺寸
CSize sizePicture(picture.m_Width, picture.m_Height);
CRect rcNewPictureRect =
SizeRectWithConstantAspectRatio(&rcScreen,
sizePicture,
TRUE);
picture.Show(&dc, rcNewPictureRect);
}
- #include <ocidl.h>
- #include <olectl.h>
-
- // lpstrFile:文件名(最好是包含路径在内)
- // hWnd
- // nScrWidth:输出图片的宽度
- // nScrHeight:输出图片的高度
- // nScrWidth、nScrHeight是输出图片的实际大小,换而言之是指缩放后的尺寸
-
- HRESULT ShowPic(char *lpstrFile,HWND hWnd,int nScrWidth,int nScrHeight)
- {
- HDC hDC_Temp=GetDC(hWnd);
-
- IPicture *pPic;
- IStream *pStm;
-
- BOOL bResult;
-
- HANDLE hFile=NULL;
- DWORD dwFileSize,dwByteRead;
-
- //打开硬盘中的图形文件
- hFile=CreateFile(lpstrFile,GENERIC_READ,
- FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
-
- if (hFile!=INVALID_HANDLE_value)
- {
- dwFileSize=GetFileSize(hFile,NULL);//获取文件字节数
-
- if (dwFileSize==0xFFFFFFFF)
- return E_FAIL;
- }
- else
- {
- return E_FAIL;
- }
-
-
- //分配全局存储空间
- HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwFileSize);
- LPVOID pvData = NULL;
-
- if (hGlobal == NULL)
- return E_FAIL;
-
- if ((pvData = GlobalLock(hGlobal)) == NULL)//锁定分配内存块
- return E_FAIL;
-
- ReadFile(hFile,pvData,dwFileSize,&dwByteRead,NULL);//把文件读入内存缓冲区
-
- GlobalUnlock(hGlobal);
-
- CreateStreamOnHGlobal(hGlobal, TRUE, &pStm);
-
- //装入图形文件
- bResult=OleLoadPicture(pStm,dwFileSize,TRUE,IID_IPicture,(LPVOID*)&pPic);
-
- if(FAILED(bResult))
- return E_FAIL;
-
- OLE_XSIZE_HIMETRIC hmWidth;//图片的真实宽度
- OLE_YSIZE_HIMETRIC hmHeight;//图片的真实高度
- pPic->get_Width(&hmWidth);
- pPic->get_Height(&hmHeight);
-
-
- //将图形输出到屏幕上(有点像BitBlt)
- bResult=pPic->Render(hDC_Temp,0,0,nScrWidth,nScrHeight,
- 0,hmHeight,hmWidth,-hmHeight,NULL);
-
- pPic->Release();
-
- CloseHandle(hFile);//关闭打开的文件
-
- if (SUCCEEDED(bResult))
- {
- return S_OK;
- }
- else
- {
- return E_FAIL;
- }
- }
我找到一个解决的方法啦:通过位图来转换
//wRatio hRatio分别为Width和Height调整的百分比(%)
int ResizePicture(LPCWSTR lpSrcFile,LPCWSTR lpDstFile,int wRatio,int hRatio)
{
Image srcImg(lpSrcFile);
int srcWidth=srcImg.GetWidth();
int srcHeight=srcImg.GetHeight();
//计算调整后的Width和Height
int dstWidth=srcWidth*wRatio/100;
int dstHeight=srcHeight*hRatio/100;
// Construct a Graphics object based on the image.
Graphics imgGraphics(&srcImg);
Bitmap bitmap(dstWidth,dstHeight,&imgGraphics);
Graphics bmpGraphics(&bitmap);
bmpGraphics.DrawImage(&srcImg,0,0,dstWidth,dstHeight);
// Save the altered image.
LPWSTR lpExt=PathFindExtensionW(lpSrcFile);
lpExt++;
LPWSTR lpEncoder;
switch(*lpExt)
{
case L 'J ':
case L 'j ':
lpEncoder=L "image/jpeg ";
break;
case L 'P ':
case L 'p ':
lpEncoder=L "image/png ";
break;
case L 'B ':
case L 'b ':
lpEncoder=L "image/bmp ";
break;
case L 'G ':
case L 'g ':
lpEncoder=L "image/gif ";
break;
case L 't ':
case L 'T ':
lpEncoder=L "image/tiff ";
break;
default:
lpEncoder=L "image/jpeg ";
}
CLSID imgClsid;
//GetEncoderClsid()函数是在MSDN中的例子
GetEncoderClsid(lpEncoder, &imgClsid);
bitmap.Save(lpDstFile,&imgClsid,NULL);
return 0;
}