标签:
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