I'm using RMagick and I want to draw text vertically or horizontally (depends on user input) with background color set by user. I've ran into odd problem: get_type_metrics(text) returns invalid data. Actual width / height are smaller than returned by method.
I've been trying to play around with ascent / descent values, but no luck. Is there any way to determine real width / height of text string? I've seen couple solutions drawing text on empty image then determining width height then looking through whole image pixel by pixel, but imho thats stupid and really resource consumptive. Also as I've find out PHP GD has same issue and no solution.
P.S. I can't use Draw#annotate because user should be able to change background box size.
As I've found out, there's undocumented (in RMagick) bounds member of TypeMetric struct which is documented in FreeType Glyph Conventions and your real width & height of text is determined like this
gc = Magick::Draw.new { ... }
# *** setup gc with font, stroke, pointsize, ... *** THATS IMPORTANT!
metrics = gc.get_type_metrics("your text")
box_width = metrics.width # this one is ok by default
box_height = (metrics.bounds.y2 - metrics.bounds.y1).round # this is the actual heihgt
Related
please see the image below for two examples of what is to be achived
the alignment should be on the Center Y of the first lines of each UILabels and should work regardless of font size or font. currently we have implemented this with different constraints to the top of the super view for different font and font size combinations.
the constraint to align the center of the two UILabels does not work since the text of the second UILabel is not fixed and can have several lines.
also the text is dynamic, so it is not known where the text will wrap to create the first line, thus it cannot be shown in an one line UILabel with the rest of the text in another one below.
currently this is implemented using UIKit, but if there is an easy solution in SwiftUI we can put these two labels in a SwiftUI component. so a SwiftUI solution would also be welcomed.
Your comments said "it should be on the glyphs" ... but, without additional information, my guess is that "real world" usage would not really need that level of precision.
For example:
While the glyphs are not perfectly center-Y aligned, it seems unlikely you'd run into a case where the first line of the "rightLabel" is " ' " ' " or . , . , ..
This layout can be easily done with only a few constraints - no need to do any calculations:
The "Positioning" label would, of course, be set .hidden = true so it would never be seen.
If you really, really want glyph-precision, you'll need to calculate
the Glyph bounding box for the left-label
the Glyph bounding box for first line of the right-label
calculate the "character box" offsets to align the Glyph Y-centers
and then position the two labels accordingly, or use Core Text to draw the text (instead of using UILabel).
Probably more work than necessary -- unless your actual use-case demands it.
That's an interesting problem! You can try using the centerYAnchor for the label on the left, and the firstBaselineAnchor for the label on the right... that will align the center Y with the text baseline, which isn't quite what you want.
To find the correct offset to apply, you can use the information from UIFont about the size of the characters. I'd probably start with capHeight * 0.5 and see if that looks or feels right. Something like:
leftLabel.centerYAnchor.constraint(equalTo: rightLabel.firstBaseLineAnchor, constant: rightFont.capHeight * 0.5)
This is a more difficult problem in SwiftUI, I think, because resolved font metrics aren't directly available to you.
I have a UILabel with a font of size 50 and text 1. At runtime, its text is changed to other numbers.
If I, say, center it in its superview, the automatically detected (intrinsic content size) height is a lot bigger than the actual text, and this is because it tries not to crop other lower characters like g.
The thing is that I know I won't use other characters than digits. I also don't want to set a fixed height constraint for it.
UIFont metrics include ascender, descender, cap height, x height, etc... all of which determines how the characters fit into a container. There is a good explanation and diagram here: http://cocoanetics.com/2010/02/understanding-uifont
If you really want to get the height (and/or width) of the individual character "glyphs" you'll need to use Core Text. This will include calling CTFontGetGlyphsForCharacters() and CTFontCreatePathForGlyph() to get the "glyph path" (a CGPath object), at which point you can get the "bounding box" to determine the exact size.
Lots of discussions and example code out there... A good starting point is simply searching for CTFontCreatePathForGlyph
In an iOS app I need to use a specific font but each character needs to be taller, thinner, and the spacing closed up to fit correctly. Is it possible to stretch/squish a font programmatically?
When you're adding text to a PDF file there are multiple ways to influence how the text is going to appear. The most generic way (and the way that might actually be sufficient for you) is to scale the text matrix:
void CGContextSetTextMatrix ( CGContextRef c, CGAffineTransform t );
As mentioned in the comment by #mkl, you can provide a matrix that will scale up in the Y direction while scaling down in the X direction. The effect will be that the letters are stretched out vertically and squished horizontally.
Normally I would expect you don't have to touch the spacing in that case, as spacing will be "squished" together just as the other characters.
Just in case that isn't sufficient, PDF actually does provide a way to change the spacing between characters too:
void CGContextSetCharacterSpacing ( CGContextRef context, CGFloat spacing );
While Apple's description talks about "additional space" to add between characters, the PDF specification and I suspect Apple's implementation as a result allows the spacing value to be both positive and negative. A negative value would have the effect of moving the characters closer together.
Seems like the best option would be to create your own custom font.
You are able to change the kerning of your font (the space between the letters) and the thickness/thinness of the font, however you probably aren't able to edit the height of the font, unless you edit the bounding box the font is inside of to scale the letters differently.
You might also want to consider using a different font...or if you're REALLY hardcore you can edit the font yourself using photoshop/illustrator.
I have an NSAttributedString which I draw into a rectangle (no text views here.) I allow the user to resize that rectangle thus forcing the text to wrap onto multiple lines. All is good and I'm using NSTextContainer etc to figure out the text bounding height for a given width.
The challenge I have is knowing what the MINIMUM width can be - so that I don't allow the user to resize the rectangle to be narrower than the widest character/glyph in the string.
I have a working solution which involves getting the bounding rect for each glyph (boundingRectForGlyphRange) and keeping track of the largest - but this is a real performance killer on larger strings.
Anyone know of a better way?
Thanks
When you choose your font and display language, you could compile a lookup of all possible glyph widths. Order it descending with the largest glyphs first, then use rangeOfString: != NSNotFound; breaking after you find one (this is your maximum glyph width).
Hard to say what the performance difference is like, but it is probably faster than fetching the width of all your glyphs every time since it's just a string comparison instead of a font measurement.
I have a LOGFONT structure. Now all i'd like to do is get the associated font size in points from the LOGFONT height.
When the mapping mode is mm_Text (which it usually is), and when the lfHeight field is positive, it already gives the height in points. When it's negative, the units are pixels. MSDN for LogFont gives you the formula to convert between them:
lfHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
There are 72 points per inch. GetDeviceCaps tells you the number of pixels per inch on a given device. Invert the formula to get pixels from points:
PointSize := MulDiv(-lfHeight, 72, GetDeviceCaps(hDC, LogPixelsY);
The important thing to realize here is that you need a device context. Font sizes don't exist independently of the media they appear on. The pixel height of a font on the screen will be different from the pixel height of a font on a printer. Use the Handle property of whatever canvas you're planning on drawing to.
I find this a bit confusing, as well.
Here are a few things that I háve learned. ;)
Examine the two low-order bits of lfPitchAndFamily to determine the font type.
For fixed-pitch fonts, use GetTextMetrics and the TEXTMETRIC structure.
For variable-pitch fonts (true-type, etc), use GetOutlineTextMetrics and the OUTLINETEXTMETRIC structure. Be sure you have the structure aligned properly. Also, the structure is variable-sized. Call the function once to get the size, allocate space, then call the function again to fill the structure.
From there, you can find proper ascent, descent, and other size-related information.
Keep in mind that they are recommended values and not all display routines will use them properly. For example, I am in the process of figuring out a correct method of determining the required height of a dialog box static control for a given string of text.
It does not appear that Microsoft has followed their own documentation. ;)
Not that the documentation is all that clear or complete, to begin with.