EternalWindows
ShellImageData / TranscodeImage

これまで取り上げてきたShellImageDataは、画像を描画するためのAPIでしたが、 今回はTranscodeImageという画像を変換するAPIを取り上げます。 TranscodeImageはWidows Vistaから登場したAPIであり、 ビットマップとJPEGの相互変換をサポートします。 ITranscodeImage::TranscodeImageを呼び出せば、実際に変換を行うことができます。

HRESULT ITranscodeImage::TranscodeImage(
  IShellItem *pShellItem,
  UINT uiMaxHeight,
  UINT uiMaxWidth,
  TI_FLAGS flags,
  IStream *pvImage,
  UINT *puiWidth,
  UINT *puiHeight
);

pShellItemは、変換元のファイルを識別するIShellItemを指定します。 uiMaxHeightは、変換後のイメージの幅を指定します。 uiMaxWidthは、変換後のイメージの高さを指定します。 flagsは、変換したい形式を表す定数を指定します。 ビットマップに変換する場合はTI_BITMAPを指定し、 JPEGに変換する場合はTI_JPEGを指定します。 pvImageは、変換後のデータを受け取るストリームを指定します。 puiWidthは、変換後のイメージの幅を受け取る変数のアドレスを指定します。 puiHeightは、変換後のイメージの高さを受け取る変数のアドレスを指定します。

今回のプログラムは、ビットマップファイルをJPEGファイルに変換します。 TranscodeImageを使用する場合は、imagetranscode.hのインクルードとtranscodeimageuid.libへのリンクが必要になります。

#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <imagetranscode.h>

#pragma comment (lib, "shlwapi.lib")
#pragma comment (lib, "transcodeimageuid.lib")

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	HRESULT          hr;
	HANDLE           hFile;
	PIDLIST_ABSOLUTE pidlAbsolute;
	IStream          *pStream;
	IShellItem       *pShellItem;
	ITranscodeImage  *pTranscodeImage;
	TCHAR            szFilePathSrc[] = TEXT("C:\\sample.bmp");
	TCHAR            szFilePathDest[] = TEXT("C:\\sample.jpg");

	CoInitialize(NULL);
	
	hr = CoCreateInstance(CLSID_ImageTranscode, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pTranscodeImage));
	if (FAILED(hr)) {
		CoUninitialize();
		return 0;
	}

	hr = SHParseDisplayName(szFilePathSrc, NULL, &pidlAbsolute, 0, NULL);
	if (FAILED(hr)) {
		MessageBox(NULL, TEXT("変換元ファイルが存在しません。"), NULL, MB_ICONWARNING);
		pTranscodeImage->Release();
		CoUninitialize();
		return 0;
	}

	SHCreateShellItem(NULL, NULL, pidlAbsolute, &pShellItem);

	hFile = CreateFile(szFilePathDest, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		MessageBox(NULL, TEXT("変換先ファイルの作成に失敗しました。"), NULL, MB_ICONWARNING);
		pShellItem->Release();
		pTranscodeImage->Release();
		CoUninitialize();
		return 0;
	}

	CloseHandle(hFile);
	SHCreateStreamOnFile(szFilePathDest, STGM_READWRITE, &pStream);
	
	pTranscodeImage->TranscodeImage(pShellItem, 0, 0, TI_JPEG, pStream, NULL, NULL);
	pStream->Commit(STGC_DEFAULT);

	MessageBox(NULL, TEXT("終了します。"), TEXT("OK"), MB_OK);

	pStream->Release();
	pShellItem->Release();
	pTranscodeImage->Release();
	CoUninitialize();

	return 0;
}

ITranscodeImage::TranscodeImageを呼び出すためには、変換元のファイルを識別するIShellItemと、 変換先のファイルを識別するIStramが必要になります。 前者については、SHParseDisplayNameでファイルパスからPIDLを取得し、 これをSHCreateShellItemに指定することで取得できます。 一方、後者についてはCreateFileで空のファイルを作成し、 これをSHCreateStreamOnFileでストリームとしてオープンします。 このストリームはファイルに関連付けられているため、 ストリームへの書き込みはファイルに反映されることになります。 ITranscodeImage::TranscodeImageの呼び出しは、次のようになっています。

pTranscodeImage->TranscodeImage(pShellItem, 0, 0, TI_JPEG, pStream, NULL, NULL);
pStream->Commit(STGC_DEFAULT);

第2引数と第3引数は変換後のサイズを指定しますが、0を指定した場合は変換元と同一のサイズになります。 第4引数にTI_JPEGを指定しているため、JPEGへの変換が行われることになります。 IStream::Convertを呼び出すと、変換されたデータが実際にストリームへ書き込まれます。


戻る