Gráficos Pasar objeto entre C++ nativo y C#La pérdida de anti-aliasing cuando se comparten entre el objeto Graphics código administrado y no administrado
Actualmente estoy trabajando en una aplicación .NET-como el Paint. Tengo varios tipos de capas que se implementan en C#. Estas capas se dibujan en un objeto de gráficos .NET proporcionado por un control de usuario de WinForms; es similar al control canvas de WPF. La clase base de capa tiene un método Draw que se implementa como sigue:
public void Draw(IntPtr hdc)
{
using (var graphics = Graphics.FromInternalHDC(hdc)
{
// First: Setup rendering settings like SmoothingMode, TextRenderingHint, ...
// Layer specific drawing code goes here...
}
}
Para problemas de rendimiento y la descompilación de que estoy haciendo la composición de las capas en un conjunto de modo mixto ya que también estoy aplicando efectos como bisel o sombra paralela El contenedor, por supuesto, escrito en C++/CLI, se llama directamente desde el control de lienzo y reenvía los metadatos de cada capa y el objeto de gráficos de destino (objeto de gráficos desde mi control de usuario de lienzo escrito C#) a una clase nativa de C++.
C++/CLI Envoltura:
public ref class RendererWrapper
{
public:
void Render(IEnumerable<Layer^>^ layersToDraw, Graphics^ targetGraphics)
{
// 1) For each layer get metadata (position, size AND Draw delegate)
// 2) Send layer metadata to native renderer
// 3) Call native renderer Render(targetGraphics.GetHDC()) method
// 4) Release targetGraphics HDC
};
}
nativo C++ Procesador:
class NativeRenderer
{
void NativeRenderer::Render(vector<LayerMetaData> metaDataVector, HDC targetGraphicsHDC)
{
Graphics graphics(targetGraphicsHDC);
// Setup rendering settings (SmoothingMode, TextRenderingHint, ...)
for each metaData in metaDataVector
{
// Create bitmap and graphics for current layer
Bitmap* layerBitmap = new Bitmap(metaData.Width, metaData.Height, Format32bppArgb);
Graphics* layerGraphics = new Graphics(layerBitmap);
// Now the interesting interop part
// Get HDC from layerGraphics
HDC lgHDC = layerGraphics->GetHDC();
// Call metaData.Delegate and pass the layerGraphics HDC to C#
// By this call we are ending up in the Draw method of the C# Layer object
metaData.layerDrawDelegate(lgHDC);
// Releasing HDC - leaving interop...
layerGraphics->ReleaseHDC(lgHDC);
// Apply bevel/shadow effects
// Do some other fancy stuff
graphics.DrawImage(layerBitmap, metaData.X, metaData.Y, metaData.Width, metaData.Height);
}
}
}
Hasta aquí todo bien. El código anterior funciona casi como se esperaba, pero ...
Problema
La única cosa es que mi implementación actual falta de anti-aliasing y semi transparencia cuando se representa PNG con sombras por ejemplo. Así que solo tengo 2 valores para el canal Alpha: Transparente o Color visible completo en 255. Este efecto secundario hace que dibujar PNG con canal alfa y las fuentes se vean muy feas. No puedo obtener el mismo anti aliasing semitransparente suave y agradable más como antes cuando trabajé con código puro C#.
PERO: Al dibujar una cadena en los gráficos nativos objeto directamente,
layerGraphics->DrawString(...);
anti-aliasing y semi transparencia están de vuelta para siempre. Entonces, el problema solo es evidente al pasar Graphics HDC a .NET.
Preguntas
¿Hay alguna solución/solución para este problema? Intenté crear el mapa de bits directamente en la clase Capa C# y devolver el IntPtr para el HBITMAP al código nativo. Este enfoque funciona, pero en este caso tengo otro problema ya que no puedo encontrar una solución perfecta para convertir HBITMAP en GDI + mapa de bits con canal alfa (el ruido blanco de píxeles rodea los bordes al dibujar fuentes).
¡Gracias por su contribución! :)
Solución de demostración
Adjunto encontrará una solución de demostración aquí: Sources
En esta solución demostración Estoy probando 3 métodos de representación diferentes (implementan en NativeRenderer.CPP), mientras que el primero muestra los problemas descritos:
1) RenderViaBitmapFromCSharp()-a) Crea un nuevo mapa de bits en C++, crea un nuevo objeto Graphics en C++, llama a la C# código de dibujo pasando los Gráficos objeto de C++ HDC - falla
Pero:b) dibujo directamente desde C++ funciona a través del mapa de bits creado demasiado
2) RenderDirectlyFromCSharp() - Crea un nuevo objeto Graphics desde C# Gráficos de manejar en C++ , llama al código de dibujo C# pasando el C++ objeto Graphics HDC - Works
3) RenderDirectlyFromCPP () - Crea un nuevo objeto Graphics de C# Gráficos de manejar en C++, dibuja el texto directamente en C++ - Obras
C++/CLI ve un poco ... código C#! De todos modos, no veo el código que utilizas para escribir la cadena en C++, así que supongo un poco: si estás usando funciones GDI nativas (para metaData.layerDrawDelegate (lgHDC)), la cadena no se representará con la configuración que tenido con GDI + (= transparencia, antialias y cualquier otra cosa de GDI + no se aplicará a una llamada de GDI). –
He cambiado el pseudo código para que sea más C++/CLI. El método para escribir la cadena se acaba de copiar y pegar recortado de la explicación de MSDN de DrawString, nada especial. En el método Dibujar de la capa estoy configurando todas esas configuraciones como SmoothingMode o TextRenderHint al mismo que en el objeto nativo GDI +. – barnacleboy
Las funciones de GDI, como 'ExtTextOut' no admiten un canal alfa, y simplemente pasar un DC con un mapa de bits seleccionado con un canal alfa no los hará alfabéticos. –