工程中有个需求是要求在windows平台下截图某一个窗口,并实现保存成jpeg,实现功能大概是:
1.查找窗口
2.截图得到bitmap数据
3.把bitmap数据保存成jpeg文件
其中bitmap数据保存成jpeg文件这里使用libjpeg来实现,这里记录下编译和使用时遇到的一些坑,首先要下载源码进行编译

1、下载源代码下载地址:http://www.ijg.org/files/,
选择最新版本的windows版本压缩包,进行下载。
2、然后开始编译,这里环境是用vs2019,windows 10 64位编译:
  • 2.1.修改文件名jconfig.vc为jconfig.h
  • 2.2.在开始菜单中打到x64 Native Tools Command Prompt For VS 2019并打开,然后进入目录输入命令:
    nmake -f makefile.vc libjpeg.lib
    有可能编译会失败,提示找不到Win32.mak,这是编译环境里找不到这个文件,这个文件一般是在安装的vs的c++编译环境中自带的,如果没有可以下载一个,这里已经文件下载到本地了
3、使用

libjpeg.lib是用c语言开发的,
如果在C++程序里使用,需要用extern “C” { }包含一下。
相关头文件:
extern “C”
{
#include “jpeglib.h”
}
cpp文件中引用编译好的文件:
#pragma comment(lib, "libjpeg/jpeg.lib")

贴出实现bitmap像素保存jpeg函数源码:

//===================================================================================
//function:       jpeg压缩
//input:          1:生成的文件名,2:bmp的指针,3:位图宽度,4:位图高度,5:颜色深度
//return:         int
//description:    bmp的像素格式为(RGB)
//===================================================================================
int savejpeg(const char* filename, unsigned char* bits, int width, int height, int depth)
{
	//RGB顺序调整,这里很重要,因为传进来的像素数组是使用CreateDIBSettion分配的,它的顺序是BGR,不是RGB,而jpeg文件是RGB,所以需要进行顺序调整,否则会出现红色变成蓝色,这个网上很多文章都没说到,不了解的小白肯定会遇到这个问题!
	/*顺便普及知识
	2.DIB注意点:
        <1>DIB位图每行数据必须是32bit(4个字节)的整数倍,如果图像数据为Byte型(0~255),即每个像素为一个字节(8bit),这样图      像每行的宽必须是4的整数倍,不足4的整数倍的部分,以0补充。
    
        <2>DIB数据存储顺序是:自左到右,自下到上,逆序存储。即:图像的第一行数据,存在DIB数据部分最后一行,最后一行存在第一行    ,因为显示的时候,DIB位图是,自下而上显示的,即读取的第一行数据,会显示在界面的最后一行,然后,第二行显示在界面倒数第    二行。
		<3>调色板顺序为BGR而不是RGB。
	*/
	unsigned char buf = 0;
	unsigned char* tmp = bits;//image_buffer = tmp = (unsigned char*)map + m_buf.offsets[frame];
	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++)
		{
			buf = *tmp;
			*tmp = *(tmp + 2);
			*(tmp + 2) = buf;
			tmp += 3;
		}
	}
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;
	FILE* outfile;                 //target file 
	JSAMPROW row_pointer[1];        //pointer to JSAMPLE row[s] 
	int     row_stride;             //physical row width in image buffer 
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);

	if (0 != fopen_s(&outfile, filename, "wb"))
	{
		fprintf(stderr, "can't open %s/n", filename);
		return -1;
	}
	jpeg_stdio_dest(&cinfo, outfile);
	cinfo.image_width = width;      //image width and height, in pixels 
	cinfo.image_height = height;
	cinfo.input_components = 3;         //# of color components per pixel 
	cinfo.in_color_space = JCS_RGB;         //colorspace of input image 
	   指定亮度及色度质量
	cinfo.q_scale_factor[0] = jpeg_quality_scaling(100);
	cinfo.q_scale_factor[1] = jpeg_quality_scaling(100);

	jpeg_set_defaults(&cinfo);
	jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE);//limit to baseline-JPEG values 
	jpeg_start_compress(&cinfo, TRUE);

	row_stride = width * depth; // JSAMPLEs per row in image_buffer 
	while (cinfo.next_scanline < cinfo.image_height)
	{
		//由于jpg文件的图像是倒的,改一下读的顺序,这个参考网上的一段源码
		//这是原代码:
		//row_pointer[0] = & bits[cinfo.next_scanline * row_stride];
		row_pointer[0] = &bits[(cinfo.image_height - cinfo.next_scanline - 1) * row_stride];
		(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
	}
	jpeg_finish_compress(&cinfo);
	fclose(outfile);
	jpeg_destroy_compress(&cinfo);
	return 0;
}

顺便贴一下截图代码:

int captureRenderProgressWindow(HWND hwnd, LPCSTR filePath)
{
	HDC     hDC;
	HDC     MemDC;
	BYTE* Data;
	HBITMAP   hBmp;
	BITMAPINFO   bi;

	RECT rtClientWnd;
	::GetClientRect(hwnd, &rtClientWnd);
	int width = rtClientWnd.right - rtClientWnd.left;
	int height = rtClientWnd.bottom - rtClientWnd.top;

	memset(&bi, 0, sizeof(bi));
	bi.bmiHeader.biSize = sizeof(BITMAPINFO);
	bi.bmiHeader.biWidth = width;
	bi.bmiHeader.biHeight = height;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = 24;

	hDC = GetWindowDC(hwnd);
	MemDC = CreateCompatibleDC(hDC);
	//创建位图
	hBmp = CreateDIBSection(MemDC, &bi, DIB_RGB_COLORS, (void**)& Data, NULL, 0);
	SelectObject(MemDC, hBmp);
	BitBlt(MemDC, 0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, hDC, 0, 0, SRCCOPY);
	//int result = SaveBitmapToFile(hBmp, filePath);
	// 保存
	int result = savejpeg(filePath, Data, width, height, 3);
	//int result = colorBitmap(hBmp);
	ReleaseDC(NULL, hDC);
	DeleteDC(MemDC);
	DeleteObject(hBmp);
	return result;
}

libjpeg源码已经配好win32.mak编译有问题的可以看下一下这个库,libjpeg已经把win32.mak文件加上,且已经编译好一个libjpeg.lib的64位版本

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐