//程序可以保存图片为001.bmp ,  但是有600多MB, ACDSEE打开后黑屏什么也没有??
//处理即给分void CBmpOptDlg::OnCap() 
{
// TODO: Add your control notification handler code here
CWnd *pWnd=GetDesktopWindow();  //GetActiveWindow()
pWnd->GetWindowRect(&rect); CopyScreenToBitmap(rect);
CString str="e:\\001.bmp";
char * cfile;
cfile=str.GetBuffer(0);
SaveBitmapToFile(hBitmap,cfile);
}HBITMAP CBmpOptDlg::CopyScreenToBitmap(CRect &rect)//LPRECT lpRect)
 //lpRect 代表选定区域
{
   HDC  hScrDC, hMemDC; 
   // 屏幕和内存设备描述表
   HBITMAP    hBitmap, hOldBitmap;   
   // 位图句柄
   int       nX, nY, nX2, nY2;      
   // 选定区域坐标
   int       nWidth, nHeight;      
   // 位图宽度和高度
   int       xScrn, yScrn;         
   
   // 屏幕分辨率
   // 确保选定区域不为空矩形   if (IsRectEmpty(rect))  //lpRect))
     return NULL;   //为屏幕创建设备描述表
   hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);   //为屏幕设备描述表创建兼容的内存设备描述表
   hMemDC = CreateCompatibleDC(hScrDC);   // 获得选定区域坐标
   nX  =rect.left;
   nY  =rect.top;
   nX2 =rect.right;
   nY2 =rect.bottom; /*  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;}int CBmpOptDlg::SaveBitmapToFile(HBITMAP hBitmap ,  LPSTR lpFileName) //hBitmap 为刚才的屏幕位图句柄
 //lpFileName 为位图文件名
{    
HDC  hDC;     
    
//设备描述表
    int  iBits;      
  //当前显示分辨率下每个像素所占字节数
WORD wBitCount;   
    //位图中每个像素所占字节数
      //定义调色板大小, 位图中像素字节大小 ,
      //位图文件大小 , 写入文件字节数
      DWORD  dwPaletteSize=0,dwBmBitsSize,dwDIBSize, dwWritten;
      BITMAP Bitmap;              //位图属性结构
      BITMAPFILEHEADER   bmfHdr;           //位图文件头结构
      BITMAPINFOHEADER   bi;               //位图信息头结构 
      LPBITMAPINFOHEADER lpbi;             //指向位图信息头结构
      HANDLE fh, hDib, hPal,hOldPal=NULL;   //定义文件,分配内存句柄,调色板句柄
      //计算位图文件每个像素所占字节数
     hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
     iBits = GetDeviceCaps(hDC, BITSPIXEL) * 
     GetDeviceCaps(hDC, PLANES);     DeleteDC(hDC);     if (iBits <= 1)
      wBitCount = 1;     else if (iBits <= 4)
      wBitCount = 4;     else if (iBits <= 8)
      wBitCount = 8;    else if (iBits <= 24)
      wBitCount = 24;   //计算调色板大小
   if (wBitCount <= 8)
      dwPaletteSize = (1 <<  wBitCount) *
      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         = wBitCount;
   bi.biCompression      = BI_RGB;
   bi.biSizeImage        = 0;
   bi.biXPelsPerMeter     = 0;
   bi.biYPelsPerMeter     = 0;
   bi.biClrUsed         = 0;
   bi.biClrImportant      = 0;
   dwBmBitsSize = ((Bitmap.bmWidth * wBitCount+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()->m_hDC;
      hOldPal = SelectPalette(hDC, (HPALETTE)hPal, FALSE);
      RealizePalette(hDC);
   }   // 获取该调色板下新的像素值 BITMAPINFOHEADER 
   GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,
   (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize, (BITMAPINFO*)lpbi, DIB_RGB_COLORS);   //恢复调色板   
   if (hOldPal)
   {
  SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
      RealizePalette(hDC);
      //ReleaseDC();   }   //创建位图文件    
   fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, 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;   // 写入位图文件头
   WriteFile(fh, (LPSTR)&bmfHdr, sizeof
   (BITMAPFILEHEADER), &dwWritten, NULL);   // 写入位图文件其余内容
   WriteFile(fh, (LPSTR)lpbi, dwDIBSize, 
   &dwWritten, NULL);   //清除   
   GlobalUnlock(hDib);
   GlobalFree(hDib);
   CloseHandle(fh);
}

解决方案 »

  1.   

    2024*768 ,颜色 32位(主板集成显卡),可是为什么存的bmp文件有600多MB? 并且打开什么都没有啊?
      

  2.   

    感觉太复杂了,中间可能有些数据重复或者错误了。其实已经有HBITMAP,中间很多数据通过GetObject()都得到了,有必要这么翻来覆去的搞吗?
      

  3.   

    保存屏幕函数如下:void CCaptureDlg::SaveBmp()
    {
    CDC dc;
    dc.CreateDC("DISPLAY",NULL,NULL,NULL);
    CBitmap bm;
    int Width=GetSystemMetrics(SM_CXSCREEN);
    int Height=GetSystemMetrics(SM_CYSCREEN);
    bm.CreateCompatibleBitmap(&dc,Width,Height);
    CDC tdc;
    tdc.CreateCompatibleDC(&dc);
    CBitmap*pOld=tdc.SelectObject(&bm);
    tdc.BitBlt(0,0,Width,Height,&dc,0,0,SRCCOPY);
    tdc.SelectObject(pOld);
    BITMAP btm;
    bm.GetBitmap(&btm);
    DWORD size=btm.bmWidthBytes*btm.bmHeight;
    LPSTR lpData=(LPSTR)GlobalAllocPtr(GPTR,size);
    /////////////////////////////////////////////
    BITMAPINFOHEADER bih;
    bih.biBitCount=btm.bmBitsPixel;
    bih.biClrImportant=0;
    bih.biClrUsed=0;
    bih.biCompression=0;
    bih.biHeight=btm.bmHeight;
    bih.biPlanes=1;
    bih.biSize=sizeof(BITMAPINFOHEADER);
    bih.biSizeImage=size;
    bih.biWidth=btm.bmWidth;
    bih.biXPelsPerMeter=0;
    bih.biYPelsPerMeter=0;
    GetDIBits(dc,bm,0,bih.biHeight,lpData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
    //bm.GetBitmapBits(size,lpData);//此函数在处理5-5-5模式的16位色下会出现颜色混乱
    static int filecount=0;
    CString name;
    name.Format("pict%04d.bmp",filecount++);
    name=m_Path+name;
    BITMAPFILEHEADER bfh;
    bfh.bfReserved1=bfh.bfReserved2=0;
    bfh.bfType=((WORD)('M'<< 8)|'B');
    bfh.bfSize=54+size;
    bfh.bfOffBits=54;
    CFile bf;
    if(bf.Open(name,CFile::modeCreate|CFile::modeWrite)){
    bf.WriteHuge(&bfh,sizeof(BITMAPFILEHEADER));
    bf.WriteHuge(&bih,sizeof(BITMAPINFOHEADER));
    bf.WriteHuge(lpData,size);
    bf.Close();
    nCount++;
    }
    GlobalFreePtr(lpData);
    if(nCount==1)
    m_Number.Format("%d picture captured.",nCount);
    else
    m_Number.Format("%d pictures captured.",nCount);
    UpdateData(FALSE);
    }