4

I need to create a pen which draws with a width of 0.5 mm regardless of the scale of the graphics transformation matrix. Here is what I am doing:

Note: The sample code is C++/CLI but answers using C# are welcome.

// assume that g is a Graphics object
int dpi = g->DpiX;
float dotsPerHalfInch = dpi * 0.5;

// to extract scale factor from the transformation matrix...
// create two points distant one unit apart...
array<PointF> ^points = gcnew array<PointF>{
    PointF(0.0f, 0.0f), PointF(1.0f, 0.0f)
};

// transform them...
g->Transform->TransformPoints(points);

// get distance after transformation...
float dX = points[1].X - points[0].X;
float dY = points[1].Y - points[0].Y;
float distance = Math::Sqrt(dX * dX + dY * dY);

// reverse the effects of any scale factor in graphics transform
float penWidth = dotsPerHalfInch / distance;

Pen ^halfInchPen = gcnew Pen(Color::Black, penWidth);

Doesn't seem to work on screen (96 dpi) ...gives me a pixel wide pen. On the PDF printer (600 dpi) it gives me a pen far more thicker than half an inch.

What am I doing wrong? What is the correct way to create a non-scaling pen in GDI?

Agnel Kurian
  • 57,975
  • 43
  • 146
  • 217

3 Answers3

7

The Pen itself has a Transform attribute. Use that one with the inverse of your global scale-Transform on the graphics object. Set the pen width to a constant of whatever you want.

Also there is a bug in gdi+ making pens of width<1.5 not being able to scale.

Good link: https://web.archive.org/web/20131221083258/http://bobpowell.net/scalepens.aspx

(Also there is a PageUnit attribute on the graphics object with ability to change between pixels, millimeters, etc. Dunno if that could help)

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
1

I know this is a super-duper old post, but I have found something interesting regarding scaling pen widths, as I am working on doing just that now.

Maybe it's because I'm using .Net Core 3? Anyway, I ScaleTransform'ed and TranslateTransform'ed a control so that I could draw lines in a different scale. So far so good. But of course, as most know, the linewidth drawn is also scaled, and is usually an undesirable effect - the line is too thick.

To keep the line at 1 pixel, I have seen the following offered as a solution (ie, adding 0f to the width parameter in the pen constructor:

            Pen penBlack0 = new Pen(Color.Black, 0f);
            sg.Graphics.DrawLine(penBlack0, 10, 20, 100, 50);

But this does not make any difference. The drawn line was still too thick. Also, the Width property of the pen is 1 if you look at it in the debugger, not zero. However, if I do this...

            Pen penBlack0 = new Pen(Color.Black);
            penBlack0.Width = 0f;
            sg.Graphics.DrawLine(penBlack0, 10, 20, 100, 50);

the result is a correct 1 pixel line width drawn.

I'm not sure what the difference in doing this is, or why the Width property is not set to 0f in the constructor.

Anyway, that is how I got over this hurdle.

Mulga Bill
  • 11
  • 2
  • This needs to be in the correct answer. It's confirmed working in .net framework 4.8 as well, so some how if you don't declare it in the pen ctor, then it's going to work, then it will make transform irrelevant to the width of the pen. – mslugx Nov 14 '22 at 03:38
0

Awesome. We had the same issue, when using 0f in ctor was working fine but after some Windows update pen started using scaling factor and as result line became thick. Setting pen width outside of ctor - resolved the issue.

  • This does not really answer the question. If you have a different question, you can ask it by clicking [Ask Question](https://stackoverflow.com/questions/ask). To get notified when this question gets new answers, you can [follow this question](https://meta.stackexchange.com/q/345661). Once you have enough [reputation](https://stackoverflow.com/help/whats-reputation), you can also [add a bounty](https://stackoverflow.com/help/privileges/set-bounties) to draw more attention to this question. - [From Review](/review/late-answers/30269023) – AndrewSilver Nov 06 '21 at 06:28