概要

コマンドプロンプト上で保存jpegファイルをリージョンでクリッピングして保存するプログラムです。
入力ファイルはtest.jpg、クリッピング結果はtest_cut.jpgに保存されます。
プログラムソースの#ifディレクティブの評価値を変更しリコンパイルし実行することにより多角形、楕円、スプラインの3種類のクリッピングを試すことができます。
以下に入力ファイルとそれぞれのクリッピング結果を示します。
test.jpg 0 50 100 150 200 250 300 320 50 100 150 200 240 SVGの代替画像 Polygon(多角形) 0 50 100 150 200 250 300 320 50 100 150 200 240 SVGの代替画像 Ellipse(楕円) 0 50 100 150 200 250 300 320 50 100 150 200 240 SVGの代替画像 Curve(スプライン) 0 50 100 150 200 250 300 320 50 100 150 200 240 SVGの代替画像

テスト環境

コンパイラ

Visual C++ 2008/2013 Express 32/64bit マルチバイト/UNICODE

実行環境

Windows 10 Home(32bit/64bit)
Windows 7 Enterprise Service Pack 1 64bit

プログラムソースの概要

jpegcut2.cpp

_tmain

GdiplusStartupによりGDI+の初期化をします。
GetEncoderClsidによりjpegエンコーダを取得します。
imgtrim関数を呼び出しクリッピングを実行します。
GdiplusShutdownにより終了処理を実行します。

imgtrim

jpegファイルの読み込み等
jpegファイルよりGdiplus::Imageオブジェクトを作成します。
GDI+はunicodeしかサポートしないのでマルチバイトでコンパイルした場合は、unicodeに変換するコードを有効にします。
GetHorizontalResolution,GetVerticalResolution関数によりソースファイルの解像度(DPI)を取得します。
new Bitmapにより保存用のBitmapオブジェクトを作成します。
SetResolutionでBitmapオブジェクトの解像度を設定します。
Bitmapオブジェクトを元にGraphicsオブジェクトを作成します。
クリッピングを実施すると背景が真っ黒になるので、Clear関数により背景色を設定します。色はColorクラスのコンストラクタで指定します。
パスの作成
#ifディレクティブの評価値(0の場合#if~#endがコンパイル対象とならない)により以下の3つのリージョンのいずれかを適用します。
多角形(Polygon)
Pointの配列でクリッピングしたい領域の各座標を指定します。ここではひし形としています。
AddPolygonに上記の配列と要素数を引数として渡すとポリゴンのパスとして設定します。
要素数はsizeof演算子で計算させます。
Point po[] = { Point(width / 2, 0), Point(width, height / 2), Point(width / 2, height), Point(0, height / 2) };
gp->AddPolygon(po, sizeof(po) / sizeof(po[0]));
楕円(Ellipse)
AddEllipseで楕円をパスとして設定します。
この関数では、楕円に外接する長方形の左上座標と右下座標を指定します。
AddEllipse(x1,y1,x2,y2) (x1,y1) (x2,y2) SVGの代替画像
gp->AddEllipse(width * 2 / 10, height * 2 / 10, width * 6 / 10, height * 6 / 10);
スプライン(Curve)
スプライン曲線の各点の座標をPointの配列で指定します。この座標列が猫のシルエットとなります。
AddCurveに上記の配列と要素数を引数として渡すしパスとして設定します。
要素数はsizeof演算子で計算させます。
Point po[] = {
 Point(152, 179), Point(159, 175), Point(160, 154), Point(143, 134), Point(138, 127), Point(123, 115), Point(122, 102),
 Point(120, 95), Point(126, 94), Point(138, 93), Point(148, 90), Point(154, 86), Point(157, 94), Point(168, 98), Point(178, 104),
 Point(206, 112), Point(224, 134), Point(228, 149), Point(228, 161), Point(226, 166), Point(235, 168), Point(247, 166), Point(265, 166),
 Point(286, 162), Point(292, 167), Point(288, 173), Point(228, 180), Point(218, 181), Point(205, 184), Point(197, 183), Point(156, 186) };
gp->AddCurve(po, sizeof(po) / sizeof(po[0]));
リージョンの作成・設定
Regionクラスのコンストラクタにより先ほど作成したパスを元にリージョンを作成します。
SetClip関数によりリージョンをクリッピングとしてGraphicsとして設定します。
描画・保存・各オブジェクトの解放
DrawImage関数によりImageオブジェクトの指定領域をGraphicsオブジェクトに描画します。
DrawImage関数には沢山のオーバーロードされた形式があります。
描画が終了すればImageオブジェクトは不要なのでデストラクタでImageオブジェクトを解放します。
Save関数によりBitmapオブジェクトをファイルに保存します。マルチバイトでコンパイルした場合は、unicodeに変換するコードを有効にします。
リージョン,パス,Bitmap,Graphicsオブジェクトを解放します。

ソースコード

jpegcut2.cpp

// jpegをリージョンでクリッピング
// コマンドプロンプトで動作
// GDI+ランタイムが必要
// 使い方
//   jpegcut2

#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
#include <tchar.h>
#include <locale.h>

#pragma comment(lib,"gdiplus.lib")

using namespace Gdiplus;
GdiplusStartupInput gdiSI;
ULONG_PTR	gdiToken;
CLSID     encoderClsid;

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid); //	エンコーダーの取得
int imgtrim(TCHAR* dtc, TCHAR* src, int wdith, int height);

int _tmain(int argc, TCHAR** argv){
	//	UNICODE文字を標準出力に正しく表示させるためにロケールを設定
	_tsetlocale(LC_ALL, _TEXT(""));
	GdiplusStartup(&gdiToken, &gdiSI, NULL);
	if (GetEncoderClsid(L"image/jpeg", &encoderClsid) < 0){
		_tprintf(_TEXT("jpegエンコーダーが取得できませんでした。¥n"));
		return (int)0;
	}

	if (imgtrim(_TEXT("test_cut.jpg"), _TEXT("test.jpg"), 320, 240))
		_tprintf(_TEXT("jpegトリミングに失敗しました¥n"));
	else
		_tprintf(_TEXT("jpegトリミングソフト¥n¥n使い方¥n¥njpegcut1 保存ファイル 入力ファイル 切り取り位置x 切り取り位置y 切り取り横幅 切り取り高さ¥n"));

	GdiplusShutdown(gdiToken);
	return 0;
}

int imgtrim(TCHAR* dtc, TCHAR* src, int width, int height){
	Image* srcImage = 0;

#ifdef UNICODE
	srcImage = Bitmap::FromFile(src);
#else
	WCHAR srcFile[MAX_PATH];
	MultiByteToWideChar(932, 0, src, -1, srcFile, sizeof(srcFile) / sizeof(WCHAR));
	srcImage = Bitmap::FromFile(srcFile);
#endif
	if (srcImage == 0 || srcImage->GetLastStatus() != Gdiplus::Ok){
		srcImage->~Image();
		return -1;
	}
	float px_res = srcImage->GetHorizontalResolution();	//	jpgファイルの解像度DPI(横)
	float py_res = srcImage->GetVerticalResolution();	//	jpgファイルの解像度DPI(縦)
	Bitmap* bmp = new Bitmap(width, height);		// 保存用
	bmp->SetResolution(px_res, py_res);

	Graphics*  MyGraphics = Graphics::FromImage(bmp);
	Color orgColor(170, 163, 155);
	MyGraphics->Clear(orgColor);

	GraphicsPath* gp = new GraphicsPath();

#if 0 // ひし形のリージョン
	Point po[] = { Point(width / 2, 0), Point(width, height / 2), Point(width / 2, height), Point(0, height / 2) };
	gp->AddPolygon(po, sizeof(po) / sizeof(po[0]));
#endif

#if 0 //  楕円のリージョン
	gp->AddEllipse(width * 2 / 10, height * 2 / 10, width * 6 / 10, height * 6 / 10);
#endif

#if 1 //  スプラインのリージョン
	Point po[] = {
		Point(152, 179), Point(159, 175), Point(160, 154), Point(143, 134), Point(138, 127), Point(123, 115), Point(122, 102),
		Point(120, 95), Point(126, 94), Point(138, 93), Point(148, 90), Point(154, 86), Point(157, 94), Point(168, 98), Point(178, 104),
		Point(206, 112), Point(224, 134), Point(228, 149), Point(228, 161), Point(226, 166), Point(235, 168), Point(247, 166), Point(265, 166),
		Point(286, 162), Point(292, 167), Point(288, 173), Point(228, 180), Point(218, 181), Point(205, 184), Point(197, 183), Point(156, 186) };
	gp->AddCurve(po, sizeof(po) / sizeof(po[0]));
#endif
	Region* rgn = new Region(gp);
	MyGraphics->SetClip(rgn);
	MyGraphics->DrawImage(srcImage, 0, 0);
	srcImage->~Image();

#ifdef UNICODE
	bmp->Save(dtc, &encoderClsid);
#else
	WCHAR dtcFile[MAX_PATH];
	MultiByteToWideChar(932, 0, dtc, -1, dtcFile, sizeof(dtcFile) / sizeof(WCHAR));
	bmp->Save(dtcFile, &encoderClsid);
#endif
	delete rgn;
	delete gp;
	delete bmp;
	delete MyGraphics;
	return 0;
}

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid){
	UINT  num = 0;
	UINT  size = 0;
	ImageCodecInfo* pImageCodecInfo;
	GetImageEncodersSize(&num, &size);
	if (size == 0)
		return -1;
	pImageCodecInfo = (ImageCodecInfo*)new char[size];
	if (pImageCodecInfo == NULL)
		return -1;
	GetImageEncoders(num, size, pImageCodecInfo);
	for (UINT n = 0; n<num; ++n) {
		if (wcscmp(pImageCodecInfo[n].MimeType, format) == 0) {
			*pClsid = pImageCodecInfo[n].Clsid;
			delete pImageCodecInfo;
			return n;
		}
	}
	delete pImageCodecInfo;
	return -1;
}

ソースコードと実行ファイルのダウンロード

ダウンロード jpegcut2.zip(91.9kB)

jpegcut2.cpp
jpegcut2.exe
test.jpg