How to draw a subpixel line

You could hack it by drawing everything x2 and then scale it down:

        Image img2x = new Bitmap(256*2, 256*2);
        Graphics g2x = Graphics.FromImage(img2x);
        g2x.SmoothingMode = SmoothingMode.AntiAlias;
        g2x.DrawLine(new Pen(Color.Red, 0.5f*2), 0, 100*2, 255*2, 110*2);

        Image img = new Bitmap(256, 256);
        Graphics g = Graphics.FromImage(img);
        g.SmoothingMode = SmoothingMode.AntiAlias;
        g.DrawImage(img2x, 0, 0, 256, 256);

        g.DrawLine(new Pen(Color.Red, 1f), 0, 110, 255, 120);

        img.Save(@"c:\tmep\test.png", ImageFormat.Png);

enter image description here


Subpixel lines can be drawn as thin rectangles.
Here's how to do this:

    public static class GraphicsExtensions
    {
        public static void DrawLineAnyWidth(this Graphics gr, Pen pen, PointF pt1, PointF pt2)
        {
            if (pen.Width > 1.5f)
            {
                gr.DrawLine(pen, pt1, pt2);
            }
            else
            {
                var poly = new PointF[5];
                var h = pen.Width * 0.5f;
                var br = new SolidBrush(pen.Color);
                poly[0] = SidePoint(pt1, pt2, -h);
                poly[1] = SidePoint(pt1, pt2, h);
                poly[2] = SidePoint(pt2, pt1, -h);
                poly[3] = SidePoint(pt2, pt1, h);
                poly[4] = poly[0];
                gr.FillPolygon(br, poly);
                br.Dispose();
            }
        }
        static PointF SidePoint(PointF pa, PointF pb, float h)
        {
            float Dx = pb.X - pa.X;
            float Dy = pb.Y - pa.Y;
            float D = (float)Math.Sqrt(Dx * Dx + Dy * Dy);
            return new PointF(pa.X + Dy * h / D, pa.Y - Dx * h / D);
        }
    }

Example:

    var bmp = new Bitmap(200, 350);
    using (var gr = Graphics.FromImage(bmp))
    {
        gr.Clear(Color.White);
        gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        var pen = new Pen(Color.IndianRed);
        for (int i = 1; i < 30; i++)
        {
            var pa = new PointF(50, 20 + i * 10);
            var pb = new PointF(150, 30 + i * 10);
            pen.Width = i * 0.1f;
            gr.DrawLineAnyWidth(pen, pa, pb);
        }
    }

Result of example:
enter image description here


According to the documentation for Pen ,

The Width property is set to the value specified in the width parameter. A width of 0 will result in the Pen drawing as if the width were 1.

It may be that that applies to any width less than one, not just widths that are precisely equal to 0.