Dibujar un solo píxel en Windows Forms

93

Estoy atascado tratando de activar un solo píxel en un formulario de Windows.

graphics.DrawLine(Pens.Black, 50, 50, 51, 50); // draws two pixels

graphics.DrawLine(Pens.Black, 50, 50, 50, 50); // draws no pixels

La API realmente debería tener un método para establecer el color de un píxel, pero no veo ninguno.

Estoy usando C #.

Mark T
fuente
Hice un control que traza algunos gráficos científicos muy agradables (con capacidades adicionales que no necesito disponibles en ningún control comercial). Puedo trazar un punto de datos con y X o un + o un cuadro pequeño. Pero para datos sin importancia, solo quiero un solo píxel.
Mark T
¿Todas las respuestas que veo parecen ser exageradas para un solo píxel? ¿Por qué parece más fácil hacer un búfer [y * ancho + x] = color;
NoMoreZealots

Respuestas:

114

Esto establecerá un solo píxel:

e.Graphics.FillRectangle(aBrush, x, y, 1, 1);
Henk Holterman
fuente
18
¿Quién hubiera adivinado que DrawRectangle dibuja un 2x2 pero FillRectange dibuja un 1x1 con los mismos argumentos? Gracias.
Mark T
9
@Mark: Tiene cierto sentido ... DrawRectangle dice "dibuja un contorno comenzando en xey de este ancho y alto", por lo que dibuja los puntos inicial y final (x, y; x + 1, y ; x, y + 1; x + 1, y + 1) y las líneas entre ellos. FillRectangle dice "dibuja una superficie sólida comenzando en x, y de este ancho y alto". Por cierto, FillRectangle toma un pincel, no un bolígrafo.
Powerlord
5
@R. Bemrose: De hecho, depende del objeto Pen al que pases DrawRectangle(). Si lo tiene Pen.Alignment = PenAlignment.Outset, dibujará Pen.Widthun contorno grueso de píxeles alrededor del rectángulo dado. Pero si lo especifica Pen.Alignment = PenAlignment.Inset, dibujará un "contorno" grueso de píxeles de Pen.Width dentro del rectángulo dado.
Cipi
2
Ésta es una respuesta muy insatisfactoria. Aunque esto establece un solo píxel, el requisito no siempre es establecer un píxel literal. Todas las veces que he necesitado esto, que es a menudo, he necesitado que el punto sea dibujado con el mismo bolígrafo con el que se dibujan las líneas, no con un pincel. En otras palabras, necesitamos una línea que sea más corta que 2 píxeles. Sospecho que eso es lo que necesitaba el OP.
RobertT
6
No me gusta esta respuesta. De esta forma es muy ineficiente.
user626528
19

Solo para mostrar el código completo de la respuesta de Henk Holterman:

Brush aBrush = (Brush)Brushes.Black;
Graphics g = this.CreateGraphics();

g.FillRectangle(aBrush, x, y, 1, 1);
WoodyDRN
fuente
18

El Graphicsobjeto no tiene esto, ya que es una abstracción y podría usarse para cubrir un formato de gráficos vectoriales. En ese contexto, establecer un solo píxel no tendría sentido. El Bitmapformato de imagen tiene GetPixel()y SetPixel(), pero no un objeto gráfico construido sobre uno. Para su escenario, su opción realmente parece ser la única porque no hay una forma única de establecer un solo píxel para un objeto gráfico general (y no sabe EXACTAMENTE qué es, ya que su control / formulario podría tener doble búfer, etc.)

¿Por qué necesita establecer un solo píxel?

Adam Robinson
fuente
9

Cuando estoy dibujando muchos píxeles individuales (para varias pantallas de datos personalizadas), tiendo a dibujarlos en un mapa de bits y luego mostrarlos en la pantalla.

Las operaciones Bitmap GetPixel y SetPixel no son particularmente rápidas porque hacen una gran cantidad de verificación de límites, pero es bastante fácil hacer una clase de 'mapa de bits rápido' que tenga acceso rápido a un mapa de bits.

Will Dean
fuente
2

Página de MSDN en GetHdc

Creo que esto es lo que estás buscando. Necesitará obtener el HDC y luego usar las llamadas GDI para usar SetPixel. Tenga en cuenta que un COLORREF en GDI es un DWORD que almacena un color BGR. No hay canal alfa y no es RGB como la estructura de color de GDI +.

Esta es una pequeña sección de código que escribí para realizar la misma tarea:

public class GDI
{
    [System.Runtime.InteropServices.DllImport("gdi32.dll")]
    internal static extern bool SetPixel(IntPtr hdc, int X, int Y, uint crColor);
}

{
    ...
    private void OnPanel_Paint(object sender, PaintEventArgs e)
    {
        int renderWidth = GetRenderWidth();
        int renderHeight = GetRenderHeight();
        IntPtr hdc = e.Graphics.GetHdc();

        for (int y = 0; y < renderHeight; y++)
        {
            for (int x = 0; x < renderWidth; x++)
            {
                Color pixelColor = GetPixelColor(x, y);

                // NOTE: GDI colors are BGR, not ARGB.
                uint colorRef = (uint)((pixelColor.B << 16) | (pixelColor.G << 8) | (pixelColor.R));
                GDI.SetPixel(hdc, x, y, colorRef);
            }
        }

        e.Graphics.ReleaseHdc(hdc);
    }
    ...
}
ni
fuente
1

Aparentemente, DrawLine dibuja una línea que es un píxel menos que la longitud real especificada. No parece haber un DrawPoint / DrawPixel / otras cosas, pero en su lugar puede usar DrawRectangle con el ancho y el alto establecidos en 1 para dibujar un solo píxel.

Rytmis
fuente
2
Buen intento, pero con el tamaño 1 dibuja 2x2 píxeles. (Dibuje al lado de una línea y verá que tiene el doble de ancho). Y con el tamaño cero, por supuesto, no dibuja nada.
Mark T
Bien, mi error. :) Menos mal que FillRectangle hace el truco.
Rytmis
0

Dibujar una línea de 2px con un lápiz con DashStyle.DashStyle.Dot dibuja un solo píxel.

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        using (Pen p = new Pen(Brushes.Black))
        {
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            e.Graphics.DrawLine(p, 10, 10, 11, 10);
        }
    }
Remolino
fuente