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.
Related
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 OpenLayers I use ol.style.Text to add a text label to federal states polygons. The states have names of different length and also polygons of different sizes. It looks like this:
Is it possible to only print the text marker if it fits inside its polygon (e.g. after zooming in)? For instance, in the above example Hessen, Thüringen, Sachsen and Bayern would be printed, but Rheinland-Pfalz, Saarland and Baden-Württemberg would be omitted because the text goes beyond its feature's geometry...
I know I can set the font property of an ol.style.Text to a particular size based on the resolution but this does not help here as text would still overlap the borders sometimes...
This is currently not possible with help from the library. But you can use CanvasRenderingContext2D#measureText() in your vector layer's stlyeFunction to get the width of the label, and compare that with the extent's width of the polygon at a certain resolution, and decide based on that whether to render or not. You can also get smarter than using the extent's width, but it is probably a good enough approximation for many cases.
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 a string that i need to calculate the Rect size (text height) when drawing. My implementation uses the DrawTextW() function with DT_WORDBREAK or DT_CALCRECT flags.
An example of my string:
thisisaverylonglonglonglineoftextthatneedstofitinsideagivenrectwidth
I can see in the MSDN docs, that DrawTextW() method states:
If the largest word is wider than the rectangle, the width is expanded. If the text is less than the width of the rectangle, the width is reduced. If there is only one line of text, DrawText modifies the right side of the rectangle so that it bounds the last character in the line.
however in the MSDN docs, then DrawTextExW() method does not state this.
So i tried to calculate the height using the DrawTextExW() method, however the result is the same as with DrawTextW() function, where it extends the width of the rect to fit the largest line of text.
So how can i correctly calculate the height of the text rect with a given (fixed) width when drawing a large string (with no spaces) where DT_WORDBREAK and DT_CALCRECT are specified?
EDIT:
As a side note, does anyone know how Microsoft Excel does cell text drawing? Is there an API call for this text drawing? This was where my original question stemmed from, however the way it is implemented in Excel is to draw the text and wordbreak/wordwrap on any character (not just a space).
You need to use the DT_WORD_ELLIPSIS flag in uFormat parameter (along with DT_WORDBREAK of course). That will prevent the widening due to long strings with no spaces. It still will not break those long strings though, but your width problem will be solved.
If you also specify DT_MODIFYSTRING, then you could kind of figure out where to break that long string yourself, prior to the final draw.
As for the difference between DrawText(W) and DrawTextEx(W): the latter provides tab formatting, setting margins and returns the actual number of drawn characters. There is no difference in (dimensioning) functionality.
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.