提问人:TakeCalios 提问时间:10/31/2023 更新时间:10/31/2023 访问量:47
C++ BYTE* 数组到 JPEG 图像 (libjpeg)
C++ BYTE* array to JPEG image (libjpeg)
问:
我正在尝试编写一个用于在外部服务器上存储屏幕截图的应用程序,但由于资源有限,我想以文本形式存储它们,特别是 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 为您提供帮助。
答:
0赞
Cem Polat
10/31/2023
#1
与您的崩溃无关,但有更简单的方法可以在 Windows 中从屏幕截图创建 jpeg 图像。使用 GDI+ 就是其中之一。我从中为 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;
}
评论
FILE*
std::ofile
BITMAPINFOHEADER bi{};