2016-06-22 19 views
4

Pourquoi les lignes, etc. ne seront-elles pas anti-aliasées?Comment activer l'anti-crénelage lors du rendu de WMF vers BitMap dans C#/WPF/WinForms?

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); 
} 

La fonction de délégué ressemble à ceci:

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; 
} 

Ai-je besoin de passer outre PlayRecord pour un type spécifique d'obtenir ici anti-aliasing?

Les fichiers WMF proviennent d'AutoCAD, si cela peut vous aider.

+0

Comment est-ce que cela concerne WPF? 'Graphics' provient de' System.Drawing', 'Metafile' provient de' System.Drawing.Image', les deux espaces de noms de WinForms. – Clemens

+0

Je l'utilise dans une application WPF, mais oui, probablement pas lié. Je vais mettre à jour les tags. – Macke

Répondre

3

Cela n'est pas possible dans GDI + en utilisant un métafichier WMF, mais avec EMF Plus. Vous pouvez convertir à EMF Plus à la source, ou à la volée avec une méthode GDI + mal documentée (voir ci-dessous). GDI (pas GDI +) rend le fichier WMF sans utiliser le compositing de l'objet GDI + Graphics sous-jacent, il s'agit simplement d'une énumération des appels GDI directs. See this question for more, but all answers say about the same thing.

Si vous pouvez convertir le fichier en EMF Plus, cela utilisera les méthodes GDI + pour rendre le contenu et utiliser la composition GDI +, y compris l'anti-aliasing. Si vous utilisez déjà WPF, vous pouvez également envisager d'exporter vers XPS que WPF peut rendre anti-aliasé.

Si vous ne pouvez pas convertir à la source, vous pouvez appeler une méthode GDI + à partir de C#, mais ce n'est pas élégant. Vous devez avoir accès aux poignées natives utilisées par les classes System.Drawing:

[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); 

Vous utilisez ce code similaire avec les éléments suivants:

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. Il convertit un fichier WMF (drawing.wmf) en un métafichier EMF Plus et l'affiche dans le panneau des résultats.

fichier WMF dans Paint: WMF file with no anti-aliasing

converti EMF + fichier dans Paint: EMF+ file with anti-aliasing


Par souci d'exhaustivité, la méthode GdipConvertToEmfPlus ci-dessus fait partie de ce qu'on appelle le "flat API "de GDI +. Son but original était de ne servir que les classes GDI + C++. L'API C++ qui utilise cette méthode est appelée Metafile.ConvertToEmfPlus.

+0

Merci! Je ne peux pas vraiment faire grand-chose à propos de la source de la WMF (AutoCAD LT), donc un peu de nativité est très bien dans ce cas. Je vais essayer et revenir si ça marche, ce à quoi il devrait ressembler (étant donné mon expérience WMF/EMF/GDI + limitée). (Je pensais que les fonctions GDI supporteraient un drapeau global "AntiAlias" et j'ai juste raté lequel.) – Macke

+0

Je n'y arrive pas. (ceci, g) devrait être (graphiques, g), non? Puis j'obtiens isSuccess = true, mais le constructeur Metafile échoue avec "erreur générique System.Runtime.InteropServices.ExternalException (0x80004005): Une erreur générique s'est produite dans GDI +." En outre, imageAttr ne semble pas être utilisé du tout? – Macke

+0

Vous avez raison, le code n'est pas prêt à être utilisé et suppose que vous ayez un attribut ImageAttributes, ce que vous ne pouvez pas faire. Avez-vous un WMF que vous pouvez partager pour reproduire le problème? – codekaizen