GDI+」タグアーカイブ

gdiplus save

Keyleigh をそろそろなんとかしたいと考えた。
拾ったデルヒャァコンポーネントを使っているだけのクソソフトだが。
せっかくなので画像コンバータ機能とかでも追加すれば面白くなるかも。

GDI+ を使うのが一番だよなぁ。
C# で使えば死ぬほど簡単だ。

using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace iconpoli2
{
	class Program
	{
		static void Main(string[] args)
		{
			foreach (var s in args)
			{
				string t = Path.ChangeExtension(s, "jpg");
				Bitmap b = new Bitmap(s);
				b.Save(t, ImageFormat.Jpeg);
			}
		}
	}
}

コンバートならマジでこれだけだ。
いや、せっかくなので C++ でやりたいぞ。
と思ったけど

Gdiplus::Bitmap * img = new Gdiplus::Bitmap(__wargv[i]);
img->Save(outname, &Gdiplus::ImageFormatJPEG);

とやっても全然上手くいかない。

Transforming a JPEG Image Without Loss of Information (Windows)
Retrieving the Class Identifier for an Encoder (Windows)

どうやら自力で CLSID を取ってくるしかないようで。
つか ImageCodecInfo って class なのにサイズを得て malloc なの?
試しに普通な new で作ったら見事にヒープ領域不足、どういう設計だよ。

とにかく MSDN の方法で上記と同じになるよう C++ で作ってみる。
C++ じゃ ChangeExtension なんて便利なものは無いし GDI+ 初期化も必須。

stdafx.h

#pragma once

// 面倒なのでココで参照追加
#pragma comment(lib, "gdiplus.lib")

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 // Vista
#endif

#include <stdio.h>
//#include <tchar.h>
#include <wchar.h>
#include <windows.h>
#include <gdiplus.h>

凄く無駄だと解っているけど tchar を利用しないで UNICODE 関数をまんま使う。
てか今となっては Ansi 関数を併用する必要は無いと思うんだが。
WCHAR や UINT のマクロも利用したくない。
だって Visual Studio は大文字マクロの型名では色が付かないんだよね。
というかなるべく小文字にしたいと思うのは多分 Python のやりすぎ。

iconpoli.cpp

#include "stdafx.h"

using namespace Gdiplus;

int GetEncoderClsid(const wchar_t* format, CLSID* pClsid)
{
	unsigned int  num = 0;
	unsigned int  size = 0;

	ImageCodecInfo * pImageCodecInfo = NULL;

	GetImageEncodersSize(&num, &size);
	if(size == 0)
		return -1;  // Failure

	// コレだとヒープ領域不足になる
	//ImageCodecInfo * pImageCodecInfo = new ImageCodecInfo();
	pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
	if(pImageCodecInfo == NULL)
		return -1;  // Failure

	GetImageEncoders(num, size, pImageCodecInfo);

	for(unsigned int j = 0; j < num; ++j)
	{
		if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return j;  // Success
		}    
	}

	free(pImageCodecInfo);
	return -1;  // Failure
}

bool ChangeExtension(const wchar_t* src, wchar_t* dst, const wchar_t* ext)
{
	wchar_t path[4][256];
	_wsplitpath_s(src, path[0], 256, path[1], 256, path[2], 256, path[3], 256);
	_wmakepath_s(dst, 1024, path[0], path[1], path[2], ext);
	return TRUE;
}

int wmain(int argc, wchar_t* argv[])
{
	// GDI+ 初期化
	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

	for (int i=1; i < __argc; i++)
	{
		// makepath
		wchar_t outname[1024];
		ChangeExtension(__wargv[i], outname, L".jpg");

		Gdiplus::Bitmap * img = new Gdiplus::Bitmap(__wargv[i]);

		CLSID encoderClsid;
		int r = GetEncoderClsid(L"image/jpeg", &encoderClsid);
		if (r == -1)
		{
			wprintf(L"no CLSID");
			return 0;
		}
		// コレは上手くいかない
		//int result = img->Save(outname, &Gdiplus::ImageFormatJPEG);
		int result = img->Save(outname, &encoderClsid);
		if (result == Gdiplus::Ok)
			wprintf(L"Encode Success");
		else
			wprintf(L"Encode Failure");
		delete img;
	}
	// 後片付け
	Gdiplus::GdiplusShutdown(gdiplusToken);
	return 0;
}

長い。。。。。

たったこれだけのモンにえらく時間が掛かった、やっぱり C# のほうがいいかなと。
それと Python や C# ばかりやっていると開放処理をつい忘れそうになるよね。

アルファブレンドの制御

クラシックてか Windows 2000 スタイルでの動作チェック。

シークバーがチラツキすぎる…だめだこりゃ。

まあWバッファリングが上手くいかんのでチラツクのは解っているんだが。
アルファを掛けているとバッファの転送で背景が消えないんで一度フラッシュしてるし。
クラシック表示だと露骨に見えるようになるのか、コレは困った。

なんとかならんかとあーでもねぇこーでもねぇとやって今日が終わるよぉ!
InvalidateRect の第三引数を TRUE にすれば普通なら消えるはずなのに…
以前の描写部分を転送前に消す、もしくは転送したら消えるようにするには…
いくら探しても古くさい情報しか見つからない!方法は絶対にあるはずだ!

GDIPlus に関する情報の少なさは悲しいね。
C++ で行う情報は皆無に近いので C# で探して自力変換するしかないし。
…それって逆だろ!と憤りを感じてもしょーがない。
まあ他言語からの変換なんて元デルヒャァユーザーはいつものことだったし。

半日探してやっとこんなのを見つけた。

方法 : 複合モードを使用してアルファ ブレンドを制御する

んーブレンド制御を行ったら透過部分も塗りつぶしにならんかな?
とも思ったけどやってみにゃ解らない、藁にもすがる気持ちでやってみる。
まあつまり

g.Clear(Color::Black); //チラつくけど背景消去方法が他にない

とやっていたトコを

g.SetCompositingMode(Gdiplus::CompositingModeSourceCopy);

に書き換えるだけなんだが。

さてどうなるか…あっさり解決…
せっかく GDI+ が用意してくれている方法を知らないって悲しいなぁ。
まあ現場のおっさんなんだからこんなもんさ。

そんなこんなで今日も進まない。

高品質双三次補間

Image Cutter 2 – ベクターソフトニュース

読み書き拡張子を見るとモロに GDI+ を使っていると解るのに
高品質双三次補間とかワケワカだし難しそうなコトやってんなぁ。
と関心したんですが、、、、、

@IT:.NET TIPS 画像を高品質に拡大/縮小するには? – C#

簡単だったのね、GDI+ って強力なアイテムだなぁ。

いや、作者イジメで書いているわけではない。
まあ初心者には解らないだろうけど情報は公開したほうが後々で得ですよと。

だけど結局は末端な人のアイデアは上に吸い取られる運命だが。
ソコをどうするかが…以上。