C++实现屏幕反色

目录

方法一:

方法二:


方法二常用一点。


效果:

如图

方法一:

思路:获取屏幕图像,反色后,设置为壁纸。

头文件:#include <windows.h>

#include <vector.h>
#include <cstdio>
#include <string>
#include <tchar.h>

代码:(调用Screenshot反转颜色)



BOOL GetHDCData(HDC hdc, const RECT& rcDC, std::vector<BYTE>& vtBuf)
{
    BOOL bRes = FALSE;
    HBITMAP hBmp = NULL;
    HDC hdcMem = NULL;

    __try
    {
        //Initilaize the bitmap information	
        BITMAPINFO bmpInfo = { 0 };
        bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmpInfo.bmiHeader.biWidth = rcDC.right - rcDC.left;
        bmpInfo.bmiHeader.biHeight = rcDC.bottom - rcDC.top;
        bmpInfo.bmiHeader.biPlanes = 1;
        bmpInfo.bmiHeader.biBitCount = 24;

        //Create the compatible DC to get the data
        hdcMem = CreateCompatibleDC(hdc);
        if (hdcMem == NULL)
        {
            //ASSERT(FALSE);
            //RETAILMSG(TRUE,(TEXT("CreateCompatibleDC failed! Error Code:0x%x\r\n"),GetLastError()));
            __leave;
        }

        //Get the data from the memory DC	
        BYTE* pData = NULL;
        hBmp = CreateDIBSection(hdcMem, &bmpInfo, DIB_RGB_COLORS, reinterpret_cast<VOID**>(&pData), NULL, 0);
        if (hBmp == NULL)
        {
            //ASSERT(FALSE);
            //RETAILMSG(TRUE,(TEXT("CreateDIBSection failed! Error Code:0x%x\r\n"),GetLastError()));
            __leave;
        }
        HGDIOBJ hOldObj = SelectObject(hdcMem, hBmp);

        //Draw to the memory DC
        SIZE sizeImg = { bmpInfo.bmiHeader.biWidth,bmpInfo.bmiHeader.biHeight };
        SIZE sizeDC = { rcDC.right - rcDC.left,rcDC.bottom - rcDC.top };
        StretchBlt(hdcMem,
            0,
            0,
            sizeImg.cx,
            sizeImg.cy,
            hdc,
            rcDC.left,
            rcDC.top,
            sizeDC.cx,
            sizeDC.cy,
            SRCCOPY);


        vtBuf.resize(sizeImg.cx * sizeImg.cy * 3);
        memcpy(&vtBuf[0], pData, vtBuf.size());

        SelectObject(hdcMem, hOldObj);

        bRes = TRUE;

    }
    __finally
    {

        if (hBmp != NULL)
        {
            DeleteObject(hBmp);
        }

        if (hdcMem != NULL)
        {
            DeleteDC(hdcMem);
        }
    }

    return bRes;
}


// 保存HDC为BMP文件
BOOL WriteBmp(const string strFile, HDC hdc, const RECT& rcDC)
{
    std::vector<BYTE> vtData;
    if (GetHDCData(hdc, rcDC, vtData) == FALSE)
    {
        return FALSE;
    }

    SIZE sizeImg = { rcDC.right - rcDC.left,rcDC.bottom - rcDC.top };

    BITMAPINFOHEADER bmInfoHeader = { 0 };
    bmInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmInfoHeader.biWidth = sizeImg.cx;
    bmInfoHeader.biHeight = sizeImg.cy;
    bmInfoHeader.biPlanes = 1;
    bmInfoHeader.biBitCount = 24;

    //Bimap file header in order to write bmp file
    BITMAPFILEHEADER bmFileHeader = { 0 };
    bmFileHeader.bfType = 0x4d42;  //bmp  
    bmFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    bmFileHeader.bfSize = bmFileHeader.bfOffBits + ((bmInfoHeader.biWidth * bmInfoHeader.biHeight) * 3); ///3=(24 / 8)

    HANDLE hFile = CreateFile(C2LW(strFile.c_str()), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }

    DWORD dwWrite = 0;
    WriteFile(hFile, &bmFileHeader, sizeof(BITMAPFILEHEADER), &dwWrite, NULL);
    WriteFile(hFile, &bmInfoHeader, sizeof(BITMAPINFOHEADER), &dwWrite, NULL);
    WriteFile(hFile, &vtData[0], vtData.size(), &dwWrite, NULL);


    CloseHandle(hFile);

    return TRUE;
}

int InvertImage(const char* srcImage, const char* destIMage, int iFlag)
{
    BITMAPFILEHEADER bmfHeader;
    BITMAPINFOHEADER bmiHeader;
    int i;

    FILE* pFile;
    if ((pFile = fopen(srcImage, "rb")) == NULL)
    {
        printf("open bmp file error.");
        exit(-1);
    }

    //读取文件和Bitmap头信息
    fseek(pFile, 0, SEEK_SET);
    fread(&bmfHeader, sizeof(BITMAPFILEHEADER), 1, pFile);
    fread(&bmiHeader, sizeof(BITMAPINFOHEADER), 1, pFile);

    //先不支持小于16位的位图
    int bitCount = bmiHeader.biBitCount;
    if (bitCount < 16)
    {
        printf("Image format is error!");
        exit(-1);
    }

    int srcW = bmiHeader.biWidth;//宽度,多少像素点
    int srcH = bmiHeader.biHeight;//高度

    int lineSize = bitCount * srcW / 8;
    //偏移量,windows系统要求每个扫描行按四字节对齐
    //int alignBytes = ((bmiHeader.biWidth * bitCount + 31) & ~31) / 8L
        //- bmiHeader.biWidth * bitCount / 8L;
    int srcLine = ((srcW * bitCount + 31) / 32) * 4;
    //int srcBufLine = srcLine * srcH;

    int srcBufSize = srcLine * srcH;

    BYTE* srcBuf = (BYTE*)malloc(srcBufSize);
    if (!srcBuf) {
        printf("Malloc memory fail!");
        exit(-1);
    }

    for (i = 0; i < srcH; i++) {
        fread(&srcBuf[i * srcLine], srcLine, 1, pFile);
        //fseek(pFile, alignBytes, SEEK_CUR);
    }

    //iFlag equal 1 表示灰度
    if (iFlag) {
        for (i = 0; i < srcH; i++) {
            for (int j = 0; j < srcW; j++) {
                int k = (srcBuf[i * srcLine + j * bitCount / 8 + 0] +
                    srcBuf[i * srcLine + j * bitCount / 8 + 1] +
                    srcBuf[i * srcLine + j * bitCount / 8 + 2]) / 3;

                srcBuf[i * srcLine + j * bitCount / 8 + 0] = k;
                srcBuf[i * srcLine + j * bitCount / 8 + 1] = k;
                srcBuf[i * srcLine + j * bitCount / 8 + 2] = k;
            }
        }
    }
    else {//反色
        for (i = 0; i < srcH; i++) {
            for (int j = 0; j < srcW; j++) {
                for (int k = 0; k < 3; k++) {
                    srcBuf[i * srcLine + j * bitCount / 8 + k] =
                        abs(srcBuf[i * srcLine + j * bitCount / 8 + k] - 255);
                }
            }
        }
    }


    HFILE hfile = _lcreat(destIMage, 0);

    //写入文件头信息
    _lwrite(hfile, (LPCSTR)&bmfHeader, sizeof(BITMAPFILEHEADER));
    //写入Bitmap头信息
    _lwrite(hfile, (LPCSTR)&bmiHeader, sizeof(BITMAPINFOHEADER));
    //写入图像数据
    _lwrite(hfile, (LPCSTR)srcBuf, srcBufSize);
    _lclose(hfile);
    fclose(pFile);
    free(srcBuf);
    
    return 0;
}




enum WallpaperStyle
{
    Tile,//平铺
    Center,//居中
    Stretch,//拉伸
    Fit, //适应
    Fill//填充
};


HRESULT SetDesktopWallpaper(LPCSTR pszFile, WallpaperStyle style)
{
    HRESULT hr = S_OK;

    //设置壁纸风格和展开方式
    //在Control Panel\Desktop中的两个键值将被设置
    // TileWallpaper
    //  0: 图片不被平铺 
    //  1: 被平铺 
    // WallpaperStyle
    //  0:  0表示图片居中,1表示平铺
    //  2:  拉伸填充整个屏幕
    //  6:  拉伸适应屏幕并保持高度比
    //  10: 图片被调整大小裁剪适应屏幕保持纵横比

    //以可读可写的方式打开HKCU\Control Panel\Desktop注册表项
    HKEY hKey = NULL;
    
    //更改注册表以更改展开方式
    hr = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CURRENT_USER,
 _T("Control Panel\\Desktop"), 0, KEY_READ | KEY_WRITE, &hKey));
    if (SUCCEEDED(hr))
    {
        LPCSTR pszWallpaperStyle = "2";
        LPCSTR pszTileWallpaper = "0";

        switch (style)
        {
        case Tile:
            pszWallpaperStyle = "0";
            pszTileWallpaper = "1";
            break;

        case Center:
            pszWallpaperStyle = "0";
            pszTileWallpaper = "0";
            break;

        case Stretch:
            pszWallpaperStyle = "2";
            pszTileWallpaper = "0";
            break;

        case Fit: // (Windows 7 and later)
            pszWallpaperStyle = "6";
            pszTileWallpaper = "0";
            break;

        case Fill: // (Windows 7 and later)
            pszWallpaperStyle = "10";
            pszTileWallpaper = "0";
            break;
        }
        // 设置 WallpaperStyle 和 TileWallpaper 到注册表项.
        DWORD cbData = lstrlen(pszWallpaperStyle) * sizeof(*pszWallpaperStyle);
        hr = HRESULT_FROM_WIN32(RegSetValueExA(hKey, "WallpaperStyle", 0, REG_SZ,
 reinterpret_cast<const BYTE*>(pszWallpaperStyle), cbData));
        if (SUCCEEDED(hr))
        {
            cbData = lstrlen(pszTileWallpaper) * sizeof(*pszTileWallpaper);
            hr = HRESULT_FROM_WIN32(RegSetValueExA(hKey, "TileWallpaper", 0, REG_SZ,
 reinterpret_cast<const BYTE*>(pszTileWallpaper) , cbData));
        }

        RegCloseKey(hKey);
    }

    if (SUCCEEDED(hr))
    {
        //调用windows api函数实现更改壁纸
        if (!SystemParametersInfo(SPI_SETDESKWALLPAPER, 0,(PVOID)pszFile, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE))
        {
            hr = HRESULT_FROM_WIN32(GetLastError());
        }
    }

    return hr;
}





void Screenshot() {

    DeleteFileA(_T("C:\\1.bmp"));
    DeleteFileA(_T("C:\\2.bmp"));

    HDC hdc1 = CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
    RECT szrc1 = { 0,0,GetDeviceCaps(hdc,HORZRES),GetDeviceCaps(hdc,VERTRES) };
    WriteBmp("C:\\1.bmp", hdc1, szrc1);
    InvertImage("C:\\1.bmp", "C:\\2.bmp", 0);//将1.bmp反色,得到2.bmp

    DeleteDC(hdc);
    Sleep(100);
    SetDesktopWallpaper("C:\\2.bmp", Stretch);//设置壁纸为2.bmp

    SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (PVOID)_T("C:\\2.bmp"), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
    

}

方法二:

将屏幕颜色反转,包括所有窗口。

void InvertColor() {
    HDC hdc = GetDC(0);
    BitBlt(hdc, 0, 0, cx, cy, hdc, 0, 0, NOTSRCCOPY);
}

是不是很简单?但是容易被刷新掉。

VS2019环境下编译运行成功。


版权声明:本文为larwar原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。