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