Open janseris opened 2 years ago
@JeremyKuhne Having played with this a lot, I noticed that the offset of the GraphicsPath containing string is probably caused by the fact that for different string content, a different offset is generated because different symbols are sized differently and might reach the max value which is that offset of the GraphicsPath bounding rectangle from the original point would be 0. I have not tested this though. And if this is true, the offset is not an issue.
I have created a sample project which might help illustrating this (among other different things): https://github.com/janseris/GraphicsPathRotatedStringDrawingIssue
you can use Graphics.MeasureCharacterRanges to get tight bounds for Graphics.DrawString
.
Never used GraphicsPath
so no idea why it interprets font size differently than the rest of the APIs.
@janseris Sorry that I couldn't look at this any sooner. One fundamental difference is that when you draw directly to the Graphics
object a scale factor is applied to the em size based on the font unit. This isn't done when writing to a path.
The logic looks something like this:
public static float EmScale(Font font, Graphics g)
{
switch (font.Unit)
{
case GraphicsUnit.Document:
return g.DpiX / 300.0f / g.PageScale;
case GraphicsUnit.Point:
return g.DpiX / 72.0f / g.PageScale;
case GraphicsUnit.Inch:
return g.DpiX / g.PageScale;
case GraphicsUnit.Millimeter:
return g.DpiX / 25.4f / g.PageScale;
case GraphicsUnit.Display:
case GraphicsUnit.Pixel:
case GraphicsUnit.World:
default:
return 1.0f;
}
}
If you use this logic to multiply the em parameter for AddString
you'll get the right scale.
I don't know much about the details of how outputting to path differs from rendering to pixels outside of that. Unfortunately I probably won't get a chance to dig into that part in the near future.
This issue is now marked as "help wanted", and we’re looking for a community volunteer to work on this issue. If we receive no interest in 180 days, we will close the issue. To learn more about how we handle feature requests, please see our documentation.
Happy Coding!
.NET version
.NET Framework 4.7.2
Did it work in .NET Framework?
No
Did it work in any of the earlier releases of .NET Core or .NET 5+?
probably in none
Issue description
What was my initial goal:
GraphicsPath
sample does but its size is wrong)This seems like an impossible task with current WinForms API because there are two string size calculations which produce different results and both are wrong.
Graphics
is approx. to 90 % right whileGraphicsPath
is like 60 % right or less,Drawing a string with font size 60 points on coordinates [200, 200] with Graphics and GraphicsPath produces two very different results (shown by text). String size calculation using
Graphics.MeasureString
andGraphicsPath.GetBounds
methods produces two very different results (shown by rectangles).Steps to reproduce
WindowsFormsApp2.zip
Note: because of the
GraphicsPath
behavior, the best size calculation (fit into rectangle) can be done by bruteforcing font size from largest to lowest usingGraphicsPath
withGetBounds
. However the result works fine only for drawing byGraphicsPath
(if drawn byGraphics
with font size calculated usingGraphicsPath
, the text will be much bigger because font sizes returned byGraphicsPath
are very small (unrealistic))GraphicsPath
only does well is calculating the bounding rectangle of the string (wrong font size and shifted position!)Edit: this project shows how to get the drawn position of
GraphicsPath
right, however it is kinda complicated because ifGraphicsPath
contains multiple objects, this must probably be done for every object (create an additionalGraphicsPath
object, measure size and offset, drop theGraphicsPath
object and then use the correction to draw the actualGraphicsPath
object): GraphicsPath corrected drawing location.zip