WinXPのエクスプローラの画面でEMFファイルを右クリックし、
プロパティ→概要と選ぶとEMFファイルの「水平方向の解像度」「垂直方向の解像度」
というEMFファイルの属性を目視できる(Vistaだと見られないようです)のですが,
VC++6.0からこの属性を参照する方法はないでしょうか。ご教示願います。
#
#ちなみに [ GetEnhMetaFileHeader ] で
# [ ENHMETAHEADER ] の [ rclBounds ] [ rclFrame ]
# [ szlDevice ] [ szlMillimeters ] を参照してみましたが駄目そうです。
Windows Vistaの場合ですが,
Microsoft Office Picture Manager でEMFを開いて
表示画面で右クリック→[プロパティ]として
右側に表示される[画像のプロパティ]で[詳細]を選ぶと,
「水平方向の解像度」「垂直方向の解像度」ともに
小数2桁の精度で表示されるみたいです。
Microsoft Office Picture Manager がインスコされているPCではお試しあれー。
XPでもVistaでもそうですが,画像のピクセル数も表示されますね。
EMFのピクセル数って何? と思ってしまいますが。
これもVC++6.0から参照できると嬉しいです。
近い値なら取得できたんですが、ぴったりにはなりませんねぇ。
まず解像度の方は、ENHMETAHEADER の szlMillimeters の値をインチに直して(1 インチ
は 25.4mm なので、25.4 で割る)、szlDevice の値を、そのインチ数で割ってやれば、
それらしい値が求まります。
解像度の単位は dpi(dots per inch)なので、ドット数をインチで割ればいいわけです
ね。
水平方向解像度は szlDevice.cx / ( szlMillimeters.cx / 25.4 ) で、垂直方向解像度
は szlDevice.cy / ( szlMillimeters.cy / 25.4 ) で求められます。
ピクセル数は微妙ですね。
解像度と、mm 単位でのサイズがあれば求められるはずです。
szlDevice を szlMilimeters で割ってやれば、mm 単位での解像度(dots per
milimeters)が求められます。
それに、mm 単位でのサイズである rclFrame をかけてやればいいと思うのですが、どう
もエクスプローラ表示とは 1px くらいの誤差が出ますね。
一応、幅は szlDevice.cx / szlMilimeters.cx * ( rclFrame.right - rclFrame.left )
で、高さは szlDevice.cy / szlMilimeters.cy * ( rclFrame.bottom - rclFrame.top )
で近似値が求まります。
エクスプローラが表示するそのままの情報を取得するサンプルを作ってみました。
ちょっと長いです。
#include <windows.h>
#include <tchar.h>
#include <propkey.h>
#include <stdio.h>
#include <locale.h>
int main()
{
setlocale( LC_ALL, japanese );
HRESULT hr = CoInitialize( NULL );
CLSID clsid;
CLSIDFromString( L{eb9b1153-3b57-4e68-959a-a3266bc3d7fe}, &clsid );
IPropertySetStorage * ppsstg = NULL;
hr = CoCreateInstance(
clsid, NULL, CLSCTX_ALL, IID_IPropertySetStorage, ( void ** )
&ppsstg );
if( SUCCEEDED( hr ) )
{
IPersistFile * ppf = NULL;
hr = ppsstg->QueryInterface( IID_IPersistFile, ( void ** )
&ppf );
if( SUCCEEDED( hr ) )
{
hr = ppf->Load( LTest.emf, STGM_DIRECT |
STGM_READ | STGM_SHARE_EXCLUSIVE );
ppf->Release();
if( SUCCEEDED( hr ) )
{
IEnumSTATPROPSETSTG * pespss = NULL;
hr = ppsstg->Enum( &pespss );
if( SUCCEEDED( hr ) )
{
STATPROPSETSTG spss;
ULONG celtFetched = 0;
while( SUCCEEDED( hr = pespss-
>Next( 1, &spss, &celtFetched ) ) && celtFetched == 1 )
{
IPropertyStorage * ppstg
= NULL;
hr = ppsstg->Open(
spss.fmtid, STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE, &ppstg );
if( SUCCEEDED( hr ) )
{
IEnumSTATPROPSTG * pesps = NULL;
hr = ppstg->Enum
( &pesps );
if( SUCCEEDED(
hr ) )
{
STATPROPSTG sps;
ULONG
celtFetched2 = 0;
while
( SUCCEEDED( hr = pesps->Next( 1, &sps, &celtFetched2 ) ) && celtFetched2 == 1 )
{
PROPSPEC ps;
ps.ulKind = PRSPEC_PROPID;
ps.propid = sps.propid;
PROPVARIANT pv;
PropVariantInit( &pv );
if( SUCCEEDED( hr = ppstg->ReadMultiple( 1, &ps, &pv ) ) )
{
if( spss.fmtid == FMTID_ImageSummaryInformation )
{
switch( sps.propid )
{
case 3:
_tprintf( _T( 幅:%u px\n ), pv.uiVal );
break;
case 4:
_tprintf( _T( 高さ:%u px\n ),
pv.uiVal );
break;
case 5:
_tprintf( _T( 水平解像度:%u dpi\n ),
pv.uiVal );
break;
case 6:
_tprintf( _T( 垂直解像度:%u dpi\n ),
pv.uiVal );
break;
case 7:
_tprintf( _T( ビット数:%u\n ),
pv.uiVal );
break;
case 12:
_tprintf( _T( フレーム数:%u\n ),
pv.uiVal );
break;
case 13:
_tprintf( _T( 次元:%ls\n ),
pv.pwszVal );
break;
}
}
PropVariantClear( &pv );
}
if( sps.lpwstrName != NULL )
{
CoTaskMemFree( ps.lpwstr );
}
}
pesps-
>Release();
}
ppstg->Release
();
}
}
pespss->Release();
}
}
}
ppsstg->Release();
}
CoUninitialize();
return 0;
}
変に改行されちゃったな…
なお、このコードは、emf に限らず、エクスプローラの「概要」タブの情報を汎用的に取
得するのにも応用できます。
>シャノン様
お返事ありがとうございます。
シャノン様の最初の回答(2008/04/09(水) 17:11:03)の方式で,
水平方向の解像度・垂直方向の解像度は小数2桁目の数字に±1程度の
誤差がある程度で求めることが出来ました。
ピクセル数は本当に微妙ですね……。
私の環境でも500px四方程度のEMFで1px程度の誤差が出ます。
#rclFrameはmmでなくHimetric(1/100mm)なので100で割りました。
次に示していただいた解法ですが,
fatal error C1083: インクルード ファイルがオープンできません。'propkey.h': No such file or
directory
となってしまい,テストできません。
「propkey.h」でぐぐってみましたが,ちょっとどういうものか分かりませんでした。
解決策をご教授いただけたら幸いです。宜しくお願いします。
>シャノン様
すみません、開発環境を明示していませんでした。
XPSP2,VC++6.0で開発しております。
http://blackfin.g.hatena.ne.jp/suikan/20061230
を見ると,propkey.hは
VC2005必須のようですね。(他にも要件がありそうです。)
VC++6.0では駄目そうです。
ご呈示いただいたソースを検証できないのは誠に申し訳ない気分なのですが,
これにて解決とさせていただきます。
# まだ見てるかな
propkey.h は FMTID_ImageSummaryInformation の定義に使っています。
もし VC++ 6.0 に付属のヘッダファイルの中に、これが定義されているものがあれば、
それに書き換えてください。
なければ、自分で定義してやればいいはずです。
DEFINE_GUID(FMTID_ImageSummaryInformation, 0x6444048f, 0x4c8b, 0x11d1, 0x8b,
0x70, 0x08, 0x00, 0x36, 0xb1, 0x1a, 0x03 )
で大丈夫かな?
ちなみに FMTID_ImageSummaryInformation は {6444048F-4C8B-11D1-8B70-
080036B11A03} です。
>シャノン様
お返事が遅くなって申し訳ありません。
金曜日の書き込み,さっきソースに組み込みました。
うまく行きました! 非常に助かります! 本当にありがとうございました!
# 私の場合は GUID を定義するために<INITGUID.H>をインクルードする必要がありまし
た。
#詳細→ http://support.microsoft.com/kb/130869/ja