zoukankan      html  css  js  c++  java
  • BMP位图之代码实现

    从16位开始,不存在调色板,顶多存在一个RGBQUAD的掩码。

    16位位图,我没有拿到对应的素材,但是根据官方文档的描述和代码验证后,我总结为下:

    当biCompression为BI_RGB时,此时是RGB555格式,不存在调色板。

    当biCompression为BI_BITFIELDS时,16位位图时RGB565格式,对应的32位是带掩码的格式,两种都有一个RGBQUAD的数据存在于调色板。

    24位位图,只有BI_RGB存储方式。

    代码实现如下

    enum { bitmap_undefined, bitmap_unknown, bitmap1, bitmap4, bitmap4_RLE4,
        bitmap8, bitmap8_RLE8, bitmap16_RGB555, bitmap16_RGB565, bitmap24, bitmap32, bitmap32_mask};//所有bmp类型
    
    
    class Bitmap {
    public:
        Bitmap();
        virtual ~Bitmap();
        HBITMAP BitCreate(HDC hDC, LPTSTR szFilename);//从文件载入
        HBITMAP BitCreate(HDC hDC, HINSTANCE hInstance, UINT rscID);//从资源载入
        PBITMAPFILEHEADER GetBitFileheader(PBYTE pBitmap = NULL);//位图头
        PBITMAPINFOHEADER GetBitInfoheader(PBYTE pBitmap = NULL);//位图INFO结构
        LPRGBQUAD GetBitPalette(PBYTE pBitmap = NULL);//位图画板,不存在返回NULL
        PVOID GetBitData(PBYTE pBitmap = NULL);//位图数据
        void BitDraw(HDC hDC, int x, int y, HBITMAP hBitmap);//将位图画到自己的窗口
    protected:
        void BitErrorshow(DWORD errorID);//错误提示
        void BitTypedefined();//类型定义
        void BitFree();//资源释放
        HBITMAP BitLoad(HDC hDC, PBYTE pBitmap = NULL);//载入的数据,转换为HBITMAP句柄,方便操作
    private:
        HGLOBAL m_hGlablebitmap;
        HANDLE m_hFilemapping;
        PBYTE m_pBitmap;
        int m_iWidth, m_iHeight, m_iFilesize;
        int m_iType;
    };

    对应的实现代码

    Bitmap::Bitmap() {
        m_hFilemapping = m_hGlablebitmap = NULL;
        m_pBitmap = NULL;
        m_iFilesize = m_iWidth = m_iHeight = 0;
        m_iType = bitmap_undefined;
    }
    
    Bitmap::~Bitmap() {
        BitFree();
    }
    
    void Bitmap::BitTypedefined() {
        PBITMAPINFOHEADER bInfoheader;
        bInfoheader = GetBitInfoheader();
        m_iWidth = bInfoheader->biWidth;
        m_iHeight = bInfoheader->biHeight;
        WORD bitCount = bInfoheader->biBitCount;
        DWORD bitCompression = bInfoheader->biCompression;
        if (bitCompression == BI_RGB) {
            switch (bitCount) {
            case 1:
                m_iType = bitmap1; break;
            case 4:
                m_iType = bitmap4; break;
            case 8:
                m_iType = bitmap8; break;
            case 16:
                m_iType = bitmap16_RGB555; break;
            case 24:
                m_iType = bitmap24; break;
            case 32:
                m_iType = bitmap32; break;
            default:
                m_iType = bitmap_unknown;
            }
        }
        else if (bitCompression == BI_BITFIELDS) {
            switch (bitCount) {
            case 16:
                m_iType = bitmap16_RGB565; break;
            case 32:
                m_iType = bitmap32_mask; break;
            default:
                m_iType = bitmap_unknown;
            }
        }
        else if (bitCompression == BI_RLE4)
            m_iType = bitmap4_RLE4;
        else if (bitCompression == BI_RLE8)
            m_iType = bitmap8_RLE8;
        else
            m_iType = bitmap_unknown;
    }
    
    HBITMAP Bitmap::BitLoad(HDC hDC, PBYTE pBitmap) {
        PBITMAPINFOHEADER pBitmapinfo = GetBitInfoheader(pBitmap);
        PBYTE pBitmapdata = (PBYTE)GetBitData(pBitmap), pDIBData = NULL;
        HBITMAP hBitmap = CreateDIBSection(hDC, (PBITMAPINFO)pBitmapinfo, DIB_RGB_COLORS, (void **)&pDIBData,
            NULL, 0);
        DWORD sizeImage = m_iFilesize - (DWORD)(pBitmapdata - pBitmap);//永远自己计算数据大小,因为位图INFO头中的biSizeImage字段可能为0.
        CopyMemory(pDIBData, pBitmapdata, sizeImage);
        return hBitmap;
    }
    
    void Bitmap::BitErrorshow(DWORD errorID) {
        TCHAR szCaption[64];
        LPVOID lpMsgBuf;
        wsprintf(szCaption, L"错误代码:0x%08x", errorID);
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            errorID,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
            (LPTSTR)&lpMsgBuf,
            0, NULL);
        MessageBox(NULL, (LPTSTR)lpMsgBuf, szCaption, MB_OK | MB_ICONSTOP);
        LocalFree(lpMsgBuf);
    }
    
    HBITMAP Bitmap::BitCreate(HDC hDC, LPTSTR szFilename) {
        HANDLE hFile = NULL;
        BitFree();//释放之前数据
        __try {
            hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            m_hFilemapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
            m_pBitmap = (PBYTE)MapViewOfFile(m_hFilemapping, FILE_MAP_READ, 0, 0, 0);
            m_iFilesize = GetFileSize(hFile, 0);
            BitTypedefined();
        }__except (EXCEPTION_EXECUTE_HANDLER) {
            BitErrorshow(GetLastError());
            CloseHandle(hFile);
            BitFree();
            return NULL;
        }
        CloseHandle(hFile);
        return BitLoad(hDC, m_pBitmap);
    }
    
    HBITMAP Bitmap::BitCreate(HDC hDC, HINSTANCE hInstance, UINT rscID) {
        HRSRC hResInfo = NULL;
        BitFree();//释放之前数据
        __try {
            hResInfo = FindResource(hInstance, MAKEINTRESOURCE(rscID), RT_BITMAP);
            m_hGlablebitmap = LoadResource(hInstance, hResInfo);
            m_pBitmap = (PBYTE)LockResource(m_hGlablebitmap);
            m_iFilesize = SizeofResource(hInstance, hResInfo);
            BitTypedefined();
        }__except (EXCEPTION_EXECUTE_HANDLER) {
            BitErrorshow(GetLastError());
            BitFree();
            return NULL;
        }
        return BitLoad(hDC, m_pBitmap);
    }
    
    void Bitmap::BitFree() {
        if (m_hFilemapping != NULL) {
            UnmapViewOfFile(m_pBitmap);
            CloseHandle(m_hFilemapping);
            m_hFilemapping = NULL;
        }
        else if (m_hGlablebitmap != NULL) {
            UnlockResource(m_hGlablebitmap);
            FreeResource(m_hGlablebitmap);
            m_hGlablebitmap = NULL;
        }
        m_pBitmap = NULL;
        m_iType = bitmap_undefined;
        m_iFilesize = m_iHeight = m_iWidth = 0;
    }
    
    PBITMAPFILEHEADER Bitmap::GetBitFileheader(PBYTE pBitmap) {
        if (m_hFilemapping != NULL)
            return pBitmap ? (PBITMAPFILEHEADER)pBitmap : (PBITMAPFILEHEADER)m_pBitmap;
        return NULL;
    }
    
    PBITMAPINFOHEADER Bitmap::GetBitInfoheader(PBYTE pBitmap) {
        DWORD offset = 0;
        if (m_hFilemapping != NULL) 
            offset = sizeof(BITMAPFILEHEADER);
        return pBitmap ? (PBITMAPINFOHEADER)(pBitmap + offset) : (PBITMAPINFOHEADER)(m_pBitmap + offset);
    }
    
    LPRGBQUAD Bitmap::GetBitPalette(PBYTE pBitmap) {
        PBITMAPINFOHEADER pBitmapinfo = GetBitInfoheader(pBitmap);
        PBYTE pPalette = (PBYTE)pBitmapinfo + sizeof(PBITMAPINFOHEADER), pData = (PBYTE)GetBitData(pBitmap);
        if (pPalette == pData)//不存在调色板
            return NULL;
        return (LPRGBQUAD)pPalette;
    }
    
    PVOID Bitmap::GetBitData(PBYTE pBitmap) {
        DWORD offset = 0, n;
        PBITMAPINFOHEADER pBitmapinfo = GetBitInfoheader(pBitmap);
        n = pBitmapinfo->biClrUsed ? pBitmapinfo->biClrUsed : pBitmapinfo->biBitCount;
        switch (m_iType) {
        case bitmap1:
        case bitmap4:
        case bitmap4_RLE4:
        case bitmap8:
        case bitmap8_RLE8:
            offset = (DWORD)pow(2, n); break;
        case bitmap16_RGB565:
        case bitmap32_mask:
            offset = 1; break;
        }
        return (PBYTE)pBitmapinfo + offset * sizeof(RGBQUAD)+sizeof (BITMAPINFOHEADER);
    }
    
    void Bitmap::BitDraw(HDC hDC, int x, int y, HBITMAP hBitmap){
        if (hBitmap != NULL) {
            HDC hMemDC = CreateCompatibleDC(hDC);
            HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);//载入位图
            BitBlt(hDC, x, y, m_iWidth, m_iHeight, hMemDC, 0, 0, SRCCOPY);
            SelectObject(hMemDC, hOldBitmap);//还原位图
            DeleteDC(hMemDC);
        }
    }

    代码测试图

    1位位图:

    4位位图

    8位位图

    24位位图

    其他位图可以随意测试,均无问题。图片是我随意弄的,哈哈哈,自己用windows自带的画图工具就可以做出不同类型的位图,这里就不上传位图资源文件了。

  • 相关阅读:
    VirtualBox 下USB 设备加载的步骤及无法加载的解决办法
    浅析:setsockopt()改善socket网络程序的健壮性
    减小Gcc编译程序的体积
    linux下查看系统进程占用的句柄数
    Linux下高并发socket最大连接数所受的各种限制
    spring-jpa通过自定义sql执行修改碰到的问题
    阿里巴巴Java开发手册中的DO、DTO、BO、AO、VO、POJO定义
    sql select时增加常量列
    CASE WHEN 及 SELECT CASE WHEN的用法
    MYSQL常见运算符和函数
  • 原文地址:https://www.cnblogs.com/dalgleish/p/9575651.html
Copyright © 2011-2022 走看看