标签:
int save_screen_to_jpeg(const char* filename, int quality)
{
/*
* 把屏幕内容保存为一个 HBITMAP DDB
*/
HDC hScrnDC = CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
HDC hMemDC = CreateCompatibleDC(hScrnDC);
// 获取屏幕分辨率
int xScrn = GetDeviceCaps(hScrnDC, HORZRES);
int yScrn = GetDeviceCaps(hScrnDC, VERTRES);
// 创建位图,并选中
HBITMAP hScrnBmp = CreateCompatibleBitmap(hScrnDC, xScrn, yScrn);
SelectObject(hMemDC, hScrnBmp);
// 复制屏幕内容
BitBlt(hMemDC, 0, 0, xScrn, yScrn, hScrnDC, 0, 0, SRCCOPY);
// 现在得到了一个 HBITMAP DDB - hScrnBmp
/*
* 通过 hScrnBmp DDB 取得 DIB 数据
*/
// 获取色深 JPG 只能处理 24 位色,所以不管当前系统设置的色深是多少,我们都要求 GetDIBits 函数返回 24 位的 DIB 数据,同时也不需要调色板
//int colorDeepBits = GetDeviceCaps(hScrnBmp, BITSPIXEL);
//if(colorDeepBits > 24) colorDeepBits = 24;
int colorDeepBits = 24;
// 每行像素占用的字节数,每行要对齐4字节.
int imageRowSize = (xScrn * colorDeepBits + 31) / 32 * 4;
// 分配 DIB 数组
unsigned char* dibBuffer = new unsigned char[imageRowSize * yScrn];
assert(dibBuffer);
memset(dibBuffer, 0, imageRowSize * yScrn); // 清零是个好习惯
// 填充 BMP 信息头
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = xScrn;
bmi.bmiHeader.biHeight = yScrn * -1; // JPG 压缩需要正序的 DIB 像素流,所以要负数.
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = colorDeepBits;
bmi.bmiHeader.biCompression = BI_RGB;
// 获取 DIB 像素数组(DIB_RGB_COLORS 表示获取 RGB 值而不是调色板索引,当然24位位图也没有调色板)
int gdiRet = GetDIBits(hMemDC, hScrnBmp, 0, yScrn, dibBuffer, &bmi, DIB_RGB_COLORS);
assert(gdiRet == yScrn);
assert(bmi.bmiHeader.biSizeImage == imageRowSize * yScrn);
// DIB 数据已经获取,所有的 GDI 对象可以释放了.
DeleteDC(hScrnDC);
DeleteDC(hMemDC);
DeleteObject(hScrnBmp);
/*
* 把 DIB 数据压缩为 JPG 数据,用 example.c 中的代码
*/
// DIB 中颜色的存放顺序是 BGR, 而 JPG 要求的顺序是 RGB, 所以要交换 R 和 B.
// 由于有行对齐因素,所以逐行处理
for(int row = 0; row < yScrn; ++row)
{
unsigned char* rowData = dibBuffer + imageRowSize * row;
for(int col = 0; col < xScrn * 3; col += 3)
{
unsigned char swap = rowData[col];
rowData[col] = rowData[col + 2];
rowData[col + 2] = swap;
}
}
//把位图数据压缩为 jpeg
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 */
int image_width = xScrn;
int image_height = yScrn;
JSAMPLE* image_buffer = dibBuffer; // DIB buffer
int image_buffer_len = imageRowSize * image_height; // DIB buffer 长度
if(fopen_s(&outfile, filename, "wb"))
//if ((outfile = fopen_s(filename, "wb")) == NULL)
{
fprintf(stderr, "can't open %s\n", filename);
assert(0);
}
else
{
/* Step 1: allocate and initialize JPEG compression object */
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
jpeg_stdio_dest(&cinfo, outfile);
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
* Four fields of the cinfo struct must be filled in:
*/
cinfo.image_width = image_width; /* image width and height, in pixels */
cinfo.image_height = image_height;
cinfo.input_components = 3; /* # of color components per pixel */ // 因为DIB数据是24位的,所以每个像素占用3个字节
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)
*/
jpeg_set_defaults(&cinfo);
/* Now you can set any non-default parameters you wish to.
* Here we just illustrate the use of quality (quantization table) scaling:
*/
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
* loop counter, so that we don't have to keep track ourselves.
* To keep things simple, we pass one scanline per call; you can pass
* more if you wish, though.
*/
row_stride = imageRowSize;
while (cinfo.next_scanline < cinfo.image_height)
{
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
//row_pointer[0] = &image_buffer[image_buffer_len - (cinfo.next_scanline + 1) * row_stride];
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
/* After finish_compress, we can close the output file. */
fclose(outfile);
/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_compress(&cinfo);
}
// 释放 DIB 数组
delete []dibBuffer;
return 0;
}
标签:
原文地址:http://blog.csdn.net/querw/article/details/51533811