DrawingContext.DrawLine: ¿La pluma no tiene opacidad total?

cuando dibujo algo así (solo dibujos al azar aquí):

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DrawingVisual visual = new DrawingVisual();
        DrawingContext context = visual.RenderOpen();

        Pen pen = new Pen(Brushes.Black, 1);

        context.DrawEllipse(Brushes.YellowGreen, pen, new Point(0,0), 40, 40);

        for (int i = 0; i <= 100 - 1; i++)
          context.DrawLine(new Pen(Brushes.Black, 1), new Point(0, i), new Point(i, i));

        context.Close();

        RenderTargetBitmap bmp = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);

        bmp.Render(visual);
        image1.Source = bmp;
    }
}

los colores de DrawLine y DrawEllipse se mezclan. (Me di cuenta de que es solo con DrawLine que usa un bolígrafo, y no con otras formas como Rectangle y Ellipse, que usan un Brush). Extrañamente, incluso con los colores del LinearGradientBrush de un fondo de Grids subyacente (argh). Me gustaría que estén ordenados en z con opacidad total cada uno.

Aquí el código XAML:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Image Name="image1" Stretch="None" />
</Window>

Gracias por cualquier ayuda.

preguntado el 12 de junio de 12 a las 17:06

Hice una solución utilizando DrawRectangle con un pincel de relleno en lugar de DrawLine con un bolígrafo. Todavía me pregunto por qué los bolígrafos no tienen una opacidad total. -

Pen tiene opacidad total, pero en tu caso, las líneas son tan finas que se vuelven borrosas y parecen semitransparentes. Lea mi respuesta para obtener más información y soluciones sugeridas :). Dibujar rectángulos le permite simular solo líneas horizontales y verticales. Dibujar líneas, pero con mayor anchura debería funcionar ;). -

4 Respuestas

Hay dos problemas de suavizado o subpixelado con RenderTargetBitmap:

1.

Deshabilitar el subpixelado para el mapa de bits en sí (por ejemplo, cuando se representa dentro de un UIElement). esto se resuelve aplicando:

    RenderOptions.SetBitmapScalingMode(image1, BitmapScalingMode.NearestNeighbor);

(donde image1 es el objeto de imagen WPF).

Solo es compatible con .NET 4 y superior. En su caso específico, no importa, ya que las líneas se representan píxel tras píxel.

2.

Deshabilitar el subpixelado al renderizar EN el RenderTargetBitmap. Se puede lograr mediante el método RenderOptions.SetEdgeMode con el valor del parámetro EdgeMode.Aliased.

SIN EMBARGO, este método funcionará solo si:

  • El método se llama para un objeto DrawingGroup.

  • La geometría suavizada se anida solo a través de un compuesto de dibujo normal (por ejemplo, si DrawingGroup contiene un rectángulo con un VisualBrush que encapsula un DrawingVisual, el contenido de ese DrawingVisual se suavizará incluso si utilizó ese método).

Por lo tanto, puede reescribir su código de la siguiente manera:

    DrawingVisual visual = new DrawingVisual();
    DrawingGroup group = new DrawingGroup();

    Pen pen = new Pen(Brushes.Black, 1);

    group.Children.Add(new GeometryDrawing(Brushes.YellowGreen, pen, new EllipseGeometry(new Point(0,0), 40, 40)));

    for (int i = 0; i <= 100 - 1; i++)
      group.Children.Add(new GeometryDrawing(null, new Pen(Brushes.Black, 1), new LineGeometry(new Point(0, i), new Point(i, i))));

    RenderOptions.SetEdgeMode(group, EdgeMode.Aliased);

    DrawingContext context = visual.RenderOpen();
    context.DrawDrawing(group);
    context.Close();

    RenderTargetBitmap bmp = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);

    bmp.Render(visual);
    image1.Source = bmp;

Respondido el 07 de junio de 13 a las 14:06

El código que publicaste está dibujando múltiples líneas delgadas una al lado de la otra. Cada uno de ellos está suavizado y tiene sus lados borrosos. Supongo que el efecto de mezcla de opacidad que describiste ocurre debido a esto.

Si dibujó una línea gruesa (es decir, con 10 de ancho), el efecto no aparecería.

Entonces, la solución depende de qué es exactamente lo que está tratando de lograr:

  • puede intentar deshabilitar el antialiasing, si esto es satisfactorio, para obtener más información al respecto, eche un vistazo aquí: Deshabilitar antialiasing en una imagen WPF
  • dibujar líneas con un Pen que tiene mayor ancho, es decir new Pen(Brushes.Black, 2)
  • en este caso particular de dibujar líneas cercanas entre sí, puede incrementar el contador en 0.5f en lugar de 1, así que reemplace for (int i = 0; i <= 100 - 1; i++) con for (float i = 0.0f; i <= 100 - 1; i+=0.5f).
  • Si no le importa escribir más código, puede crear su propia clase de mapa de bits personalizada que no haga que las imágenes se vean borrosas. Alguna solución está disponible aquí http://www.nbdtech.com/Blog/archive/2008/11/20/blurred-images-in-wpf.aspx y en el sitio al que se hace referencia allí

contestado el 23 de mayo de 17 a las 13:05

No pude dibujar una línea de 1 px de ancho, pero la línea de 2 px se dibuja completamente opaca. Aquí hay un buen ejemplo: daniel-albuschat.blogspot.com/2011/04/… - Monseñor

Otra forma (más fácil) aquí:

https://stackoverflow.com/a/10257614/2463642

Para su ejemplo, solo tiene que crear una clase como:

    public class AliasedDrawingVisual : DrawingVisual
    {
        public AliasedDrawingVisual()
        {
            this.VisualEdgeMode = EdgeMode.Aliased;
        }
    }

y reemplace su instancia de DrawingVisual con AliasedDrawingVisual:

    DrawingVisual visual = new AliasedDrawingVisual(); // Here is the only change
    DrawingContext context = visual.RenderOpen();

    Pen pen = new Pen(Brushes.Black, 1);

    context.DrawEllipse(Brushes.YellowGreen, pen, new Point(0,0), 40, 40);

    for (int i = 0; i <= 100 - 1; i++)
      context.DrawLine(new Pen(Brushes.Black, 1), new Point(0, i), new Point(i, i));

    context.Close();

    RenderTargetBitmap bmp = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);

    bmp.Render(visual);
    image1.Source = bmp;

contestado el 23 de mayo de 17 a las 13:05

Me he encontrado con el mismo problema con la representación programática para DrawingContext. La única forma en que funciona es usar GuidelineSet: http://wpftutorial.net/DrawOnPhysicalDevicePixels.html

contestado el 05 de mayo de 15 a las 13:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.