C++保存HBITMAP为位图文件的实现方法

本文使用C++将位图句柄HBITMAP保存为位图文件,配合C++抓图代码可以实现抓图保存文件(.bmp)。

其步骤如下:

1、创建位图文件;
2、计算位图中每个像素所占字节数;
3. 获取位图结构BITMAP;
4、构造位图信息头BITMAPINFOHEADER;
5、构造位图文件头BITMAPFILEHEADER;
6、为位图内容分配内存;
7、处理调色板;
8、写入文件;
9、清除资源。

下面是C++源代码:

ImageHelper.h

#pragma once
 
#include <windows.h>
#include <string>
using namespace std;
 
class ImageHelper
{
public:
    static bool SaveBitmapToFile(HBITMAP bitmap, const string& filename); //保存位图到文件
 
private:
    static WORD GetBitmapBitCount(); //计算位图文件每个像素所占字节数
    static void ProcessPalette(HBITMAP hBitmap, const BITMAP& bitmap,
        DWORD paletteSize, LPBITMAPINFOHEADER lpBmpInfoHeader); //处理调色板
};

ImageHelper.cpp

#include "ImageHelper.h"
#include <shlwapi.h>
 
 
bool ImageHelper::SaveBitmapToFile(HBITMAP hBitmap, const string& filename)
{
    //1. 创建位图文件
    const auto file = CreateFileA(filename.c_str(), GENERIC_WRITE,
        0, nullptr, CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
        nullptr);
    if (file == INVALID_HANDLE_VALUE)
    {
        return false;
    }
 
    //2. 计算位图文件每个像素所占字节数
    const auto bitCount = GetBitmapBitCount();
 
    //3. 获取位图结构
    BITMAP bitmap;
    ::GetObject(hBitmap, sizeof(bitmap), reinterpret_cast<LPSTR>(&bitmap));
 
    //位图中像素字节大小(32字节对齐)
    const DWORD bmBitsSize = ((bitmap.bmWidth * bitCount + 31) / 32) * 4 * bitmap.bmHeight;
 
    //调色板大小
    const DWORD paletteSize = 0;
 
    //4. 构造位图信息头
    BITMAPINFOHEADER  bmpInfoHeader; //位图信息头结构
    bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfoHeader.biWidth = bitmap.bmWidth;
    bmpInfoHeader.biHeight = bitmap.bmHeight;
    bmpInfoHeader.biPlanes = 1;
    bmpInfoHeader.biBitCount = bitCount;
    bmpInfoHeader.biCompression = BI_RGB;
    bmpInfoHeader.biSizeImage = 0;
    bmpInfoHeader.biXPelsPerMeter = 0;
    bmpInfoHeader.biYPelsPerMeter = 0;
    bmpInfoHeader.biClrImportant = 0;
    bmpInfoHeader.biClrUsed = 0;
 
    //5. 构造位图文件头
    BITMAPFILEHEADER bmpFileHeader;
    bmpFileHeader.bfType = 0x4D42; //"BM"
    //位图文件大小
    const DWORD dibSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + paletteSize + bmBitsSize;
    bmpFileHeader.bfSize = dibSize;
    bmpFileHeader.bfReserved1 = 0;
    bmpFileHeader.bfReserved2 = 0;
    bmpFileHeader.bfOffBits = static_cast<DWORD>(sizeof(BITMAPFILEHEADER))
        + static_cast<DWORD>(sizeof(BITMAPINFOHEADER)) + paletteSize;
 
    //6. 为位图内容分配内存 
    const auto dib = GlobalAlloc(GHND, bmBitsSize + paletteSize + sizeof(BITMAPINFOHEADER)); //内存句柄
    const auto lpBmpInfoHeader = static_cast<LPBITMAPINFOHEADER>(GlobalLock(dib)); //指向位图信息头结构
    *lpBmpInfoHeader = bmpInfoHeader;
 
    //7. 处理调色板
    ProcessPalette(hBitmap, bitmap, paletteSize, lpBmpInfoHeader);
 
    //8. 写入文件
    DWORD written = 0; //写入文件字节数   
    WriteFile(file, reinterpret_cast<LPSTR>(&bmpFileHeader), sizeof(BITMAPFILEHEADER),
        &written, nullptr); //写入位图文件头
    WriteFile(file, reinterpret_cast<LPSTR>(lpBmpInfoHeader), dibSize,
        &written, nullptr); //写入位图文件其余内容
 
    //9. 清理资源
    GlobalUnlock(dib);
    GlobalFree(dib);
    CloseHandle(file);
 
    return true;
}
 
//计算位图文件每个像素所占字节数
WORD ImageHelper::GetBitmapBitCount()
{
    const auto dc = ::CreateDCA("DISPLAY", nullptr, nullptr, nullptr);
    //当前分辨率下每像素所占字节数
    const auto bits = ::GetDeviceCaps(dc, BITSPIXEL) * GetDeviceCaps(dc, PLANES);
    ::DeleteDC(dc);
 
    //位图中每像素所占字节数
    WORD bitCount;
    if (bits <= 1)
        bitCount = 1;
    else if (bits <= 4)
        bitCount = 4;
    else if (bits <= 8)
        bitCount = 8;
    else
        bitCount = 24;
 
    return bitCount;
}
 
//处理调色板
void ImageHelper::ProcessPalette(HBITMAP hBitmap, const BITMAP& bitmap,
    DWORD paletteSize, LPBITMAPINFOHEADER lpBmpInfoHeader)
{
    HANDLE oldPalette = nullptr;
    HDC dc = nullptr;
    const auto palette = GetStockObject(DEFAULT_PALETTE);
    if (palette != nullptr)
    {
        dc = ::GetDC(nullptr);
        oldPalette = ::SelectPalette(dc, static_cast<HPALETTE>(palette), FALSE);
        ::RealizePalette(dc); //实现设备调色板
    }
 
    //获取该调色板下新的像素值
    GetDIBits(dc, hBitmap, 0, static_cast<UINT>(bitmap.bmHeight),
        reinterpret_cast<LPSTR>(lpBmpInfoHeader) + sizeof(BITMAPINFOHEADER) + paletteSize,
        reinterpret_cast<BITMAPINFO*>(lpBmpInfoHeader), DIB_RGB_COLORS);
 
    //恢复调色板
    if (oldPalette != nullptr)
    {
        ::SelectPalette(dc, static_cast<HPALETTE>(oldPalette), TRUE);
        ::RealizePalette(dc);
        ::ReleaseDC(nullptr, dc);
    }
}

以上就是C++保存HBITMAP为位图文件的实现方法的详细内容,更多关于C++保存HBITMAP的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++数据精度问题的解决方案(对浮点数保存指定位小数)

     1.背景 对浮点数保存指定位小数.比如,  1.123456.   要保存1位小数,,调用方法后, 保存的结果为: 1.1. 再比如,1.98765,  保存2位小数的结果为: 2.00. 2. 解决方案 A.添加头文件 #include <sstream> #include <iomanip> B.添加命名空间 using namespace std; C.添加函数 /*******************************************************

  • VC++实现View内容保存为图片的方法

    本文实例讲述了VC++实现View内容保存为图片的方法.分享给大家供大家参考,具体如下: 我们在单文档应用程序中,经常需要将View中的内容保存为各种格式的图片文件,以便打印.乍一看,可能不知道从哪里下手,其实主要就是用到Bitmap的save方法,如: HDC hmemDC = ::CreateCompatibleDC( hdc ); HBITMAP hBmp = ::CreateCompatibleBitmap( hdc, destRect.Width(),destRect.Height()

  • C++保存txt文件实现方法代码实例

    简单示例 #include <windows.h> #include <fstream> #include <iostream> #include <string> using namespace std; int main() { ifstream myfile("in.txt"); ofstream outfile("out.txt", ios::app); //ios::app指追加写入 string temp;

  • C++实现单张图片读取和保存

    使用C++实现对单张图片的读取和保存,C语言可以参考,比较简单. #include<iostream> using namespace std; void main(void) { //保存输入图像文件名和输出图像文件名 char InImgName[10]; char OutImgName[10]; //图像数据长度 int length; //文件指针 FILE* fp; //输入要读取的图像名 cout<<"Enter Image name:"; cin&

  • C++数据精度问题(对浮点数保存指定位小数)

    1.背景 对浮点数保存指定位小数.比如, 1.123456. 要保存1位小数,,调用方法后, 保存的结果为: 1.1. 再比如,1.98765, 保存2位小数的结果为: 2.00. 2. 解决方案 A.添加头文件 #include <sstream> #include <iomanip> B.添加命名空间 using namespace std; C.添加函数 /* 函数名:round /* 函数功能:数据精度计算函数 /* 函数参数:float src:待求精度数 int bit

  • C++将txt文件内容保存到数组的方法

    代码如下: #include<iostream> #include<fstream> //必要头文件 using namespace std; int main() { int a[9][9]; fstream in("E://C//LQB_04data.txt"); //""中是txt文件路径,注意:路径要用//隔开 cin.rdbuf(in.rdbuf()); //将输入信息从控制台转向txt文件 for(int i=0;i<9;i

  • C++将CBitmap类中的图像保存到文件的方法

    本文实例讲述了C++将CBitmap类中的图像保存到文件的方法.分享给大家供大家参考.具体实现方法如下: 使用下面的代码,可以把CBitmap类中的图像保存到图像文件中.支持格式:BMP.JPG.GIF和PNG. void SaveBitmap(CString strFilePath, CBitmap Bitmap) { if ( Bitmap.m_hObject ) { CImage imgTemp; // CImage是MFC中的类. imgTemp.Attach(Bitmap.operat

  • C++保存HBITMAP为位图文件的实现方法

    本文使用C++将位图句柄HBITMAP保存为位图文件,配合C++抓图代码可以实现抓图保存文件(.bmp). 其步骤如下: 1.创建位图文件: 2.计算位图中每个像素所占字节数: 3. 获取位图结构BITMAP: 4.构造位图信息头BITMAPINFOHEADER: 5.构造位图文件头BITMAPFILEHEADER: 6.为位图内容分配内存: 7.处理调色板: 8.写入文件: 9.清除资源. 下面是C++源代码: ImageHelper.h #pragma once   #include <wi

  • Python保存MongoDB上的文件到本地的方法

    本文实例讲述了Python保存MongoDB上的文件到本地的方法.分享给大家供大家参考,具体如下: MongoDB上的文档通过GridFS来操作,Python也可以通过pymongo连接MongoDB数据库,使用pymongo模块的gridfs方法操作文档.以下示例是把MongoDB上GridFS存的excel文档保存到本地. from pymongo import MongoClient import gridfs client = MongoClient('mongodb://usernam

  • 使用hta保存utf8格式的文件的代码

    对于一个web程序员来说,使用hta来处理一些桌面程序功能是比较明智的,这样就还能用我们熟悉的js来进行开发,而不需要掌握新的语言. 平时的网页编辑器,做出来的网页是gb2312编码的,而要实现编码兼容,最好转化为utf8.我们完全可以用hta来做一个批量转换编码的工具,只是,fso不支持保存uft8编码的文件.这样,就需要借助adodb.stream控件了. function saveFile(sUrl,sData){ var oStream oStream=new ActiveXObject

  • Android仿银行客户签名并且保存签名的截图文件并命名为本地时间

    首先需要一个自定义view用来签字使用,可以修改颜色和画笔的粗细,可以擦拭重新画 package com.android.tcm.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Color; import androi

  • python保存二维数组到txt文件中的方法

    一个非常繁琐粗暴的方法,python属于入门级水平,就酱先备份一下,如果有更好的方法再更新 arrs=[[2,15,48,4,5],[6,7,6,4,1],[2,3,6,6,7],[4,6,8,11,2]] ARRS = [] f=open('testARRS.txt','w+') for i in range(4): jointsFrame = arrs[i] #每行 ARRS.append(jointsFrame) for Ji in range(5): strNum = str(joint

  • python3将视频流保存为本地视频文件

    使用python3+opencv3.3.1环境将视频流保存为本地视频文件,具体内容如下 1.利用opencv中的VideoCapture类获取视频流的链接,通过cv2的方法得到该视频流的帧数和每帧大小. 2.使用VideoWriter类进行视频编码 3.通过VideoCapture的read()方法进行视频流解码成每一帧 4.获取到每一帧frame,我们就可以对该帧做图像算法(例如识别.图像加强.灰度变换等) import cv2 from matplotlib import pyplot as

  • python保存数据到本地文件的方法

    1.保存列表为.txt文件 #1/list写入txt ipTable = ['158.59.194.213', '18.9.14.13', '58.59.14.21'] fileObject = open('sampleList.txt', 'w') for ip in ipTable: fileObject.write(ip) fileObject.write('\n') fileObject.close() 2.字典保存 #2/dict写入json import json dictObj =

  • python 实现保存最新的三份文件,其余的都删掉

    我就废话不多说了,直接上代码吧! """ 对于每天存储文件,文件数量过多,占用空间 采用保存最新的三个文件 """ from airflow import DAG from airflow.operators.python_operator import PythonOperator from airflow.models import Variable from sctetl.airflow.utils import dateutils fro

  • TensorFlow实现保存训练模型为pd文件并恢复

    TensorFlow保存模型代码 import tensorflow as tf from tensorflow.python.framework import graph_util var1 = tf.Variable(1.0, dtype=tf.float32, name='v1') var2 = tf.Variable(2.0, dtype=tf.float32, name='v2') var3 = tf.Variable(2.0, dtype=tf.float32, name='v3')

  • Springboot项目保存本地系统日志文件的实现方法

    背景:我们都知道springboot默认日志是打印在控制台中的,不会以文件的形式进行保存.那么日后系统上线肯定是有需要对日志进行定位分析问题的,那么如何实现将控制台输出的日志保存起来? 话不多说,实际效果如下,如果是你预期的那样,咱们接着往下看. 如果最后觉得有所帮助,请不要吝啬你的赞,直接pia的点亮就完事了啦,可好: 如下是集成,按步骤来: 1.在项目的resources目录下创建一个名为logback-spring.xml的日志配置文件,配置文件名最好跟我一样: 2.编写xml文件内容:

随机推荐