2016-06-22 9 views
4

これを行うときにラインなどがアンチエイリアス処理されないのはなぜですか?C#/ WPF/WinFormsでWMFをBitMapにレンダリングするときにアンチエイリアスを有効にするには?

using (var myGraphics = Graphics.FromImage(bitmap)) 
{ 
myGraphics.CompositingQuality = CompositingQuality.HighQuality; 
myGraphics.SmoothingMode = SmoothingMode.HighQuality; 
myGraphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; 

myGraphics.Clear(backgroundColor); 

myGraphics.EnumerateMetafile(m_metafile, new Point(0, 0), m_metafileDelegate); 
} 

デリゲート関数は次のようになります。

private bool MetafileCallback(EmfPlusRecordType recordType, int flags, int dataSize, IntPtr data, PlayRecordCallback callbackData) 
{ 
     byte[] dataArray = null; 
     if (data != IntPtr.Zero) 
     { 
      // Copy the unmanaged record to a managed byte buffer 
      // that can be used by PlayRecord. 
      dataArray = new byte[dataSize]; 
      Marshal.Copy(data, dataArray, 0, dataSize); 
     } 

     m_metafile.PlayRecord(recordType, flags, dataSize, dataArray); 

     return true; 
} 

は、私がここにアンチエイリアシングを得るために、特定のタイプのためにPlayRecordを上書きする必要がありますか?

WMFはAutoCADから提供されています。

+0

これはWPFとどのように関連していますか? 'Graphics'は' System.Drawing'に由来し、 'Metafile'はWinFormsの両方の名前空間である' System.Drawing.Image'に由来します。 – Clemens

+0

私はWPFアプリケーションで使用していますが、おそらく関係はありません。タグを更新します。 – Macke

答えて

3

これは、WMFメタファイルを使用するGDI +では不可能ですが、EMF Plusを使用しています。あなたはソースでEMF Plusに変換することができます。また、文書化されていないGDI +メソッド(下記参照)を使用してオンザフライで変換することもできます。

GDI(GDI +ではなく)は、GDI + Graphicsオブジェクトの合成を使用せずにWMFファイルをレンダリングします。これは直接GDI呼び出しの列挙です。 See this question for more, but all answers say about the same thing

ファイルをEMF Plusに変換できる場合は、GDI +メソッドを使用してコンテンツをレンダリングし、アンチエイリアスを含むGDI +合成を使用します。既にWPFを使用している場合は、WPFがアンチエイリアスをレンダリングできるXPSにエクスポートすることも検討してください。

ソースで変換できない場合は、C#からGDI +メソッドを呼び出すことはできますが、それは優雅ではありません。あなたは次のようなコードでこれを使用することになり

[DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] 
internal static extern int GdipConvertToEmfPlus(HandleRef graphics, 
               HandleRef metafile, 
               out Boolean conversionSuccess, 
               EmfType emfType, 
               [MarshalAsAttribute(UnmanagedType.LPWStr)] 
               String description, 
               out IntPtr convertedMetafile); 

using (var graphics = Graphics.FromImage(bmp)) 
using (var metafile = Metafile.FromFile(@"drawing.wmf")) 
using (var imageAttr = new ImageAttributes()) 
{ 
    graphics.SmoothingMode = SmoothingMode.AntiAlias; 
    graphics.CompositingQuality = CompositingQuality.HighQuality; 
    graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; 

    var metafileHandleField = typeof(Metafile).GetField("nativeImage", BindingFlags.Instance | BindingFlags.NonPublic); 
    var imageAttributesHandleField = typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.Instance | BindingFlags.NonPublic); 
    var graphicsHandleProperty = typeof(Graphics).GetProperty("NativeGraphics", BindingFlags.Instance | BindingFlags.NonPublic); 
    var setNativeImage = typeof(Image).GetMethod("SetNativeImage", BindingFlags.Instance | BindingFlags.NonPublic); 
    IntPtr mf = (IntPtr)metafileHandleField.GetValue(metafile); 
    IntPtr ia = (IntPtr)imageAttributesHandleField.GetValue(imageAttr); 
    IntPtr g = (IntPtr)graphicsHandleProperty.GetValue(graphics); 

    Boolean isSuccess; 
    IntPtr emfPlusHandle; 
    var status = GdipConvertToEmfPlus(new HandleRef(graphics, g), 
             new HandleRef(metafile, mf), 
             out isSuccess, 
             EmfType.EmfPlusOnly, 
             "", 
             out emfPlusHandle); 
    if (status != 0) 
    { 
     throw new Exception("Can't convert"); 
    } 

    using (var emfPlus = (Metafile)System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject(typeof(Metafile))) 
    { 
     setNativeImage.Invoke(emfPlus, new object[] { emfPlusHandle }); 

     // use EnumerateMetafile on emfPlus as per your example code or save it: 
     emfPlus.Save(@"drawing.emf"); 
    } 
} 

Here's a working example for LinqPadあなたはたSystem.Drawingクラスによって使用されるネイティブハンドルへのアクセスを持っている必要があります。 WMFファイル(drawing.wmf)をEMF Plusメタファイルに変換し、結果パネルに表示します。

ペイントでWMFファイル: WMF file with no anti-aliasing

ペイントで変換EMF +ファイル: EMF+ file with anti-aliasing


完全を期すために、上記GdipConvertToEmfPlus方法は、「flat APIとして知られるものの一部であります"GDI +の。その元の目的は、GDI + C++クラスのみを提供することでした。このメソッドを使用するC++ APIはMetafile.ConvertToEmfPlusと呼ばれます。

+0

ありがとう!私は実際にWMF(AutoCAD LT)のソースについて多くのことをすることはできないので、この場合は少々本物です。私はそれを試してみると、それが動作するように見える(私の限定されたWMF/EMF/GDI +の経験を与えれば)。 (私は、GDI関数がいくつかのグローバルな "AntiAlias"フラグをサポートしていると考えていましたが、私はちょうどそれを逃しました)。 – Macke

+0

私はそこには到着しません。 (これ、g)は(グラフィックス、g)、そうでしょうか?それから、isSuccess = trueが返されますが、メタファイルのコンストラクタは "Generic error System.Runtime.InteropServices.ExternalException(0x80004005):GDI +で一般的なエラーが発生しました。また、imageAttrはまったく使用されていないようですか? – Macke

+0

あなたが正しいです、コードは使用する準備ができておらず、ImageAttributesがあるかもしれないと想定しています。問題を再現するために共有できるWMFをお持ちですか? – codekaizen

関連する問題