2016-06-22 15 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

나는 거기에 도착하지 않습니다. (this, g)는 (graphics, g)이어야합니다, 맞습니까? 그런 다음 isSuccess = true, 메타 파일 생성자가 "일반 오류 System.Runtime.InteropServices.ExternalException (0x80004005) : GDI +에서 일반 오류가 발생했습니다."오류가 발생합니다. " 또한 imageAttr이 전혀 사용되지 않는 것 같습니다. – Macke

+0

맞습니다. 코드를 사용할 준비가되지 않았으며 ImageAttributes가 있다고 가정합니다. 문제를 재현하기 위해 공유 할 수있는 WMF가 있습니까? – codekaizen