C++ BYTE* 数组转 JPEG 图像 (libjpeg)

问题描述 投票:0回答:1

我正在尝试编写一个用于在外部服务器上存储屏幕截图的应用程序,但由于资源有限,我想以文本形式存储它们,特别是作为 BYTE* 数组。因此,我在读取上传到服务器的屏幕截图时遇到了一些问题。我可以随时在计算机上读取并保存在会话期间拍摄的任何屏幕截图,但我朋友拍摄的屏幕截图被创建为没有内容的 0kb 文件,并导致应用程序在执行负责扫描行的函数期间崩溃。 .

LPBYTE SaveScreenshotNew()
{
    int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
    int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);

    HDC hdcScreen = GetDC(NULL);
    HDC hdcMem = CreateCompatibleDC(hdcScreen);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, nScreenWidth, nScreenHeight);
    SelectObject(hdcMem, hBitmap);
    BitBlt(hdcMem, 0, 0, nScreenWidth, nScreenHeight, hdcScreen, 0, 0, SRCCOPY);

    int bufferSize = nScreenWidth * nScreenHeight * 3;
    LPBYTE buffer = new BYTE[bufferSize];

    BITMAPINFOHEADER bi;
    memset(&bi, 0, sizeof(BITMAPINFOHEADER));
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = nScreenWidth;
    bi.biHeight = -nScreenHeight;
    bi.biPlanes = 1;
    bi.biBitCount = 24;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;

    if (GetDIBits(hdcScreen, hBitmap, 0, nScreenHeight, buffer, (BITMAPINFO*)&bi, DIB_RGB_COLORS) != 0) {
        for (int i = 0; i < nScreenHeight; i++) {
            for (int j = 0; j < nScreenWidth; j++) {
                int index = i * nScreenWidth * 3 + j * 3;
                BYTE blue = buffer[index];
                buffer[index] = buffer[index + 2];
                buffer[index + 2] = blue;
            }
        }
    }

    DeleteObject(hBitmap);
    DeleteDC(hdcMem);
    ReleaseDC(NULL, hdcScreen);

    return buffer;
}

jpeglib 代码:

    FILE* outfile = fopen(szPath, "wb");

    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);

    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width = sWidth;
    cinfo.image_height = sHeight;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);
    jpeg_start_compress(&cinfo, TRUE);

    while (cinfo.next_scanline < cinfo.image_height) {
        JSAMPROW row_pointer = &gScreenPacket.lpData[cinfo.next_scanline * cinfo.image_width * cinfo.input_components];
        jpeg_write_scanlines(&cinfo, &row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);

    jpeg_destroy_compress(&cinfo);
    fclose(outfile);

我已经尝试过:

增加/减少缓冲区大小, 更改截图保存功能, 在 jpeglib 中使用不同的可用函数。

Tyvm 为您提供帮助。

c++ arrays libjpeg
1个回答
0
投票

与您的崩溃无关,但有更简单的方法可以在 Windows 中从屏幕截图创建 jpeg 图像。使用 GDI+ 就是其中之一。我从 this 为 VS2019 准备了一个工作示例,如下所示:

#include <windows.h>
#include <gdiplus.h>
#include <atlimage.h>

using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")


BITMAPINFOHEADER createBitmapHeader(int width, int height)
{
    BITMAPINFOHEADER  bi;

    // create a bitmap
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = width;
    bi.biHeight = -height;  //this is the line that makes it draw upside down or not
    bi.biPlanes = 1;
    bi.biBitCount = 24;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;

    return bi;
}

HBITMAP GdiPlusScreenCapture(HWND hWnd)
{
    // get handles to a device context (DC)
    HDC hwindowDC = GetDC(hWnd);
    HDC hwindowCompatibleDC = CreateCompatibleDC(hwindowDC);
    SetStretchBltMode(hwindowCompatibleDC, COLORONCOLOR);

    // define scale, height and width
    int scale = 1;
    int screenx = GetSystemMetrics(SM_XVIRTUALSCREEN);
    int screeny = GetSystemMetrics(SM_YVIRTUALSCREEN);
    int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
    int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);

    // create a bitmap
    HBITMAP hbwindow = CreateCompatibleBitmap(hwindowDC, width, height);
    BITMAPINFOHEADER bi = createBitmapHeader(width, height);

    // use the previously created device context with the bitmap
    SelectObject(hwindowCompatibleDC, hbwindow);

    // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that call HeapAlloc using a handle to the process's default heap.
    // Therefore, GlobalAlloc and LocalAlloc have greater overhead than HeapAlloc.
    DWORD dwBmpSize = ((width * bi.biBitCount + 31) / 32) * 4 * height;
    HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
    char* lpbitmap = (char*)GlobalLock(hDIB);

    // copy from the window device context to the bitmap device context
    StretchBlt(hwindowCompatibleDC, 0, 0, width, height, hwindowDC, screenx, screeny, width, height, SRCCOPY);   //change SRCCOPY to NOTSRCCOPY for wacky colors !
    GetDIBits(hwindowCompatibleDC, hbwindow, 0, height, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS);

    // avoid memory leak
    DeleteDC(hwindowCompatibleDC);
    ReleaseDC(hWnd, hwindowDC);

    return hbwindow;
}

int main()
{
    // Initialize GDI+.
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    // get the bitmap handle to the bitmap screenshot
    HWND hWnd = GetDesktopWindow();
    HBITMAP hBmp = GdiPlusScreenCapture(hWnd);

    CImage image;
    image.Attach(hBmp);
    image.Save(L"d://Screenshot.jpg");

    GdiplusShutdown(gdiplusToken);
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.