如何保存图片的指定区域 VC6.0 MFC GDI+

bearJiang 2011-01-20 11:36:47
如何保存图片的指定区域 VC6.0 MFC GDI+

图片现在在 Image* currentImg 。

请问怎样才能保存这个图片的制定区域为bmp文件。

或者保存到内存为HBITMAP指向也可以

一下是一些参考代码,我刚学MFC,弄了一天了,还没弄懂,谢谢!


// DIB.cpp
//------------------------------------------------------------------------------//
#include "stdafx.h"
#include "DIB.h"
//------------------------------------------------------------------------------//
CDib::CDib()
{

// Set the Dib pointer to
// NULL so we know if it's
// been loaded.
this->m_pDib = NULL;
this->m_pBIH = NULL;

}
//------------------------------------------------------------------------------//
CDib::~CDib()
{

// If a Dib has been loaded,
// delete the memory.
this->ReleaseBuffer();
}
//------------------------------------------------------------------------------//
void CDib::ReleaseBuffer()
{
if( m_pDib != NULL )
{ delete [] m_pDib; }
m_pDib = NULL;
}
//------------------------------------------------------------------------------//
BOOL CDib::Load( const char *pszFilename )
{

CFile cf;

// Attempt to open the Dib file for reading.
if( !cf.Open( pszFilename, CFile::modeRead ) )
return( FALSE );

// Get the size of the file and store
// in a local variable. Subtract the
// size of the BITMAPFILEHEADER structure
// since we won't keep that in memory.
DWORD dwDibSize;
dwDibSize =
cf.GetLength() - sizeof( BITMAPFILEHEADER );

// Attempt to allocate the Dib memory.
unsigned char *pDib;
pDib = new unsigned char [dwDibSize];
if( pDib == NULL )
return( FALSE );

BITMAPFILEHEADER BFH;

// Read in the Dib header and data.
try{

// Did we read in the entire BITMAPFILEHEADER?
if( cf.Read( &BFH, sizeof( BITMAPFILEHEADER ) )
!= sizeof( BITMAPFILEHEADER ) ||

// Is the type 'MB'?
BFH.bfType != 'MB' ||

// Did we read in the remaining data?
cf.Read( pDib, dwDibSize ) != dwDibSize ){

// Delete the memory if we had any
// errors and return FALSE.
delete [] pDib;
cf.Close();
return( FALSE );
}
}

// If we catch an exception, delete the
// exception, the temporary Dib memory,
// and return FALSE.
catch( CFileException *e ){
e->Delete();
delete [] pDib;
cf.Close();
return( FALSE );
}

// If we got to this point, the Dib has been
// loaded. If a Dib was already loaded into
// this class, we must now delete it.
if( m_pDib != NULL )
delete m_pDib;

// Store the local Dib data pointer and
// Dib size variables in the class member
// variables.
m_pDib = pDib;
m_dwDibSize = dwDibSize;

// Pointer our BITMAPINFOHEADER and RGBQUAD
// variables to the correct place in the Dib data.
m_pBIH = (BITMAPINFOHEADER *) m_pDib;
m_pPalette =
(RGBQUAD *) &m_pDib[sizeof(BITMAPINFOHEADER)];

// Calculate the number of palette entries.
m_nPaletteEntries = 1 << m_pBIH->biBitCount;
if( m_pBIH->biBitCount > 8 )
m_nPaletteEntries = 0;
else if( m_pBIH->biClrUsed != 0 )
m_nPaletteEntries = m_pBIH->biClrUsed;

// Point m_pDibBits to the actual Dib bits data.
m_pDibBits =
&m_pDib[sizeof(BITMAPINFOHEADER)+
m_nPaletteEntries*sizeof(RGBQUAD)];

// If we have a valid palette, delete it.
if( m_Palette.GetSafeHandle() != NULL )
m_Palette.DeleteObject();

// If there are palette entries, we'll need
// to create a LOGPALETTE then create the
// CPalette palette.
if( m_nPaletteEntries != 0 ){

// Allocate the LOGPALETTE structure.
LOGPALETTE *pLogPal = (LOGPALETTE *) new char
[sizeof(LOGPALETTE)+
m_nPaletteEntries*sizeof(PALETTEENTRY)];

if( pLogPal != NULL ){

// Set the LOGPALETTE to version 0x300
// and store the number of palette
// entries.
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = m_nPaletteEntries;

// Store the RGB values into each
// PALETTEENTRY element.
for( int i=0; i<m_nPaletteEntries; i++ ){
pLogPal->palPalEntry[i].peRed =
m_pPalette[i].rgbRed;
pLogPal->palPalEntry[i].peGreen =
m_pPalette[i].rgbGreen;
pLogPal->palPalEntry[i].peBlue =
m_pPalette[i].rgbBlue;
}

// Create the CPalette object and
// delete the LOGPALETTE memory.
m_Palette.CreatePalette( pLogPal );
delete [] pLogPal;
}
}
cf.Close();
return( TRUE );

}
//------------------------------------------------------------------------------//
BOOL CDib::Save( const char *pszFilename )
{

// If we have no data, we can't save.
if( m_pDib == NULL )
return( FALSE );

CFile cf;

// Attempt to create the file.
if( !cf.Open( pszFilename,
CFile::modeCreate | CFile::modeWrite ) )
return( FALSE );

// Write the data.
try{

// First, create a BITMAPFILEHEADER
// with the correct data.
BITMAPFILEHEADER BFH;
memset( &BFH, 0, sizeof( BITMAPFILEHEADER ) );
BFH.bfType = 'MB';
BFH.bfSize = sizeof( BITMAPFILEHEADER ) + m_dwDibSize;
BFH.bfOffBits = sizeof( BITMAPFILEHEADER ) +
sizeof( BITMAPINFOHEADER ) +
m_nPaletteEntries * sizeof( RGBQUAD );

// Write the BITMAPFILEHEADER and the
// Dib data.
cf.Write( &BFH, sizeof( BITMAPFILEHEADER ) );
cf.Write( m_pDib, m_dwDibSize );
}

// If we get an exception, delete the exception and
// return FALSE.
catch( CFileException *e ){
e->Delete();
return( FALSE );
}

return( TRUE );

}
//------------------------------------------------------------------------------//
BOOL CDib::DrawPartion( HDC &pDC, int SrcnX, int SrcnY, int SrcnWidth, int SrcnHeight, int DestnX = 0, int DestnY = 0, int DestnWidth = -1, int DestnHeight = -1 ) // Draw BMP image
{
// If we have not data we can't draw.
if( m_pDib == NULL )
return( FALSE );

// Check for the default values of -1
// in the width and height arguments. If
// we find -1 in either, we'll set them
// to the value that's in the BITMAPINFOHEADER.
if( SrcnWidth == -1 ) { return FALSE; }
if( SrcnHeight == -1 ) { return FALSE; }

// Use StretchDIBits to draw the Dib.

StretchDIBits( pDC, DestnX, DestnY,
DestnWidth, DestnHeight,
SrcnX, SrcnY,
SrcnWidth, SrcnHeight,
m_pDibBits,
(BITMAPINFO *) m_pBIH,
BI_RGB, SRCCOPY );

return( TRUE );

}
//------------------------------------------------------------------------------//
BOOL CDib::Draw( HDC &pDC, int nX, int nY, int nWidth, int nHeight )
{

// If we have not data we can't draw.
if( m_pDib == NULL )
return( FALSE );

// Check for the default values of -1
// in the width and height arguments. If
// we find -1 in either, we'll set them
// to the value that's in the BITMAPINFOHEADER.
if( nWidth == -1 )
nWidth = m_pBIH->biWidth;
if( nHeight == -1 )
nHeight = m_pBIH->biHeight;

// Use StretchDIBits to draw the Dib.
StretchDIBits( pDC, nX, nY,
nWidth, nHeight,
0, 0,
m_pBIH->biWidth, m_pBIH->biHeight,
m_pDibBits,
(BITMAPINFO *) m_pBIH,
BI_RGB, SRCCOPY );

return( TRUE );

}
//------------------------------------------------------------------------------//
BOOL CDib::SetPalette( CDC *pDC )
{

// If we have not data we
// won't want to set the palette.
if( m_pDib == NULL )
return( FALSE );

// Check to see if we have a palette
// handle. For Dibs greater than 8 bits,
// this will be NULL.
if( m_Palette.GetSafeHandle() == NULL )
return( TRUE );

// Select the palette, realize the palette,
// then finally restore the old palette.
CPalette *pOldPalette;
pOldPalette = pDC->SelectPalette( &m_Palette, FALSE );
pDC->RealizePalette();
pDC->SelectPalette( pOldPalette, FALSE );

return( TRUE );

}
//------------------------------------------------------------------------------//
unsigned char * CDib::GetDIB()
{
return m_pDib;
}
//------------------------------------------------------------------------------//
unsigned char * CDib::GetDIBBits()// BMP Bits data
{
return m_pDibBits;
}
//------------------------------------------------------------------------------//
BITMAPINFO * CDib::GetDIBInfo() //眔BMP Infor
{
return (BITMAPINFO*)this->m_pBIH;
}
//------------------------------------------------------------------------------//

HBITMAP CDib::CreatBMP(int nWidth, int nHeight, int nColor, CClientDC *pDC, UINT c)
{
void * pdata=0;

BITMAPINFO bi;
ZeroMemory(&bi,sizeof(bi));
bi.bmiHeader.biSize=sizeof(bi.bmiHeader);
bi.bmiHeader.biHeight=nHeight;
bi.bmiHeader.biWidth=nWidth;
bi.bmiHeader.biPlanes=1;
bi.bmiHeader.biBitCount=nColor;
bi.bmiHeader.biCompression=BI_RGB;
bi.bmiHeader.biSizeImage=GetBMPImagePixelsPerLine(nWidth,nColor)*nHeight;
HBITMAP hBitmap=CreateDIBSection(pDC->m_hDC,&bi,DIB_RGB_COLORS,&pdata,NULL,0);


BYTE *p=(BYTE *)pdata;
for(int i=0;i<nHeight*GetBMPImagePixelsPerLine(nWidth,nColor);i++)
{
p[i]=c;//位图的颜色
}

return hBitmap;
}

int CDib::GetBMPImagePixelsPerLine(int ImageX,int weishu)
{
int bytes_per_line ;
bytes_per_line=(ImageX*weishu+31)/8;
bytes_per_line=bytes_per_line/4*4;//得到图像的一行的位数
return bytes_per_line;
}




...全文
246 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
bearJiang 2011-01-20
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wwgddx 的回复:]

先把图片画到一个内存DC里,再把DC里的区域BITBLT拷贝到另外一个内存DC里,设置好起点和长宽。

然后把内存DC里的数据保存为BMP图片。思路是这样的。

也可以得到图像数据起点指针,然后通过位置移动到要截图的区域,然后从新保存到文件。、
[/Quote]

能给几行代码参考一下不?
wwgddx 2011-01-20
  • 打赏
  • 举报
回复
先把图片画到一个内存DC里,再把DC里的区域BITBLT拷贝到另外一个内存DC里,设置好起点和长宽。

然后把内存DC里的数据保存为BMP图片。思路是这样的。

也可以得到图像数据起点指针,然后通过位置移动到要截图的区域,然后从新保存到文件。、
bearJiang 2011-01-20
  • 打赏
  • 举报
回复


BOOL CDib::SaveNewImage(HBITMAP hbitmap, LPSTR filename, int nColor)
{
BITMAP Bitmap;
HDC hDC;
DWORD dwPaletteSize=0,dwBmBitsSize,dwDIBSize, dwWritten;
BITMAPFILEHEADER bmfHdr;
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh, hDib, hPal,hOldPal=NULL;

if (nColor<= 8)
dwPaletteSize = (1<<nColor) *sizeof(RGBQUAD);
GetObject(hbitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = Bitmap.bmWidth;
bi.biHeight = Bitmap.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = nColor;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmBitsSize = ((Bitmap.bmWidth * nColor+31)/32*4)*Bitmap.bmHeight;
//为位图分配内存
hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
//设置调色板
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hDC = ::GetDC(NULL);
hOldPal = SelectPalette(hDC, (HPALETTE)hPal, FALSE);
RealizePalette(hDC);
}
// 获取该调色板下新的像素值
GetDIBits(hDC, hbitmap, 0, Bitmap.bmHeight,
(LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize,
(BITMAPINFO *)lpbi, DIB_RGB_COLORS);
if (hOldPal)
{
SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL,hDC);
}

fh = CreateFile(filename, GENERIC_WRITE,
0,//not be shared
NULL, //cannot be inherited
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);

if (fh == INVALID_HANDLE_VALUE)
return FALSE;
//设置位图文件头
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER)
+ (DWORD)sizeof(BITMAPINFOHEADER)+ dwPaletteSize;

//write file header
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);

//write bmp data
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);

GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
DeleteObject(hbitmap);
return TRUE;
}
HBITMAP CDib::CopyScreenToBitmap(LPRECT lpRect)
{
// 屏幕和内存设备描述表
HDC hScrDC, hMemDC;

// 位图句柄
HBITMAP hBitmap, hOldBitmap;

// 选定区域坐标
int nX, nY, nX2, nY2;

// 位图宽度和高度
int nWidth, nHeight;

// 屏幕分辨率
int xScrn, yScrn;

// 确保选定区域不为空矩形
if (IsRectEmpty(lpRect))
return NULL;

//为屏幕创建设备描述表
hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);

//为屏幕设备描述表创建兼容的内存设备描述表
hMemDC = CreateCompatibleDC(hScrDC);

// 获得选定区域坐标
nX = lpRect->left;
nY = lpRect->top;
nX2 = lpRect->right;
nY2 = lpRect->bottom;

// 获得屏幕分辨率
xScrn = GetDeviceCaps(hScrDC, HORZRES);
yScrn = GetDeviceCaps(hScrDC, VERTRES);

//确保选定区域是可见的
if (nX < 0)
nX = 0;
if (nY < 0)
nY = 0;
if (nX2 > xScrn)
nX2 = xScrn;
if (nY2 > yScrn)
nY2 = yScrn;

nWidth = nX2 - nX;
nHeight = nY2 - nY;

// 创建一个与屏幕设备描述表兼容的位图
hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);

// 把新位图选到内存设备描述表中
hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);

// 把屏幕设备描述表拷贝到内存设备描述表中
BitBlt(hMemDC, 0, 0, nWidth, nHeight,hScrDC, nX, nY, SRCCOPY);

//得到屏幕位图的句柄
hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);

//清除
DeleteDC(hScrDC);
DeleteDC(hMemDC);

// 返回位图句柄
return hBitmap;
}

Visual C++6.0使用GDI+的一般方法 1. 载解压GDI+开发包; 2. 正确设置include & lib 目录; 3. stdafx.h 添加: #ifndef ULONG_PTR #define ULONG_PTR unsigned long* #endif #include 4. 程序中添加GDI+的包含文件gdiplus.h以及附加的类库gdiplus.lib。 通常gdiplus.h包含文件添加在应用程序的stdafx.h文件中,而gdiplus.lib可用两种进行添加: 第一种是直接在stdafx.h文件中添加下列语句: #pragma comment( lib, "gdiplus.lib" ) 另一种方法是: 在VC.net中添加库文件在:项目菜单->属性->链接器->输入 举个例子: (1)在应用程序项目的应用类中,添加一个成员变量,如下列代码: ULONG_PTR m_gdiplusToken; 其中,ULONG_PTR是一个DWORD数据类型,该成员变量用来保存GDI+被初始化后在应用程序中的GDI+标识,以便能在应用程序退出后,引用该标识来调用Gdiplus:: GdiplusShutdown来关闭GDI+。 (2)在应用类中添加ExitInstance的重载,并添加下列代码用来关闭GDI+: int CGDITestApp::ExitInstance() { Gdiplus::GdiplusShutdown(m_gdiplusToken); return CWinApp::ExitInstance(); } (3)在应用类的InitInstance函数中添加GDI+的初始化代码: 注意:下面这些GDI+的初始化代码必须放在m_pMainWnd->UpdateWindow();之前。 CWinApp::InitInstance(); Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL); (4)在需要绘图的窗口或视图类中添加GDI+的绘制代码。 下面分别就单文档和基于对话框应用程序为例,说明使用GDI+的一般过程和方法。 1. 在单文档应用程序中使用GDI+ 在上面的过程中,我们就是以一个单文档应用程序Ex_GDIPlus作为示例的。下面列出第4步所涉及的代码: void CGDITestView::OnDraw(CDC* pDC) { CGDITestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here usingnamespace Gdiplus; Graphics graphics(pDC->m_hDC); Pen newPen(Color(255,0,0),3); HatchBrush newBrush(HatchStyleCross,Color(255,0,255,0),Color(255,0,0,255));//创建一个填充画刷,前景色为绿色,背景色为蓝色 graphics.DrawRectangle(&newPen,50,50,100,60);// 在(50,50)处绘制一个长为100,高为60的矩形 graphics.FillRectangle(&newBrush,50,50,100,60); // 在(50,50)处填充一个长为100,高为60的矩形区域 } 编译并运行,结果如图:

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧