zoukankan      html  css  js  c++  java
  • win32

    虽然标题中标有GDI+,但其实真正实施的时候并没有用到。

    不过GDI+的相关文档有一些关于高斯模糊的api说明,见下面链接:

         使用Blur类,你可以将高斯模糊效果应用于位图并指定模糊的性质。Blur对象的地址传递Graphics :: DrawImage方法或Bitmap :: ApplyEffect方法。若要指定模糊的性质,请将BlurParams结构传递Blur对象Blur :: SetParameters方法

    一般来说,上面的类封装了模糊的算法,所以我下面贴的代码是直接用算法来模糊位图的。

    C++ code:

    #define _USE_MATH_DEFINES
    #include <cmath>
    #include <iostream>
    #include <fstream>
    
    #define NOMINMAX
    #if defined(_WIN32) || defined(_WIN64)
    #include <windows.h>
    #endif
    
    #ifndef max
    #define max(a,b)            (((a) > (b)) ? (a) : (b))
    #endif
    
    #ifndef min
    #define min(a,b)            (((a) < (b)) ? (a) : (b))
    #endif
    
    typedef struct
    {
        uint8_t r, g, b, a;
    } rgb32;
    
    
    #if !defined(_WIN32) && !defined(_WIN64)
    #pragma pack(2)
    typedef struct
    {
        uint16_t bfType;
        uint32_t bfSize;
        uint16_t bfReserved1;
        uint16_t bfReserved2;
        uint32_t bfOffBits;
    } BITMAPFILEHEADER;
    #pragma pack()
    
    
    #pragma pack(2)
    typedef struct
    {
        uint32_t biSize;
        int32_t biWidth;
        int32_t biHeight;
        uint16_t biPlanes;
        uint16_t biBitCount;
        uint32_t biCompression;
        uint32_t biSizeImage;
        int16_t biXPelsPerMeter;
        int16_t biYPelsPerMeter;
        uint32_t biClrUsed;
        uint32_t biClrImportant;
    } BITMAPINFOHEADER;
    #pragma pack()
    #endif
    
    #pragma pack(2)
    typedef struct
    {
        BITMAPFILEHEADER bfh;
        BITMAPINFOHEADER bih;
    } BMPINFO;
    #pragma pack()
    
    
    class bitmap
    {
    private:
        BMPINFO bmpInfo;
        uint8_t* pixels;
    
    public:
        bitmap(const char* path);
        ~bitmap();
    
        void save(const char* path, uint16_t bit_count = 24);
    
        rgb32* getPixel(uint32_t x, uint32_t y) const;
        void setPixel(rgb32* pixel, uint32_t x, uint32_t y);
    
        uint32_t getWidth() const;
        uint32_t getHeight() const;
        uint16_t bitCount() const;
    };
    
    bitmap::bitmap(const char* path) : bmpInfo(), pixels(nullptr)
    {
        std::ifstream file(path, std::ios::in | std::ios::binary);
    
        if (file)
        {
            file.read(reinterpret_cast<char*>(&bmpInfo.bfh), sizeof(bmpInfo.bfh));
    
            if (bmpInfo.bfh.bfType != 0x4d42)
            {
                throw std::runtime_error("Invalid format. Only bitmaps are supported.");
            }
    
            file.read(reinterpret_cast<char*>(&bmpInfo.bih), sizeof(bmpInfo.bih));
    
            if (bmpInfo.bih.biCompression != 0)
            {
                std::cerr << bmpInfo.bih.biCompression << "
    ";
                throw std::runtime_error("Invalid bitmap. Only uncompressed bitmaps are supported.");
            }
    
            if (bmpInfo.bih.biBitCount != 24 && bmpInfo.bih.biBitCount != 32)
            {
                throw std::runtime_error("Invalid bitmap. Only 24bit and 32bit bitmaps are supported.");
            }
    
            file.seekg(bmpInfo.bfh.bfOffBits, std::ios::beg);
    
            pixels = new uint8_t[bmpInfo.bfh.bfSize - bmpInfo.bfh.bfOffBits];
            file.read(reinterpret_cast<char*>(&pixels[0]), bmpInfo.bfh.bfSize - bmpInfo.bfh.bfOffBits);
    
    
            uint8_t* temp = new uint8_t[bmpInfo.bih.biWidth * bmpInfo.bih.biHeight * sizeof(rgb32)];
    
            uint8_t* in = pixels;
            rgb32* out = reinterpret_cast<rgb32*>(temp);
            int padding = bmpInfo.bih.biBitCount == 24 ? ((bmpInfo.bih.biSizeImage - bmpInfo.bih.biWidth * bmpInfo.bih.biHeight * 3) / bmpInfo.bih.biHeight) : 0;
    
            for (int i = 0; i < bmpInfo.bih.biHeight; ++i, in += padding)
            {
                for (int j = 0; j < bmpInfo.bih.biWidth; ++j)
                {
    
                    out->b = *(in++);
                    out->g = *(in++);
                    out->r = *(in++);
                    out->a = bmpInfo.bih.biBitCount == 32 ? *(in++) : 0xFF;
                    ++out;
                }
            }
    
            delete[] pixels;
            pixels = temp;
        }
    }
    
    bitmap::~bitmap()
    {
        delete[] pixels;
    }
    
    void bitmap::save(const char* path, uint16_t bit_count)
    {
        std::ofstream file(path, std::ios::out | std::ios::binary);
    
        if (file)
        {
            bmpInfo.bih.biBitCount = bit_count;
            uint32_t size = ((bmpInfo.bih.biWidth * bmpInfo.bih.biBitCount + 31) / 32) * 4 * bmpInfo.bih.biHeight;
            bmpInfo.bfh.bfSize = bmpInfo.bfh.bfOffBits + size;
    
            file.write(reinterpret_cast<char*>(&bmpInfo.bfh), sizeof(bmpInfo.bfh));
            file.write(reinterpret_cast<char*>(&bmpInfo.bih), sizeof(bmpInfo.bih));
            file.seekp(bmpInfo.bfh.bfOffBits, std::ios::beg);
    
            uint8_t* out = NULL;
            rgb32* in = reinterpret_cast<rgb32*>(pixels);
            uint8_t* temp = out = new uint8_t[bmpInfo.bih.biWidth * bmpInfo.bih.biHeight * sizeof(rgb32)];
            int padding = bmpInfo.bih.biBitCount == 24 ? ((bmpInfo.bih.biSizeImage - bmpInfo.bih.biWidth * bmpInfo.bih.biHeight * 3) / bmpInfo.bih.biHeight) : 0;
    
            for (int i = 0; i < bmpInfo.bih.biHeight; ++i, out += padding)
            {
                for (int j = 0; j < bmpInfo.bih.biWidth; ++j)
                {
                    *(out++) = in->b;
                    *(out++) = in->g;
                    *(out++) = in->r;
    
                    if (bmpInfo.bih.biBitCount == 32)
                    {
                        *(out++) = in->a;
                    }
                    ++in;
                }
            }
    
            file.write(reinterpret_cast<char*>(&temp[0]), size); //bmpInfo.bfh.bfSize - bmpInfo.bfh.bfOffBits
            delete[] temp;
        }
    }
    
    rgb32* bitmap::getPixel(uint32_t x, uint32_t y) const
    {
        rgb32* temp = reinterpret_cast<rgb32*>(pixels);
        return &temp[(bmpInfo.bih.biHeight - 1 - y) * bmpInfo.bih.biWidth + x];
    }
    
    void bitmap::setPixel(rgb32* pixel, uint32_t x, uint32_t y)
    {
        rgb32* temp = reinterpret_cast<rgb32*>(pixels);
        memcpy(&temp[(bmpInfo.bih.biHeight - 1 - y) * bmpInfo.bih.biWidth + x], pixel, sizeof(rgb32));
    };
    
    uint32_t bitmap::getWidth() const
    {
        return bmpInfo.bih.biWidth;
    }
    
    uint32_t bitmap::getHeight() const
    {
        return bmpInfo.bih.biHeight;
    }
    
    uint16_t bitmap::bitCount() const
    {
        return bmpInfo.bih.biBitCount;
    }
    
    void apply_blur(int x, int y, bitmap* bmp, int blurRadius)
    {
        double blurValue = 0.111;
        int r = 0;
        int g = 0;
        int b = 0;
    
        for (int k = y - blurRadius; k <= blurRadius; ++k)
        {
            for (int l = x - blurRadius; l <= blurRadius; ++l)
            {
                rgb32* pixel = bmp->getPixel(l, k);
                r += blurValue * pixel->r;
                g += blurValue * pixel->g;
                b += blurValue * pixel->b;
            }
        }
    
        rgb32 pixel = *bmp->getPixel(x, y);
    
        pixel.r = r;
        pixel.g = g;
        pixel.b = b;
    
        bmp->setPixel(&pixel, x, y);
    }
    void blur(bitmap* bmp, int radius);
    
    int main(int argc, const char* argv[])
    {
        bitmap bmp{ "C:\Users\strives\Desktop\new_2.bmp" };
        blur(&bmp, 5);
        bmp.save("C:\Users\strives\Desktop\blurred-panda.bmp");
        return 0;
    }
    
    void blur(bitmap* bmp, int radius)
    {
        float rs = ceil(radius * 2.57);
        for (int i = 0; i < bmp->getHeight(); ++i)
        {
            for (int j = 0; j < bmp->getWidth(); ++j)
            {
                double r = 0, g = 0, b = 0;
                double count = 0;
    
                for (int iy = i - rs; iy < i + rs + 1; ++iy)
                {
                    for (int ix = j - rs; ix < j + rs + 1; ++ix)
                    {
                        auto x = min(static_cast<int>(bmp->getWidth()) - 1, max(0, ix));
                        auto y = min(static_cast<int>(bmp->getHeight()) - 1, max(0, iy));
    
                        auto dsq = ((ix - j) * (ix - j)) + ((iy - i) * (iy - i));
                        auto wght = std::exp(-dsq / (2.0 * radius * radius)) / (M_PI * 2.0 * radius * radius);
    
                        rgb32* pixel = bmp->getPixel(x, y);
    
                        r += pixel->r * wght;
                        g += pixel->g * wght;
                        b += pixel->b * wght;
                        count += wght;
                    }
                }
    
                rgb32* pixel = bmp->getPixel(j, i);
                pixel->r = std::round(r / count);
                pixel->g = std::round(g / count);
                pixel->b = std::round(b / count);
            }
        }
    }

    当然,这些代码是搬得so论坛的,放在此处也是用于以后工作上的参考,毕竟墙的厉害。

    如果想制作位图的蒙版,参考: MaskBlt

    也可以使用原始的BitBlt进行颜色的位与操作,见下面案例:

    一些其他文档可以学习:

  • 相关阅读:
    复杂模拟 | 1017 模拟N个顾客M个柜台进行排队
    徒手实现lower_bound和upper_bound
    树状数组 | 1057
    动态规划 | 最长回文子串 1040
    动态规划 | 背包问题 1068
    动态规划 | 对输入进行hash处理的LIS 1045
    总结那些有默认margin,padding值的html标签
    javascript 的七种基本数据类型
    牛客网笔试题整理
    JavaScript 的数据结构与算法
  • 原文地址:https://www.cnblogs.com/strive-sun/p/14633584.html
Copyright © 2011-2022 走看看