Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

text scaled wrong (resolution = 100 should be 72) #4304

Open
jordanbrown0 opened this issue Jul 19, 2022 · 62 comments · May be fixed by #4306
Open

text scaled wrong (resolution = 100 should be 72) #4304

jordanbrown0 opened this issue Jul 19, 2022 · 62 comments · May be fixed by #4306

Comments

@jordanbrown0
Copy link
Contributor

jordanbrown0 commented Jul 19, 2022

That seems like a pretty blunt statement, but after some analysis I come to the conclusion that it's true: OpenSCAD text processing scales the text wrong by about 30%.

If you tell OpenSCAD to draw an X at 10 units in the default Liberation Sans, you get an object that's 9.552 units tall. What happened to the other 0.45 units?

If you tell it to draw an X in Arial at 72 units, you get an object that's 71.6 units tall. But if you tell any other application (Word, PowerPoint, CorelDraw) to draw an X in Arial at 72pt, noting that 72pt is one inch, you get an X that's 0.716 inches or about 51.6pt tall. In OpenSCAD, you get an X that's close to the specified size, but in all of the other programs you get an X that's about 70% of the specified size. Why the mismatch?

The answer is buried in the text processing...

FT_Error error = FT_Set_Char_Size(face, 0, scale, 100, 100);

  FT_Error error = FT_Set_Char_Size(face, 0, scale, 100, 100);

The two constant 100s are the answer. They tell FreeType to return results scaled so that one unit is 1/100 inches. (Yes, OpenSCAD is unit-less, but FreeType is not - with this call, the input parameter "scale" is in points (1/72 inch) and the output coordinates are in 1/100 inches.)

The "size" parameter controls the body size of the text, which is roughly and nominally the font ascent plus the font descent. The cap-height of the font is typically 70% or so of that, to allow for descenders.

Thus with size=72 we ask for a 72pt body size, or a body size of an inch, but because of the two 100s we get glyphs with a body size of 100.

It's a total coincidence that the typical ratio for cap height to body size is 72:100 and so the scaling mismatch roughly yields the size equaling the cap height.

This inaccuracy affects both text() and the text metrics functions textmetrics() and fontmetrics(). (But at least they match.)


The picture in font-land is really more complex than this, because body height is not necessarily related to the actual size of the glyphs. Some fonts have glyphs that are taller than their nominal body height, while other fonts have glyphs that are smaller than their nominal body height.


The picture in OpenSCAD internals is really more complex than this, because OpenSCAD has FreeType render glyphs at 100,000 units tall, where units are 1/64pt, and then scales them to the specified size.


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@jordanbrown0
Copy link
Contributor Author

So what to do about it?
a) Ignore it. Pretend that "size" means "cap height", and pretend the difference between that and reality is because of font design and the "some fonts are tall and others are short" issue. Put the actual explanation in a footnote in the documentation.
b) Fix it. Seems like a non-starter; there's just too much legacy to allow for changing the size of all text by ~30%.
c) Provide a UI switch. Also seems like a non-starter, an opportunity for users to get confused because the UI switch doesn't match the expectations of the program they imported.
d) Provide a new parameter to text() and the functions that says in some fashion "do the scaling right". Maybe, but yuck.
e) Provide a new $ variable that, similarly, says "do the scaling right". Also yuck, and an opportunity for problems where the main program's expectations don't match a library's expectations.
f) Say that positive sizes have the legacy behavior and that negative sizes are to be interpreted with "correct" scaling.

@adrianVmariano
Copy link

It seems to me that if something is to be done, option (d) is best: provide a new parameter to text() that does the scaling right. Deprecate the old parameter, but continue to support it for legacy compatibility. This seems like a pretty clean way to transition and not a "yuck".

@t-paul
Copy link
Member

t-paul commented Jul 20, 2022

I agree with @adrianVmariano, giving the parameter a reasonable name pt? points? and making it an error to specify both old and new one seems like a reasonable option that's not going to break anything while providing a path forward.

@adrianVmariano
Copy link

I'm not sure what a reasonable name is, but if pt or point was used it would suggest that the size was in printers points. Since OpenSCAD is dimensionless, that doesn't make sense. It seems like it would need to be something like height or fontsize or scale.

@jordanbrown0
Copy link
Contributor Author

Ah, duh, yes. I was thinking the new parameter would be do_scaling_right=true, but just replacing size would be much better.

Agree that anything referencing points is wrong.

scale: OK,
height: don't like it because it continues the "height of what?" confusion.
fontsize: more verbose than I like.

Other possibilities might include the word "body", e.g. bodysize or even just body.

@jordanbrown0
Copy link
Contributor Author

But, come to think of it, anything that doesn't include "body" will have the "height of what?" problem, so they're all equivalent. And other places in OpenSCAD have height or, better, h.

@jordanbrown0
Copy link
Contributor Author

And even if it does include "body", only font geeks will know what that means, as distinct from any of the other perhaps-relevant measurements.

@adrianVmariano
Copy link

A potential advantage of using jargon like "body" is that people might realize that they don't know what it means rather than making assumptions. I mean, "scale" isn't really any better than height and raises the question of what's the "base" scale. Note that "bodysize" is not less verbose than "fontsize". And at least people think they know what that means.

@jordanbrown0
Copy link
Contributor Author

Would anybody think that height=... or h=... was going to yield a 3D object?

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 20, 2022

We have »height« in linear_extrusion and »h« in cylinders. Squares using size as [x,y]. So for a 2D object h and height works fine but if you assume text could be a 3D object i would assume this is z. So you just need to know text is 2D.

The problem with points is that the rest of openSCAD is Units (metric as 3mf) so this would not be any help to fit fonts onto something without conversion. And there exist different definitions https://en.wikipedia.org/wiki/Point_(typography) - points are also bigger then the actual body height - This is something from ancient times that imho shouldn't be used in digital media.

There is https://en.wikipedia.org/wiki/X-height cap height and ascender height which is probably not what you want.
But as you said https://en.wikipedia.org/wiki/Body_height_(typography) look promessing - So i think Body_height in scadUnits is what you want so a bottom or top aligned letter text size 10 fit on a cube(10) - else you need text/font metrics or resize. But the problem is that »baseline« is the default orientation which is why user probably expect size to be ascender height - so maybe we could use size for that which would only cause a little difference and as people use some padding will hopefully not break a lot of designs - a flag "height="body/acsender/(x)/compatibility or depreciated" could be used to switch

@adrianVmariano
Copy link

Yeah, I think height or h are probably a mistake because they will suggest a 3d extrusion of text.

I don't understand what UBaer21 means about "points are bigger than the actual body height". The point is a unit equal to 1/72 inch. That's it.

Note that body height is the standard way of specifying sizes in typography. When you use other software and request a font by giving a font size you are specifying the body height. If the OpenSCAD font code didn't have a bug that introduces a factor of 0.72 then it would also be specifying font by body size. Trying to set an ascender height raises issues about which height, exactly. The tallest ascenders in Liberation Sans are line drawing characters and they extend past the interline spacing.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 20, 2022

@adrianVmariano as you can see in https://en.wikipedia.org/wiki/Point_(typography) a point (DTP) is a rational number (imperial and metric). So with intruducing points we would define scad Units (which is not a bad thing), however there are also other Point definitions used by Tex or dd or DIN and are slightly larger (0.375mm instead of 0.352777777mm) but even if the DTP point definition is used a font 12pt is not 12pt high but smaller as the points are not the body height according to WP "the point size in digital fonts may be defined as the distance between the ascender and descender lines plus a few points above and below the ascender and descender lines, "
Which is why i would refrain from using points and use body height instead.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 20, 2022

image
Just tried different Fonts and 72pt size are different for each font - Also e.g. XHM are smaller than O and Q (both are not just higher for the ascent but also extend sub baseline) - So i guess if you want a specific height you need to use resize. Also the ascent value from textmetrics is a tiny bit bigger than the letter while the descent matches.
So for the ABC size 100 i get 101.184 in Arial and 97.024 for Liberation Sans.. While the ascent in fontmetrix is 125.733/136.109 (liberation Sans)

txt=ABC();
font=undef;//"arial";
size=100;
function ABC(i=26)=i?str(ABC(i-1),chr(i +64)):"";
tm=textmetrics(txt,size=size,font=font);
fm=fontmetrics(size=size,font=font);
echo(height=tm.ascent,tm,fm);
text(txt,size=size,font=font);

@adrianVmariano
Copy link

I remain a little confused about your point @UBaer21. Yes, there are multiple definitions of the "point". This is true of every traditional unit of measurement. The point that is in common use is what you're calling the DTP point equal to 1/72 inch. The point is simply a unit of measurement. It isn't anything else. Whether you size a font by body size and whether you use points to specify that size are two independent decisions. You can set the body size to 42 points or you can set it to 12 mm, or 2 inches.

There is no reason to associate any units with the sizing of typography in OpenSCAD. If units are someday added, it should be at a higher level so it applies uniformly to the whole model.

Regarding "body size", the Wikipedia page is reporting a definition inconsistent with what I found. I am not a sufficient expert in typography to say with certainty that one definition is clearly right, but to me, Wikipedia's definition of "body height" seems suspect, since it doesn't match the prior historical definition, it doesn't seem to match sources from topography sites, and it creates an inconsistency about what type sizing means. Also note that the citation Wikipedia gives for this definition goes to a gambling website.

From https://www.onlineprinters.co.uk/magazine/font-sizes/ "But the body height is still an important reference measure in font design. After all, when you enter a 12 pt font size in InDesign, you define the height of a glyph’s bounding box which corresponds to the height of the metal body the type was cast on in the early days." In other words, the em square in which a digital font is defined is equivalent to the body size, and the size of a font is (still) equal to the body size.

And from https://www.monotype.com/jp/studio/typography-terms : "In digital type [the body] is the imaginary area that encompasses each character in a font. The height of the body equals the point size."

And really, I'm not sure what you're getting at. If we fix the bug and set type sizing the way FreeType is meant to work, then when you request a font with a size of h you will get a font sized so that the em box in which it is designed has size h, in OpenSCAD's dimensionless scale. And the two typography sources say this is the same as setting the body size to h. Doing anything else would (1) be nonstandard and (2) would require some kind of special effort to execute. I'm can't find a term that clearly refers to the distance between the tallest ascender and lowest descender, but in the font I was examining, the line drawing characters are so large that the extend beyond the body size, and in fact beyond the line spacing for the font.

@adrianVmariano
Copy link

As an addendum, yes, if you want a particular collection of glyphs to appear at a particular size then you should create them at the desired size. You can do that now by using textmetrics to get the size and then adjusting the scale as required. But that's not how font sizing works. If you wanted four rows of type consider how weird it would look if you sized each row independently to fill 1/4 of the available space. Each row would be at a different scale---perhaps dramatically so if one row had no descenders or no ascenders.

It should come as no surprise that different fonts look different at the same size. This is a well known consequence of the fact that the size of a font is the em square or body size and not an actual characteristic of the font glyphs. A font can be designed small relative to the em square or big. Or even bigger than the em square. Much larger variation in the glyph size occurs if you look around the fonts that are out there. Your example shows glyphs that are all very close in size.

I'm not sure what you mean when you say that the ascent from the textmetrics is bigger while the descent matches. I would think if they didn't both match it would be a bug in textmetrics. Do you have an example? For the case you posted above, they match (for me). The fontmetrics value is larger because it covers all glyphs, including those super tall line drawing unicode glyphs.

@jordanbrown0
Copy link
Contributor Author

I don't really have much to add to what @adrianVmariano said.

About the Wikipedia article: I don't think that the article really contradicts other sources; rather, I think it's (over)simplified and ignores fonts with unusual design choices. Note that it finishes by saying that the point size might be a few points larger than ascent+descent. The reference is not really to a gambling site; rather, it's to a dead site that's had its name recycled as a gambling site. The "Archived" link leads to the right place. The referred-to web site, typeindex.org, looks like it was created by some well-meaning folks who knew more about typography than most, but who were not typography experts... and who eventually ran out of interest and let the domain lapse, ca 2014.

I think that OpenSCAD must use some established font metric for its sizing. The body size is the obvious one, and the one that I'd endorse for compatibility and historical reasons. The metrics reported by fontmetrics() are the others that are available. I would recommend against, for instance, measuring A-Z and using those values for sizing, because it's not standard. (And because it would be more work.) Also, the user can readily do it in userspace if they want. Also, that's approximately what we have today, albeit by coincidence.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 21, 2022

image
here an example of an X and a pink square with y=the textmetric.ascent for that X, if you zoom in you see a small "gap".
Further if we introduce a new variable "pt/points" scad units will be defined, in some way it is already when importing. At the moment a square(5); can be inch or mm or cm (not when exported as 3mf ) but if we translate a "point" to either 0.352777 scad units or 0.013888 units it will be fix.
Also i exported a 100mm »A« (liberation sans) from inkscape to SVG and imported it in SCAD where this was 68.799mm which would be a 72.053 size in scad text() - but the ascent of the "A" is 68.8481 and the ascend for that font is 98.0706 .. not sure how inkscape calculates this with px (100mm is 377.953px).
Another example a 12pt "A" imported is 2.91242 units which will be text(size=3.0481) while 12pt should be 4.2333 bodyH (12×0.352777) but the font bodyH is according to fontmetric 5.43242 (nominal 4.72961) and textmetric for "A" 2.91252 - so nothing matches here. Exporting this from SCAD will match again a 12pt "A" in Inkscape.
But if you can make it working that a text(pt=50) in SCAD matches in exports i absolutely second this.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 21, 2022

(https://stackoverflow.com/questions/25520410/when-setting-a-font-size-in-css-what-is-the-real-height-of-the-letters)

found this .. where points (13) is higher than the body - But a full Block (U+2588) is bigger than that,
so it looks like points are measured from the baseline not descent.
image

pink is the points H (1 pica=12point),
magenta the height of the Letter "A"
lightblue is the text ascent
cyan is the font max ascent

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 21, 2022

it seems that SCAD font size is pt×0.254 - so a 100point Letter is text("txt",size=25.4)
or in imperial units the size 1" would be a 100 points letter. ↦ size=.12 would be 1 pica or 12points (if scad unit is inch)
At least this is exactly what i get when exporting and comparing (metric system).

@MichaelAtOz
Copy link
Member

I'll have more to say, I looked into this at the time text() was developed.

Don't confuse aspects that are means for vertical (in LTR) spacing of lines of text, with vertical height of glyphs of a font.

Some measures apply to the font as a whole, and don't particularly relate to the layout of any particular glyph. e.g you can have three lines spaced evenly, but glyphs of one can enter the space of lines above or below.

text() does not concern itself with line separation.

Also any particular glyph outline is not restricted to aspects of the whole font, it is the art of the font designer.
So notionally 'M' is Em, but an actual "M" could have a nice cursive tail that goes below the decent.
So comparing any 'x' is not necessarily the xHeight; mean-line is indicative, a bunch may be that high, maybe.
To a degree this is how long is a piece of string. Hence the need for textmetrics().
One could say OpenSCAD is unitless, so size= is just what it is, a relative size.

Of course, this could be an opportunity to metricate OpenSCAD and declare a default unit.

@jordanbrown0
Copy link
Contributor Author

It's not necessary or appropriate to bring units into the definition of OpenSCAD behavior. Other programs have units, so to some extent we need to discuss them, but what are important are the ratios, and those are unitless.

When you ask for a 72-unit X, how tall is the X, in units? It doesn't matter what those units are - they could be points, mm, or furlongs; the ratio between the requested size and the height of an X is a unitless quantity.

For informal conversation we might say that the "size" parameter is in points, but that would be wrong. It is, and should be, in OpenSCAD units.

Deep in the implementation, FreeType thinks that the size parameter is in points. But it also thinks that the output coordinates are in inches. Dividing the two causes the unit to fall out and the result is again a unitless ratio.

OpenSCAD's "size" parameter definitely does not measure ascent or cap-height. There's a mathematical error down at the interface to FreeType that imposes a 72/100 scaling error. It's only a coincidence that that error approximately cancels out the typical ratio between cap-height and body-size. (Could it have been deliberate? Well, sure... if the original author really intended to apply this magic correction without any comments as to why it was being applied. More likely, and meaning no offense, the author made the error, did not understand font sizing, got letters that were approximately a sensible size, and declared it working.)

As for the thin line at the top of the X... I measure that at 0.003 units for Liberation Sans, 0.01 units for Times New Roman, and 0.03 units for Arial, for a size=72 X. That's between one part in 2400 and one part in 24,000. TrueType fonts are defined on a grid with a maximum size of 32768; according to the specification Apple fonts use 2048 units per em. I'd say that thin line represents rounding error between how the characters are defined by their metadata and the instructions that actually generate ink. I don't think it's a real difference in how the fonts are measured.

@MichaelAtOz
Copy link
Member

I'm not heavily pushing for unitifying, but if it is unitless, then the text(size=) is in size units, whatever they happen to be ATM. The whole premise of this issue, is that the resolution is wrong, it is only wrong in comparison to a outside fixed unit, like e.g. pt, which is inch based.

X in Arial at 72 units, you get an object that's 71.6 units tall. But if you tell any other application (Word, PowerPoint, CorelDraw) to draw an X in Arial at 72pt, noting that 72pt is one inch, you get an X that's 0.716 inches or about 51.6pt tall. In OpenSCAD, you get an X that's close to the specified size, but in all of the other programs you get an X that's about 70% of the specified size

There is only a problem, iif you relate size= units, to outside inch-based-points.

So the issue perhaps is expectation. Do you/we expect whatever-size= to match our (country-culture) based chunkyness. In the absence of externally defined units, being either US inches or everybody-else-in-the-world metric, size= is correct as it is.

SO, the discussion is, to reinterpret a-size-param= TO MATCH an external reference size, inherently based in inches, or perhaps pick a Euro metrication, or just say, heck, it is unit-less. (and heck, then there is no backwards compatibility problem).

When you add all the glyph artistry, where any glyph can be wildly lets-say outside-the-box, does it really matter. As long as textmetrics matches.
Now I admit it is 00:35 here ATM following red wine (measured in ml's here), so I may be over philosophical.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 21, 2022

So for leading (line space) the question is what would be preferred.. should a text size be "em" so you get nice multiline text by translating × size. Or would it be better to have a body height that equals the acender-decender. (according to WP this is used in DTP) and would cause that two size 10 | ( full block is bigger than em) translated by 10 would just touch ( or font depending something like »M« and a »q« above). I think the later is better but would make it hard to calculate a certain point size in outputs.
It looks that the valign="center" would use the DTP body height/2 to move from bottom.

@MichaelAtOz
Copy link
Member

IF you are talking about the graphical object that text() generates, the actual unit size (say in ltr unitless height) is not in anyway related to the size= parameter.
That is the issue with glyphs. Glyphs heights have no actual bearing to line spacing.
There is a whole-different-science to working out multi-line layout. text() just does one line.

@MichaelAtOz
Copy link
Member

BTW re Wikipedia Em

The name em was originally a reference to the width of the capital M in the typeface and size being used, which was often the same as the point size.

Originally, ie when they were steel blocks. Em is width, often the same as size (originally), Em is NOT height.
Modern font glyphs can splatter all over the place. Particularly non-english fonts.

I know this is frustrating for the IT crowd, I got over it about a year into researching it.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 21, 2022

image
left is the current, green (chartreuse) is if size would correspond "em" or line-spacing is size/.72
the last with DTP body height would also cause that different fonts would get the same sizes in opposite to their real size based on points. The origin of em or body height (not DTP) was when they had to arrange the letters for press to get the proper leading (2pt). Currently the font size in SCAD has no proper correlation to the units.

@MichaelAtOz
Copy link
Member

BTW#2 nice multiline text must be font specific.
Eight years ago I had to specifically program layout based on which letters a user specified in Customizer, and that was before text(). It is no different now.

@MichaelAtOz
Copy link
Member

OK, note to self, tomorrow throw up a bunch of splatter fonts to show that size and height (in OpenSCAD unitlesses) do not correlate. Good night.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 21, 2022

image

as original em was a max - all letter would fit. Sure today we have DTP and as said size could be calculated per fontmetrics
But most fonts of a certain size will fit into an "em" box - the full block is bigger so that is not fitting. The current text size will never fit into a "size" box - so this should work as a minimum and this is caused by that 100 pt/unit sizing leading to that 100/72 error (because 1 pt = 1/72"). As i already said pt is a holdover so the DTP body height (not based on points) should be used for text size - but this will scale fonts other than point based software ("inkscape or word")

@jordanbrown0
Copy link
Contributor Author

I'm not heavily pushing for unitifying, but if it is unitless, then the text(size=) is in size units, whatever they happen to be ATM. The whole premise of this issue, is that the resolution is wrong, it is only wrong in comparison to a outside fixed unit, like e.g. pt, which is inch based.

No. What's wrong is that the ratio between the specified size and the actual size of the rendered glyphs does not match the various definitions.

When you specify a body size of 100, you should get capital letters that are about 70 tall, because that's the definition of body size. That's true no matter what units you use to measure body size and the size of the resulting glyphs. It's true if you use points, it's true if you use mm, and it's true if you use smoots.


But: does the size parameter control body size? No.

OpenSCAD is behaving as documented, at least roughly.
The documentation says that you get an ascent of approximately the given value. I think that documentation is an explanation of the observed behavior, rather than the result of a considered design decision. But it says what it says, and what it says isn't totally silly.

So the buggy implementation and the documentation agree: size does not mean body size - it means, approximately, ascent. (Well, not really, because it doesn't match the font's specified ascent. But it does match A-Z ascent, more or less.)

But we already knew that we couldn't change the behavior of size. Right or wrong, documented or not, too many people are relying on it. We couldn't even change it to base its scaling on the font's specified ascent.

The question is, I think, whether we should introduce a new parameter that specifies the body size and so allows one to get results that align with the results produced by other programs, where specifying a size of 100 yields A-Z that are about 70 tall - again, unit-independent.

@adrianVmariano
Copy link

We can't use "bodysize" because its definition is not clear. Ubaer21 and Wikipedia think body size is the ascender height plus descender depth---the actual size of the glpyhs---and that is not the thing we are setting.

I also think we cannot use h or height because other functions use this to refer to extrusion height.

boxsize is ok because the em square is a box and that's what's being set. But I think it's kind of obscure.

I think that of the options, really fontsize or typesize or their short forms are the only acceptable options. I had previously suggested scale, which is shorter than fontsize, but I think less clear.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 22, 2022 via email

@adrianVmariano
Copy link

Could use emsize instead of bodysize. That's unambiguously correct for digital fonts, and maybe more clear than just "em".

@MichaelAtOz
Copy link
Member

Is there a common understanding of "Em" in a vertical context?
FreeType EM square is not necessarily anything related to post scaled size.
So is Emsize referring to point-size, ie pts in 1/72inch, not to the notional "M" size whence Em comes from?
If so the Emsize is inherently unitifying to inches.

Anyway...
Having re-read some of the early posts, this seems to be going in circles.

The original problem can be paraphrased as, 'the size of the inked-letter is not relative to letters in pts of other programs'

any other application (...) to draw an X in Arial at 72pt, noting that 72pt is one inch, you get an X that's 0.716 inches or about 51.6pt tall. In OpenSCAD, you get an X that's close to the specified size, but in all of the other programs you get an X that's about 70% of the specified size.

However with Word on my PC 'X' in Arial 72pt paints on the screen an 'X' that is 14mm/0.55 inch or printed it is 18mm/0.708 inch ~51pt.

What FT_Set_Char_Size does is scale the font (in FreeType "pts") to the output device resolution in dpi (dots per inch), and OpenSCAD text() is saying the output device graphical resolution is 100dpi.

So:

translate([0,0,-1]) color("green") cube([100,100,0.99]);
translate([0,0,-0.01]) color("blue")  cube([71.6,71.6,0.01]);
linear_extrude(1,convexity=6) text("X",size=72, font="arial");

Capture-text-x-100dpi

In a 100dpi resolution output (inherently unitising a cube(100) to an inch, the X is very close to 71dots or 0.71 inch.

Thus with size=72 we ask for a 72pt body size, or a body size of an inch, but because of the two 100s we get glyphs with a body size of 100.

I never expected size= to be pt based body size. The OP is written with an expectation that size= is in pts, hence the inked-part should be ~51pt tall, not ~72pts. IF OpenSCAD IS unitless there is noting wrong.
However, if OpenSCAD is unitified to 100dpi, nothing is wrong.
But, if you EXPECT OpenSCAD to be unitified to 72dpi, then text() size= does not match.

Now
Lets say that is a problem, some people think in inches, so size=72 on a 72dpi output should output a ~51pt X. Then the solution is add a new unitifying parameter, as @t-paul suggested points or pt, then everything works and people can work in notional inches with pt, or something metricalish with size.

Or am I missing something?

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 23, 2022

@MichaelAtOz it is about what "size" means. All programs use fontsize to determine the Size of the font in a way that you use the vertical distance for lines as size and for a nice look add 20%. This ratio is not working in SCAD. One sure can argue that size in SCAD doesn't mean em or body like everywhere else but more something like "hp" (which is also not true as hp would be font Independent). So this is about define the size the same way all other software does that uses fonts - completely Independent from the unit used (metric/imperial) or the font or resolution.
If you export a text render you will then get the exact (really exact) result any other Software would have for that size.
Meaning if i work with inch a text size=1 will be a 72pt letter in metric i need to calculate the point size which relates to inch.
(btw: your blue square is not an exact match of the X)

@MichaelAtOz
Copy link
Member

Or in other words, if we ask for text size of 100 text("X",size=100);
Capture-text-x-100dpi-x100
we get a glyph of about a 100.
And because in typefaces, particular glyphs can splatter outside the EM Square, it is all arbitrary anyway.

@MichaelAtOz
Copy link
Member

(btw: your blue square is not an exact match of the X)

Read this. particularly II.2.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 23, 2022

simple:
In openSCAD a 1 inch size text generate a 100pt text.
All other Software produces a 72pt text (when text size is 1 inch or 72pt).

Also when a font designer creates a font, he does that in regards of an em-square - it can be bigger or smaller but this will determine the size of the font.
https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
And current text size in SCAD scale that size up by 38.888% to correct this you need size×.72 or size/ 1.3888

@MichaelAtOz
Copy link
Member

it is about what "size" means

In OpenSCAD size= means pts on a 100dpi resolution output device. For backward compatibility it will likely be that way for a long time. Hence the suggested points=.

All programs use fontsize to determine the Size of the font in a way that you use the vertical distance for lines as size and for a nice look add 20%. This ratio is not working in SCAD.

IF you are in a word processor you think in FONT size because you work on a page with a page size in mm or inch and pts is in inches and the WP and OS and printer driver convert it all.

IF you are in a unitless CAD modeller you think in UNIT size in an indeterminate sized universe.

text() doesn't to lines, vertical text rendering has much more complex issues.

In openSCAD a 1 inch size text generate a 100pt text.

There is no such thing as 1 inch size text in a unitless program, nor 100pt's text,
You do know there are more people who don't know what an inch is, than people who do.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 23, 2022

@MichaelAtOz if SCAD design it for 100dpi it wouldn't be unitless.
if you export in SVG or 3mf you also get a metric unit. However if you make a 10 unit square and you export that square it will be 10 units. If you now print this you scale that to 1 inch or 1 meter or 1mm or 1cm.
So the em square in units for a text will be the text size in units.

But currently this is not true in openSCAD as a text of 12 units in size will end up in a text which em-square is 16.6666 units.

@MichaelAtOz
Copy link
Member

a. size= is not likely to change, for a whole bunch of reasons.
b. so what's wrong with using points= if you want to work in points?

There is a red wine calling from the other end of the house...out for now...

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 23, 2022

I am trying to understand you here.
So what size would be the em size of text rendered with 72pt? would it be 1 or 25.4 ?
When exported as 3mf it must be 25.4 (or you need to introduce a unit size in open SCAD)
So if using STL what would it be, because when introducing a pt variable you will either shut out people using inch or the metric people. Which is why i can't see pt as an option without the definition of a unit size in scad.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 23, 2022

for a.
we can't change "size" which is why we need a new variable "body" or "em" either boolean to switch "size" or to overwrite size if defined as size=is_num(em)? em * .72 : em==true? size*.72 : size;

@adrianVmariano
Copy link

adrianVmariano commented Jul 23, 2022

@MichaelAtOz there is no meaningful notion of "resolution" for OpenSCAD output. The resolution is used internally in the font system because you have to specify a resolution in FreeType, but there is a bug that introduces a 0.72 scale factor.

This issue has nothing to do with units. We do not "want to work in points".

When you specify a font you are giving a length. What does that length actually mean? Customarily the length is given in the units of points, which is why people talk of a 20 pt font. But it's just a length and can be measured in any units. In OpenSCAD a length is always in OpenSCAD dimensionless units. What the length means is the side length of an imaginary square, the em square, that was used to design the font. It doesn't correspond to any real dimension in the font. We know that. This is the conventional meaning of font size. Yes, it's arbitrary. But it's the standard convention for what "size" of a font means. OpenSCAD should follow this convention.

In OpenSCAD when you request a font with size=x you get a font whose em square has size x/0.72 instead of x. Again, there are no units here. This does not have anything to do with points. It has to do with the size of the em square in OpenSCAD dimensionless units. Anybody who wants to create a font at a known size, consistent with standards, will need to compensate for the 0.72 factor.

Repeating my example above with units, if you wanted to produce 36 point text and you are treating OpenSCAD units as mm, then this should work. But right now, this code will produce 50 point text instead:

inch = 25.4;        // Inches in millimeters
point = inch/72;  // points in millimeters
text("ABCD", size=36*point);

The em square is typically a bounding box for the font, including both the ascenders and descenders. (Note I said typically---as you said, the font can go outside this box.) In your example above with the X, when you request a font of size 100 you get an X that is approximately 100 units tall because the cap height (the height of capital letters) is approximately 70% of the em square for typical fonts. That approximately cancels out the 0.72 factor. But if you're hoping that size means something about the height of the X you're deluded. It's a combination of two assumptions that can both fail about the font's relation to the em square the the proportion of the cap height. If you care about the actual size of the glyphs rendered---e.g. to fit them into a space---this is not a robust approach. You should use textmetrics for that.

@MichaelAtOz
Copy link
Member

No, and it's after midnight so I'll be brief, size= is based on 100 units, that is what it is, and for a typical English letter the cap-height-ish ink-size is ~72 odd units. For many other languages that does not apply. I haven't checked in detail, but I expect my hieroglyphics-type characters (yes I have used them "Pseudo-Assyrian-Cuneiform" and others) will not be 72 odd units, This is so parochial.

babel-fish-gir-gunu-b

In OpenSCAD when you request a font with size=x you get a font whose em square has size x/0.72 instead of x. Again, there are no units here.

You have just introduced a different unit. What is an Em Square? How is it measured? In what language?

@MichaelAtOz
Copy link
Member

Now size= should not be redefined for lots of reasons.
What is the problem of introducing, as discussed above:

Ah, duh, yes. I was thinking the new parameter would be do_scaling_right=true, but just replacing size would be much better.

points= to give you what you want, an imperial size.

@MichaelAtOz
Copy link
Member

Good night.

@MichaelAtOz
Copy link
Member

Or rather, I don't care. If the consensus is to break backward compatibility of size=, go ahead. OUT.

@adrianVmariano
Copy link

@MichaelAtOz, We agree that size= cannot be redefined because that breaks backward compatibility. The proposal is to introduce a new size parameter.

The problem with introducing points= is that it has units in it and there are no units in OpenSCAD. Would you propose inches= for an OpenSCAD argument under some circumstance? For these ideas to make sense, we would need to define units in OpenSCAD. This issue has nothing to do with units.

You wrote: "You have just introduced a different unit. What is an Em Square? How is it measured? In what language?" The em square is the design scale for a font. It's a square. You measure it with whatever units you want. It's not a unit. The size of the em square is conventionally measured in points, but it could be measured in mm, inches, microns, miles. Any units you want because it is simply a length. I'm not sure what you mean about "in what language?" We don't normally consider units of measurement to be "in a language" but if you want to measure the em square in Japanese "rin" units you could do that. Also, I haven't introduced it. It's how fonts are designed. It's the (arbitrary) reference length that characterizes the size of a font. The point is not that the em square is fundamentally meaningful, but that it's the standard.

I don't understand what you mean when you say size is "based on 100 units". What "size" is doing is specifying the size of the em square. That is what it means because that's the typographic definition of a font's "size". It's doing it with a 0.72 factor introduced because the way the font sizing is done in the OpenSCAD code. Unlike OpenSCAD, FreeType has units associated with its size parameters. The freetype size input is in points. The output is in pixels based on the specified size of a pixel. The existing OpenSCAD code is requesting a font with a size specified in points (1/72 inch) and the output in pixels of size 1/100 inch. This introduces a scale factor of 1/0.72. Suppose I decide that OpenSCAD units are points. Then if I ask for size=50 I should get a 50 point font whose em square is 50 OpenSCAD units tall, and whose capital Roman letters are about 35 units tall. If I change my mind about the units I'm using in OpenSCAD...nothing changes. I should get the same output. Because the scaling of OpenSCAD units was only in my mind, not in OpenSCAD.

Note that the current code is using the em square. You can't avoid it because that is how fonts are specified. It's just using the em square in a confusing way, inconsistent with other software, where it adds a factor of 1/0.72. The only way to avoid using the em square would be to factor it out by using text metrics to get the glyphs' true size and then compute a new scaled size based on that. I actually like the idea of specifying text that way, but that's a nontrivial new feature whereas this issue is a bug fix. And using textmetrics to scale glyphs to a desired size can be done in userspace---it is routinely argued that if it can be done in userspace we shouldn't add it to core OpenSCAD.

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 23, 2022

here a comparison the background height is = size
image
you can clearly see why em sized (green) is better

@jordanbrown0
Copy link
Contributor Author

@UBaer21: just so we're all on the same page, can you give us the program that generated that image?

@adrianVmariano
Copy link

adrianVmariano commented Jul 23, 2022

@MichaelAtOz said something about being parochial about the sizing. What's parochial is the current scheme. Here's an example. Which looks reasonable:

image

The top with the blue background uses the correct em size of the font. The bottom with green and black uses the OpenSCAD size that was used to request the font with the current behavior. The scheme OpenSCAD uses which sort of seems OK on Roman lettering based on cap height is simply absurd on Chinese.

Code:

 include<BOSL2/std.scad>
 font = "Droid Sans Fallback";
 color("blue")translate([0,-19,0])square([1250,100/.72]);
 text(size=100,font=font,str_join([for(i=[20075:20083]) chr(i)]));
 translate([0,-200,0]){
   color("green")translate([0,-19,0])square([1250,100]);
   color("black")text(size=100,font=font,str_join([for(i=[20075:20083]) chr(i)]));
 }

@UBaer21
Copy link
Contributor

UBaer21 commented Jul 23, 2022

it is from the Text() module of my lib that allow to select between different sizing.
body for em sized, hp for the size of letters "hp", versal for size of letters like "H" (cap height) ..
but basically you just need

color("magenta")square([500,10],true);
color("green")text("ABCabcqfg$|",size=10 * .72, valign="center");

@jordanbrown0
Copy link
Contributor Author

With respect to @adrianVmariano's example... on my Windows system, I don't have Droid Sans Fallback, but I see the same effect with font = "Microsoft JhengHei:style=Normal";

jordanbrown0 added a commit to jordanbrown0/openscad that referenced this issue Aug 1, 2022
openscad#4304.

Add underline position and thickness to fontmetrics.
Note:  underline position is the *bottom* of the underline.
@UBaer21
Copy link
Contributor

UBaer21 commented Oct 11, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants