1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

サムネイル画像を作成する

Posted at

はじめに

Windows APIを使ってサムネイル画像を作成するプログラムを記述しました。

DMD v2.095.0でコンパイルしました。

ソースコード

tnail.d
import core.sys.windows.windows;
import std.path;
import std.utf;

pragma(lib, "Gdi32.lib");
pragma(lib, "Ole32.lib");
pragma(lib, "Rpcrt4.lib");
pragma(lib, "Shell32.lib");
pragma(lib, "User32.lib");

extern (C) {
	interface IShellItem : IUnknown {
	}
	interface IShellItemImageFactory : IUnknown {
		HBITMAP GetImage(SIZE nativeSize, int options, HBITMAP *hBitmap);
	}
	interface IBindCtx : IUnknown {
	}
}
extern (Windows) HRESULT SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv);

HBITMAP getThumbnail(string fileName, int width, int height, int options)
{
	CoInitialize(null);
	scope(exit) CoUninitialize();
	
	GUID shellItem2Guid;
	UuidFromString(cast(wchar *)"7E9FB0D3-919F-4307-AB2E-9B1860310C93"w.ptr, &shellItem2Guid);
	IShellItem *nativeShellItem;
	int retCode = SHCreateItemFromParsingName(fileName.absolutePath.toUTF16z, cast(IBindCtx *)null, &shellItem2Guid, cast(void **)&nativeShellItem);
	
	HBITMAP hBitmap;
	if ( retCode == 0 ){
		SIZE nativeSize;
		nativeSize.cx = width;
		nativeSize.cy = height;
		GUID IID_IShellItemImageFactory;
		UuidFromString(cast(wchar *)"BCC18B79-BA16-442F-80C4-8A59C30C463B"w.ptr, &IID_IShellItemImageFactory);
		IShellItemImageFactory *psiif;
		(cast(IShellItemImageFactory)nativeShellItem).QueryInterface(&IID_IShellItemImageFactory, cast(void**)&psiif);
		(cast(IShellItemImageFactory)psiif).GetImage(nativeSize, 0, &hBitmap); // SIIGBF_RESIZETOFIT = 0;
	}
	return ( hBitmap );
}

void saveBmpFile(HBITMAP hBmp, string filename)
{
	HDC hdc = GetDC(null);
	scope(exit) ReleaseDC(null, hdc);
	HDC hdcMem = CreateCompatibleDC(hdc);
	scope(exit) DeleteDC(hdcMem);
	BITMAP bmp;
	GetObject(hBmp, bmp.sizeof, &bmp);
	SelectObject(hdcMem, hBmp);
	
	uint bpp;
	switch ( bmp.bmBitsPixel ){
		case 2: case 4: case 8:
			bpp = 2 ^^ bmp.bmBitsPixel;
			break;
		default:
			bpp = 0;
	}
	uint imageSize = cast(uint)(bmp.bmWidthBytes * bmp.bmHeight
		+ BITMAPFILEHEADER.sizeof + BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * bpp);
	
	BITMAPFILEHEADER bfh;
	bfh.bfType = 'B' | 'M' << 8;		// "BM" : LittleEndian
	bfh.bfSize = imageSize;
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;
	bfh.bfOffBits = cast(uint)(BITMAPFILEHEADER.sizeof + BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * bpp);
	
	union BI {
		BITMAPINFO bi;
		byte[BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * 256] dummy;
		alias bi this;
	}
	BI bi;
	bi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
	bi.bmiHeader.biWidth = bmp.bmWidth;
	bi.bmiHeader.biHeight = bmp.bmHeight;
	bi.bmiHeader.biPlanes = 1;
	bi.bmiHeader.biBitCount = bmp.bmBitsPixel;
	bi.bmiHeader.biCompression = BI_RGB;
	if ( bpp != 0 ){
		GetDIBColorTable(hdcMem, 0, bpp, bi.bmiColors.ptr);
	}
	
	byte[] bits = new byte[bmp.bmWidthBytes * bmp.bmHeight];
	GetDIBits(hdcMem, hBmp, 0, bmp.bmHeight, bits.ptr, &bi.bi, DIB_RGB_COLORS);
	
	HANDLE hFile = CreateFile(filename.toUTF16z, GENERIC_WRITE, 0, null, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, null);
	scope(exit) CloseHandle(hFile);
	DWORD writeSize;
	WriteFile(hFile, &bfh, bfh.sizeof, &writeSize, null);
	WriteFile(hFile, &bi, cast(uint)(BITMAPINFOHEADER.sizeof + RGBQUAD.sizeof * bpp), &writeSize, null);
	WriteFile(hFile, bits.ptr, bmp.bmWidthBytes * bmp.bmHeight, &writeSize, null);
}

void main(string[] args)
{
	int THUMB_SIZE = 256;
	HBITMAP thumbnail = getThumbnail(args[1], THUMB_SIZE, THUMB_SIZE, 0x00);
	saveBmpFile(thumbnail, args[2]);
}

ソースコード補足説明

getThumbnail関数は、ファイル名よりサムネイル画像のハンドル(HBITMAP)を返します。
関数内部でIShellItemImageFactory::GetImageメソッドを呼び出しています。
このメソッドは、エクスプローラーで表示されるファイルアイコンと同じ画像のハンドルを取得できます。
つまり、画像ファイルだけでなく、EXEファイルのアイコン画像なども取得可能です。

saveBmpFile関数は、ビットマップのハンドルから、ビットマップファイルを作成します。
GetObjectを使って、BITMAP構造体の情報を取得します。
BITMAPFILEHEADERBITMAPINFO構造体に必要な情報をセットして、ファイルを作成します。

コンパイル、実行結果

コマンドプロンプト
D:\Dev> dmd -m64 tnail.d

D:\Dev> tnail dlang.jpg dlang.bmp

元ファイル(dlang.jpg): https://dlang.org の画面イメージです
dlang.jpg

サムネイル(dlang.bmp)出力例
※bmp形式のファイルを直接アップロードできなかったので、jpeg形式に保存しなおしたものになります。

dlang1.jpg

参考情報

IShellItemImageFactory
SHCreateItemFromParsingName
UuidFromString

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?