まず、
GetWindowDC関数はタイトルバーなども含めたウィンドウ領域のデバイスコンテキストを返すので、
クライアント領域のデバイスコンテキストを得るためにかわりに
GetDC関数を用います。
なお、GetDC関数(やGetWindowDC関数)で取得したデバイスコンテキストは
ReleaseDC関数で解放するべきです。
画像をjpeg保存するには、ライセンスを承諾できるのであればライブラリを使うのが簡単です。
以下に、
libjpegを使ったコードの例を示します。
libjpegの使用条件は、大まかにいえば「the Independent JPEG Groupの成果物を使っていることを明示すること」です。
コード:
#include <setjmp.h>
#include <stdio.h>
#include "jpeglib.h"
BOOL SaveImage(LPTSTR filename, HWND hWnd)
{
HDC hdc;
HDC dc;
RECT rc;
BITMAP bmp;
HBITMAP hbmp;
HBITMAP hbmpPrev;
GetClientRect(hWnd, &rc);
hdc = CreateCompatibleDC(NULL);
hbmp = CreateBackbuffer(rc.right, rc.bottom);
hbmpPrev = (HBITMAP)SelectObject(hdc, hbmp);
dc = GetDC(hWnd);
BitBlt(hdc, 0, 0, rc.right, rc.bottom, dc, 0, 0, SRCCOPY);
ReleaseDC(hWnd, dc);
GetObject(hbmp, sizeof(BITMAP), &bmp);
if (WriteBitmap(filename, rc.right, rc.bottom, bmp.bmBits))
{
MessageBox(hWnd, "保存完了", "保存済み", MB_OK);
}
else
{
MessageBox(hWnd, "保存されませんでした", "Error!!", MB_OK);
}
SelectObject(hdc, hbmpPrev);
DeleteObject(hbmp);
DeleteDC(hdc);
return TRUE;
}
HBITMAP CreateBackbuffer(int nWidth, int nHeight)
{
LPVOID lp;
BITMAPINFO bmi;
BITMAPINFOHEADER bmiHeader;
ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmiHeader.biWidth = nWidth;
bmiHeader.biHeight = nHeight;
bmiHeader.biPlanes = 1;
bmiHeader.biBitCount = 24;
bmi.bmiHeader = bmiHeader;
return CreateDIBSection(NULL, (LPBITMAPINFO)& bmi, DIB_RGB_COLORS, &lp, NULL, 0);
}
/* エラーが起きた時、終了せずに戻れるようにする */
struct jumping_error_mgr {
struct jpeg_error_mgr std_error_mgr;
jmp_buf jmp_info;
};
METHODDEF(void) jumping_exit(j_common_ptr cinfo) {
struct jumping_error_mgr* emgr = (struct jumping_error_mgr*)cinfo->err;
longjmp(emgr->jmp_info, 1);
}
/* Win32 APIを用いてファイルに書き込めるようにする */
struct win32_write_mgr {
struct jpeg_destination_mgr std_dest_mgr;
HANDLE hFile;
JOCTET buffer[4096];
};
METHODDEF(void) win32_write_init(j_compress_ptr cinfo) { /* 書き込みを開始する */
struct win32_write_mgr* wmgr = (struct win32_write_mgr*)cinfo->dest;
wmgr->std_dest_mgr.next_output_byte = wmgr->buffer;
wmgr->std_dest_mgr.free_in_buffer = sizeof(wmgr->buffer);
}
METHODDEF(boolean) win32_write(j_compress_ptr cinfo) { /* バッファ全体を書き出す */
struct win32_write_mgr* wmgr = (struct win32_write_mgr*)cinfo->dest;
DWORD sizeToWrite = sizeof(wmgr->buffer);
DWORD sizeWritten = 0;
if (sizeToWrite > sizeof(wmgr->buffer)) return FALSE;
if (!WriteFile(wmgr->hFile, wmgr->buffer, sizeToWrite, &sizeWritten, NULL)) return FALSE;
if (sizeWritten != sizeToWrite) return FALSE;
wmgr->std_dest_mgr.next_output_byte = wmgr->buffer;
wmgr->std_dest_mgr.free_in_buffer = sizeof(wmgr->buffer);
return TRUE;
}
METHODDEF(void) win32_write_term(j_compress_ptr cinfo) { /* 書き込みを終了する */
struct win32_write_mgr* wmgr = (struct win32_write_mgr*)cinfo->dest;
DWORD sizeToWrite = sizeof(wmgr->buffer) - wmgr->std_dest_mgr.free_in_buffer;
DWORD sizeWritten = 0;
if (sizeToWrite > sizeof(wmgr->buffer)) return;
WriteFile(wmgr->hFile, wmgr->buffer, sizeToWrite, &sizeWritten, NULL);
wmgr->std_dest_mgr.next_output_byte = wmgr->buffer;
wmgr->std_dest_mgr.free_in_buffer = sizeof(wmgr->buffer);
}
BOOL WriteBitmap(LPTSTR lpszFileName, int nWidth, int nHeight, LPVOID lpBits)
{
struct jpeg_compress_struct cinfo;
struct jumping_error_mgr emgr;
struct win32_write_mgr wmgr;
HANDLE hFile = INVALID_HANDLE_VALUE;
int stride = ((3 * nWidth + 3) / 4) * 4; /* 画像1行あたりのバイト数 */
JOCTET* imageData = (JOCTET*)lpBits;
JOCTET* rowBuffer;
/* データを変換する用のバッファを確保する */
rowBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(JOCTET) * 3 * nWidth);
if (rowBuffer == NULL) return FALSE;
/* エラーが起きた時、終了せずにここに戻ってくるようにする */
cinfo.err = jpeg_std_error(&emgr.std_error_mgr);
emgr.std_error_mgr.error_exit = jumping_exit;
if (setjmp(emgr.jmp_info)) {
jpeg_destroy_compress(&cinfo);
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
HeapFree(GetProcessHeap(), 0, rowBuffer);
return FALSE;
}
/* ファイルを開く */
hFile = CreateFile(lpszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
HeapFree(GetProcessHeap(), 0, rowBuffer);
return FALSE;
}
/* JPEGの作成を開始する */
jpeg_create_compress(&cinfo);
/* ファイルを連携する */
wmgr.std_dest_mgr.init_destination = win32_write_init;
wmgr.std_dest_mgr.empty_output_buffer = win32_write;
wmgr.std_dest_mgr.term_destination = win32_write_term;
wmgr.hFile = hFile;
cinfo.dest = (struct jpeg_destination_mgr*)&wmgr;
/* 画像のパラメータを設定する */
cinfo.image_width = nWidth;
cinfo.image_height = nHeight;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 100, TRUE);
/* 画像のエンコードを行う */
jpeg_start_compress(&cinfo, TRUE);
while (cinfo.next_scanline < cinfo.image_height) {
JSAMPROW row_pointer = rowBuffer;
int i;
/* ビットマップは下から上に格納されることが多いので、反転する */
JOCTET* row_data = imageData + stride * (cinfo.image_height - 1 - cinfo.next_scanline);
/* ビットマップはBGRの順に格納されているので、libjpeg用のRGBに変換する */
for (i = 0; i < nWidth; i++) {
row_pointer[3 * i + 0] = row_data[3 * i + 2];
row_pointer[3 * i + 1] = row_data[3 * i + 1];
row_pointer[3 * i + 2] = row_data[3 * i + 0];
}
/* 行をエンコードする */
jpeg_write_scanlines(&cinfo, &row_pointer, 1);
}
/* 後片付けを行う */
jpeg_finish_compress(&cinfo);
CloseHandle(hFile);
jpeg_destroy_compress(&cinfo);
HeapFree(GetProcessHeap(), 0, rowBuffer);
return TRUE;
}