ウィンドウのクライアント領域をjpegで保存したいです

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
PonPon
記事: 8
登録日時: 4年前

ウィンドウのクライアント領域をjpegで保存したいです

#1

投稿記事 by PonPon » 4年前

ウィンドウの画像が切れた状態で保存されるのですが、本来はクライアント領域のみをjpeg保存したいです。
どのように修正したらよろしいでしょうか?

コード:

BOOL SaveImage(LPTSTR filename, HWND hWnd)
{
	HDC hdc;
	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);

	BitBlt(hdc, 0, 0, rc.right, rc.bottom, GetWindowDC(hWnd), 0, 0, SRCCOPY);
	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);
}

BOOL WriteBitmap(LPTSTR lpszFileName, int nWidth, int nHeight, LPVOID lpBits)
{
	HANDLE           hFile;
	DWORD            dwResult;
	DWORD            dwSizeImage;
	BITMAPFILEHEADER bmfHeader;
	BITMAPINFOHEADER bmiHeader;

	hFile = CreateFile(lpszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
		return FALSE;

	dwSizeImage = nHeight * ((3 * nWidth + 3) / 4) * 4;

	ZeroMemory(&bmfHeader, sizeof(BITMAPFILEHEADER));
	bmfHeader.bfType = *(LPWORD)"BM";
	bmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwSizeImage;
	bmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

	WriteFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER), &dwResult, NULL);

	ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
	bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth = nWidth;
	bmiHeader.biHeight = nHeight;
	bmiHeader.biPlanes = 1;
	bmiHeader.biBitCount = 24;
	bmiHeader.biSizeImage = dwSizeImage;
	bmiHeader.biCompression = BI_RGB;

	WriteFile(hFile, &bmiHeader, sizeof(BITMAPINFOHEADER), &dwResult, NULL);

	WriteFile(hFile, lpBits, dwSizeImage, &dwResult, NULL);

	CloseHandle(hFile);

	return TRUE;
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ウィンドウのクライアント領域をjpegで保存したいです

#2

投稿記事 by みけCAT » 4年前

まず、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;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

返信

“C言語何でも質問掲示板” へ戻る