MFC中从位图角度旋转图片示例代码

MFC中从位图角度旋转图片示例代码

cpp 复制代码
// 角度宏:0=不旋转,1=顺时针90°,2=顺时针180°,3=顺时针270°
#define ROTATE_0   0
#define ROTATE_90  1
#define ROTATE_180 2
#define ROTATE_270 3

/**
 * @brief 固定角度旋转位图(仅 0/90/180/270 度),纯内存像素操作。
 *
 * 本函数将输入 CBitmap 顺时针旋转到 0/90/180/270 四种角度之一。
 * 内部使用 32bpp 顶向下 DIBSection 做像素搬运,不依赖 MFC 的 CDC。
 *
 * @param pInput  输入位图指针,不能为空。
 * @param nRotate 旋转角度宏:ROTATE_0 / ROTATE_90 / ROTATE_180 / ROTATE_270。
 * @return  旋转后的 CBitmap(内部附加了新的 HBITMAP)。若失败,返回空 CBitmap。
 *
 * @note
 * - 源位图将通过 GetDIBits 转换为 32bpp 顶向下格式进行处理。
 * - 返回值为临时对象时,在老编译器/老 MFC 下可能存在所有权不清风险;
 *   更稳妥的做法是使用带 out 参数的重载(见下文)。
 */
CBitmap RotateBitmap(const CBitmap* pInput, int nRotate)
{
    if (!pInput)
        return CBitmap();

    // 读取源位图信息
    BITMAP bm{};
    if (!pInput->GetBitmap(&bm) || bm.bmWidth <= 0 || bm.bmHeight <= 0)
        return CBitmap();

    // 仅允许 0/1/2/3
    if (nRotate < ROTATE_0 || nRotate > ROTATE_270)
        nRotate = ROTATE_0;

    // --- 创建源 DIBSection(32bpp,顶向下)并填充像素 ---
    BITMAPINFO biSrc{};
    biSrc.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    biSrc.bmiHeader.biWidth       = bm.bmWidth;
    biSrc.bmiHeader.biHeight      = -bm.bmHeight;    // 顶向下
    biSrc.bmiHeader.biPlanes      = 1;
    biSrc.bmiHeader.biBitCount    = 32;
    biSrc.bmiHeader.biCompression = BI_RGB;

    void*    pBitsSrc = nullptr;
    HBITMAP  hDibSrc  = ::CreateDIBSection(nullptr, &biSrc, DIB_RGB_COLORS, &pBitsSrc, nullptr, 0);
    if (!hDibSrc)
        return CBitmap();

    HDC hdc = ::GetDC(nullptr); // 仅用于 GetDIBits
    if (!hdc) {
        ::DeleteObject(hDibSrc);
        return CBitmap();
    }

    const HBITMAP hInput = (HBITMAP)pInput->GetSafeHandle();
    const int gotLines = ::GetDIBits(hdc, hInput, 0, bm.bmHeight, pBitsSrc, &biSrc, DIB_RGB_COLORS);
    ::ReleaseDC(nullptr, hdc);

    if (gotLines == 0) { // 失败
        ::DeleteObject(hDibSrc);
        return CBitmap();
    }

    DWORD* src = static_cast<DWORD*>(pBitsSrc);

    // --- 计算目标尺寸 ---
    int newW = bm.bmWidth;
    int newH = bm.bmHeight;
    if (nRotate == ROTATE_90 || nRotate == ROTATE_270) {
        newW = bm.bmHeight;
        newH = bm.bmWidth;
    }

    // --- 创建目标 DIBSection(32bpp,顶向下) ---
    BITMAPINFO biDst{};
    biDst.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    biDst.bmiHeader.biWidth       = newW;
    biDst.bmiHeader.biHeight      = -newH;
    biDst.bmiHeader.biPlanes      = 1;
    biDst.bmiHeader.biBitCount    = 32;
    biDst.bmiHeader.biCompression = BI_RGB;

    void*   pBitsDst = nullptr;
    HBITMAP hDibDst  = ::CreateDIBSection(nullptr, &biDst, DIB_RGB_COLORS, &pBitsDst, nullptr, 0);
    if (!hDibDst) {
        ::DeleteObject(hDibSrc);
        return CBitmap();
    }
    DWORD* dst = static_cast<DWORD*>(pBitsDst);

    // --- 各角度像素搬运 ---
    switch (nRotate)
    {
    case ROTATE_0:
        // 逐行快速拷贝
        for (int y = 0; y < bm.bmHeight; ++y) {
            ::memcpy(dst + y * newW, src + y * bm.bmWidth, bm.bmWidth * sizeof(DWORD));
        }
        break;

    case ROTATE_90: // x' = H-1-y, y' = x
        for (int y = 0; y < bm.bmHeight; ++y) {
            for (int x = 0; x < bm.bmWidth; ++x) {
                const int x2 = newW - 1 - y; // H-1 - y
                const int y2 = x;
                dst[y2 * newW + x2] = src[y * bm.bmWidth + x];
            }
        }
        break;

    case ROTATE_180: // x' = W-1-x, y' = H-1-y
        for (int y = 0; y < bm.bmHeight; ++y) {
            for (int x = 0; x < bm.bmWidth; ++x) {
                const int x2 = newW - 1 - x;   // W-1 - x
                const int y2 = newH - 1 - y;  // H-1 - y
                dst[y2 * newW + x2] = src[y * bm.bmWidth + x];
            }
        }
        break;

    case ROTATE_270: // x' = y, y' = W-1-x
        for (int y = 0; y < bm.bmHeight; ++y) {
            for (int x = 0; x < bm.bmWidth; ++x) {
                const int x2 = y;
                const int y2 = bm.bmWidth - 1 - x; // W-1 - x
                dst[y2 * newW + x2] = src[y * bm.bmWidth + x];
            }
        }
        break;
    }

    // 清理源 DIB
    ::DeleteObject(hDibSrc);

    // 封装返回
    CBitmap bmpDst;
    bmpDst.Attach(hDibDst);
    return bmpDst; // 注意:按值返回在老 MFC 下可能有所有权语义风险,见注记
}


/**
 * @brief 固定角度旋转位图(0/90/180/270),结果输出到 out,规避按值返回风险。
 * @return TRUE 成功,FALSE 失败
 */
BOOL RotateBitmap(const CBitmap* pInput, int nRotate, CBitmap& out)
{
    CBitmap tmp = RotateBitmap(pInput, nRotate);
    if (tmp.GetSafeHandle() == nullptr)
        return FALSE;

    // 把句柄"转移"给 out,避免双重释放
    out.Attach((HBITMAP)tmp.Detach());
    return TRUE;
}
相关推荐
兵哥工控3 小时前
mfc最简单自定义消息投递实例
c++·mfc·postmessage
hetao173383712 小时前
2025-12-12~14 hetao1733837的刷题笔记
数据结构·c++·笔记·算法
椰子今天很可爱12 小时前
五种I/O模型与多路转接
linux·c语言·c++
程序员zgh12 小时前
C++ 互斥锁、读写锁、原子操作、条件变量
c语言·开发语言·jvm·c++
獭.獭.14 小时前
C++ -- STL【unordered_set和unordered_map的使用】
c++·stl·unordered_map·unordered_set
star _chen15 小时前
C++ std::move()详解:从小白到高手
开发语言·c++
福尔摩斯张15 小时前
C++核心特性精讲:从C语言痛点出发,掌握现代C++编程精髓(超详细)
java·linux·c语言·数据结构·c++·驱动开发·算法
charlie11451419116 小时前
如何快速在 VS2026 上使用 C++ 模块 — 完整上手指南
开发语言·c++·笔记·学习·现代c++
报错小能手16 小时前
STL_unordered_map
开发语言·c++·哈希算法