使用libjpeg实现windows截图保存成jpeg文件【看这一篇就好啦】

工程中有个需求是要求在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位版本

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 首先需要安装libjpeg库,可以使用命令行进行安装: ``` sudo apt-get install libjpeg-dev ``` 2. 然后创建一个C文件,例如convert.c,包含以下代码: ```c #include <stdio.h> #include <stdlib.h> #include <jpeglib.h> int main(int argc, char *argv[]) { if (argc != 4) { fprintf(stderr, "Usage: %s <input_yuv_file> <width> <height>\n", argv[0]); exit(EXIT_FAILURE); } char *input_file = argv[1]; int width = atoi(argv[2]); int height = atoi(argv[3]); FILE *fp_in = fopen(input_file, "rb"); if (fp_in == NULL) { fprintf(stderr, "Error opening input file: %s\n", input_file); exit(EXIT_FAILURE); } FILE *fp_out = fopen("output.jpg", "wb"); if (fp_out == NULL) { fprintf(stderr, "Error creating output file\n"); exit(EXIT_FAILURE); } struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp_out); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_YCbCr; jpeg_set_defaults(&cinfo); jpeg_start_compress(&cinfo, TRUE); JSAMPROW row_pointer[1]; row_pointer[0] = malloc(width * 3); int y, u, v; unsigned char *buffer = malloc(width * height * 3); fread(buffer, width * height * 3, 1, fp_in); for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { y = buffer[(i * width + j) * 3]; u = buffer[(i * width + j) * 3 + 1]; v = buffer[(i * width + j) * 3 + 2]; row_pointer[0][j * 3] = y; row_pointer[0][j * 3 + 1] = u; row_pointer[0][j * 3 + 2] = v; } jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(fp_in); fclose(fp_out); return 0; } ``` 3. 编译上述代码,可以使用以下命令: ``` gcc -o convert convert.c -ljpeg ``` 4. 运行程序,命令格式为: ``` ./convert <input_yuv_file> <width> <height> ``` 其中,input_yuv_file为需要换的YUV图像文件,width和height为图像的宽度和高度。 例如,换名为test.yuv的图像,宽度为640,高度为480,可以使用以下命令: ``` ./convert test.yuv 640 480 ``` 5. 换后的JPEG文件保存在当前目录下的output.jpg中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值