web-dev-qa-db-ja.com

GDI + / C#:画像をEMFとして保存する方法は?

Image.Saveメソッドを使用して画像をEMF/WMFに保存すると、例外が発生します( http://msdn.Microsoft.com/en-us/library/ktx83wah.aspx

画像をEMF/WMFに保存する別の方法はありますか?利用可能なエンコーダーはありますか?

19
EricSch

Imageは抽象クラスです。何をしたいかは、MetafileBitmapのどちらを扱っているかによって異なります。

GDI +で画像を作成し、それをEMFとして保存するのは、Metafileで簡単です。Mikeの post

_var path = @"c:\foo.emf"
var g = CreateGraphics(); // get a graphics object from your form, or wherever
var img = new Metafile(path, g.GetHdc()); // file is created here
var ig = Graphics.FromImage(img);
// call drawing methods on ig, causing writes to the file
ig.Dispose(); img.Dispose(); g.ReleaseHdc(); g.Dispose();
_

これは、ほとんどの場合に実行したいことです。これは、EMFの目的:ベクター画像をGDI +描画コマンドの形式で保存するためです。

上記のメソッドを使用してig.DrawImage(your_bitmap)を呼び出すことにより、BitmapをEMFファイルに保存できますが、これはラスターデータを魔法のように隠蔽しないことに注意してくださいベクトル画像に。

21
user120789

私の記憶が正しければ、Metafile.GetHenhmetafile()、API GetEnhMetaFileBits()、Stream.Write()の組み合わせで実行できます。

[DllImport("gdi32")] static extern uint GetEnhMetaFileBits(IntPtr hemf, uint cbBuffer, byte[] lpbBuffer);


IntPtr h = metafile.GetHenhMetafile();
int size = GetEnhMetaFileBits(h, 0, null);
byte[] data = new byte[size];
GetEnhMetaFileBits(h, size, data);
using (FileStream w = File.Create("out.emf")) {
    w.Write(data, 0, size);
}
// TODO: I don't remember whether the handle needs to be closed, but I guess not.

これが私がそれを持っていたときに私が問題を解決した方法だと思います。

12
erikkallen

質問は、「画像をEMF/WMFに保存する別の方法はありますか?」でした。 「メタファイルとは」、「メタファイルの作成方法」、「グラフィックスでメタファイルを使用する方法」ではありません。

また、「EMF/WMFを保存する方法」というこの質問に対する回答も探しています。

  Graphics grfx = CreateGraphics();
  MemoryStream ms = new MemoryStream();
  IntPtr ipHdc = grfx.GetHdc();

  Metafile mf = new Metafile(ms, ipHdc);

  grfx.ReleaseHdc(ipHdc);
  grfx.Dispose();
  grfx = Graphics.FromImage(mf);

  grfx.FillEllipse(Brushes.Gray, 0, 0, 100, 100);
  grfx.DrawEllipse(Pens.Black, 0, 0, 100, 100);
  grfx.DrawArc(new Pen(Color.Red, 10), 20, 20, 60, 60, 30, 120);
  grfx.Dispose();

  mf.Save(@"C:\file.emf", ImageFormat.Emf);
  mf.Save(@"C:\file.png", ImageFormat.Png);

どちらの場合も、画像はpng形式で保存されます。そして、これは私が解決できない問題です:/

3
Greg

メタファイルは、一連のGDI操作を記録するファイルです。画像を生成した元の一連の操作がキャプチャされるため、スケーラブルであり、記録された座標をスケーリングできます。 。

.NETでは、Metafileオブジェクトを作成し、Graphics.FromImageを使用してGraphicsオブジェクトを作成してから、描画手順を実行する必要があると思います。ファイルを描画すると、ファイルは自動的に更新されます。 Graphics.AddMetafileComment のドキュメントに小さなサンプルがあります。

本当にビットマップをメタファイルに保存したい場合は、次の手順を使用してから、Graphics.DrawImageを使用してビットマップをペイントします。ただし、スケーリングされると、StretchBltを使用して引き伸ばされます。

3
Mike Dimmick

また、CopyEnhMetaFileハンドラーを閉じる必要があります。

IntPtr ptr2 = CopyEnhMetaFile(iptrMetafileHandle, "image.emf");
DeleteEnhMetaFile(ptr2);

// Delete the metafile from memory
DeleteEnhMetaFile(iptrMetafileHandle);

それ以外の場合は、プロセスでまだ使用されているため、ファイルを削除できません。

2
Alex

Erikkallenの答えは正しいです。私はこれをVB.NETから試しましたが、それを機能させるには2つの異なるDllImportsを使用する必要がありました。

<System.Runtime.InteropServices.DllImportAttribute("gdi32.dll", EntryPoint:="GetEnhMetaFileBits")> _
    Public Shared Function GetEnhMetaFileBits(<System.Runtime.InteropServices.InAttribute()> ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData As IntPtr) As UInteger
End Function

    <System.Runtime.InteropServices.DllImportAttribute("gdi32.dll", EntryPoint:="GetEnhMetaFileBits")> _
    Public Shared Function GetEnhMetaFileBits(<System.Runtime.InteropServices.InAttribute()> ByVal hEMF As System.IntPtr, ByVal nSize As UInteger, ByVal lpData() As Byte) As UInteger
End Function

最初のインポートは、emfサイズを取得するための最初の呼び出しに使用されます。実際のビットを取得するための2番目のインポート。または、次を使用することもできます。

Dim h As IntPtr = mf.GetHenhmetafile()
CopyEnhMetaFileW(h, FileName)

これにより、emfビットが指定されたファイルに直接コピーされます。

2
Han

マネージド.NETアプリでは、このようなexternやアンマネージドの問題を回避することをお勧めします。代わりに、このスレッドで提供されているマネージドソリューションのようなものをもう少しお勧めします。

。NETを使用して画像をWMFに変換しますか?

P.S.これが私が見つけた最良の答えだったので、私はこの古いスレッドに答えていますが、その後、マネージドソリューションを開発することになり、それが上記のリンクにつながりました。それで、その時間を他の人を救うために、私はこれをそのものに向けると思いました。

1
Brian Kennedy

ベクトルとビットマップについては多くの混乱があるようです。このスレッドのすべてのコードはビットマップ(非ベクトル)ファイルを生成します-ベクトルGDI呼び出しを保持しません。これを自分で証明するには、「EMFパーサー」ツールをダウンロードして検査します。出力ファイル: http://downloads.z​​dnet.com/abstract.aspx?docid=749645

この問題により、多くの開発者が苦悩を検討しています。 Microsoftがこれを修正し、独自のEMF形式を適切にサポートするのであれば、確かに素晴らしいでしょう。

0
Roger

メタファイルオブジェクトのGDI命令をEMFファイルに保存する方法を探していました。Hanの投稿は問題の解決に役立ちました。これは私の前でした。 SOFに参加しました。ありがとう、ハン。これが 試しました です。

 [DllImport( "gdi32.dll")] 
 static extern IntPtr CopyEnhMetaFile(//コピーEMFファイル
 IntPtr hemfSrc、// EMFへのハンドル
 String lpszFile // File 
); 
 
 [DllImport( "gdi32.dll")] 
 static extern int DeleteEnhMetaFile( // EMF 
 IntPtrhemfを削除します// EMF 
); 
 
 //メタファイルを作成するコード
 //メタファイルメタファイル= ... 
 
 //メタファイルへのハンドルを取得
 IntPtr iptrMetafileHandle = metafile.GetHenhmetafile(); 
 
 //メタファイルをにエクスポートイメージファイル
 CopyEnhMetaFile(
 iptrMetafileHandle、
 "image.emf"); 
 
 //メモリからメタファイルを削除します
 DeleteEnhMetaFile(iptrMetafileHandle); 
 
0
BZ1