C++中BYTE*数组转JPEG图像(libjpeg)跨设备异常求助
问题描述
开发一款将截图存储到外部服务器的应用,受资源限制需将截图以BYTE*数组的文本形式存储。本地会话内可正常读写截图,但朋友上传的截图会生成0KB空文件,且在扫描行函数执行时导致程序崩溃。
截图获取函数 SaveScreenshotNew
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; }
libjpeg压缩代码
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);
排查与修复建议
修复BITMAP行对齐问题:Windows DIB位图要求行字节数为4的倍数,当前代码直接用
nScreenWidth*3计算行大小,未考虑对齐,会导致缓冲区越界。修改缓冲区大小计算:int rowSize = ((nScreenWidth * 3 + 3) / 4) * 4; // 按4字节对齐计算行宽 int bufferSize = rowSize * nScreenHeight;同时遍历像素时用对齐后的行大小:
int index = i * rowSize + j * 3;同步跨机器分辨率参数:朋友机器的屏幕分辨率可能与本地不同,若
sWidth/sHeight未正确获取对方实际分辨率,会导致jpeg压缩时访问非法内存。传输截图时必须同步分辨率参数,确保压缩时的尺寸与截图生成时一致。检查缓冲区传输完整性:BYTE*转文本传输时,可能存在编码错误或数据截断,导致接收端缓冲区不完整。传输前需记录缓冲区总大小,接收端先验证数据长度是否匹配,再执行解压操作。
添加文件打开错误处理:当前代码未检查
fopen是否成功,若路径无效或无写入权限,会生成0KB空文件。增加判断:if (outfile == NULL) { // 处理文件打开失败逻辑,如返回错误码 return; }自定义libjpeg错误处理:默认错误处理会直接终止程序,自定义错误捕获逻辑避免崩溃:
struct my_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; METHODDEF(void) my_error_exit(j_common_ptr cinfo) { my_error_mgr* myerr = (my_error_mgr*)cinfo->err; longjmp(myerr->setjmp_buffer, 1); } // 使用时替换默认错误处理 struct my_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&cinfo); fclose(outfile); // 处理错误逻辑 return; }
内容的提问来源于stack exchange,提问作者take2137
相关产品推荐
相关产品推荐

