Custom installed font not displayed correctly in UILabel - ios
I'm trying to use a Helvetica Neue Condensed font which I got from the Adobe Font Collection Pro Package. Unfortunately, it seems to draw incorrectly when I use it within a UILabel.
The line height seems to be calculated correctly (I think), but when the font is displayed, it is aligned to the very top of the bounding box. I called [myLabel sizeToFit] and only adjusted the width to produce this screen capture:
I had the same problem with both the bold and regular version of the font. I was able to pull a version of Helvetica Neue Bold from OSX and put it on my device and it displays fine (green background in above picture).
What could be wrong with the either the font file or my code that would cause it to draw this way?
I posted a solution that involves patching ttf font file here:
Here's the solution that worked for my custom font which had the same issue in UILabel, UIButton and such. The problem with the font turned out to be the fact that its ascender property was too small compared to the value of system fonts. Ascender is a vertical whitespace above font's characters. To fix your font you will have to download Apple Font Tool Suite command line utilities. Then take your font and do the following:
~$ ftxdumperfuser -t hhea -A d Bold.ttf
This will create Bold.hhea.xml. Open it with a text editor and increase the value of ascender attribute. You will have to experiment a little to find out the exact value that works best for you. In my case I changed it from 750 to 1200. Then run the utility again with the following command line to merge your changes back into the ttf file:
~$ ftxdumperfuser -t hhea -A f Bold.ttf
Then just use the resulting ttf font in your app.
So this is a modified version of kolyuchiy's answer.
I opened my font with Glyphs, and then exported it without modifying anything. Somehow, magically, the vertical alignment issue was gone!
What's better is that the new font plays nicely with methods like sizeWithFont:, so it doesn't have the issues mentioned by Joshua.
I took a look at the HHEA table with the command kolyuchiy mentioned, and noticed that Glyphs modified not just the ascender, but also lineGap and numberOfHMetrics for me.
Here's the raw data, before:
versionMajor="1"
versionMinor="0"
ascender="780"
descender="-220"
lineGap="200"
advanceWidthMax="1371"
minLeftSideBearing="-73"
minRightSideBearing="-52"
xMaxExtent="1343"
caretSlopeRise="1"
caretSlopeRun="0"
caretOffset="0"
metricDataFormat="0"
numberOfHMetrics="751"
and after:
versionMajor="1"
versionMinor="0"
ascender="980"
descender="-220"
lineGap="0"
advanceWidthMax="1371"
minLeftSideBearing="-73"
minRightSideBearing="-52"
xMaxExtent="1343"
caretSlopeRise="1"
caretSlopeRun="0"
caretOffset="0"
metricDataFormat="0"
numberOfHMetrics="748"
So the moral of the story- don't just increase the ascender, but modify other related values as well.
I'm no typography expert so I can't really explain the why and how. If anyone can provide a better explanation it'd be greatly appreciated! :)
iOS 6 honors the font's lineGap property, while iOS 7 ignores it. So only custom fonts with a line gap of 0 will work correctly across both operating systems.
The solution is to make the lineGap 0 and make the ascender correspondingly larger. Per the answer above, one solution is to import and export from Glyphs. However, note that a future version of the app might fix this "bug".
A more robust solution is to edit the font yourself, per this post. Specifically,
Install OS X Font Tools.
Dump the font metrics to a file: ftxdumperfuser -t hhea -A d YOUR_FONT.ttf
Open the dumped file in an editor.
Edit the ascender property by adding the value of the lineGap property to it. For example, if the lineGap is 200 and the ascender is 750, make the ascender 950.
Set the lineGap to 0.
Merge the changes into the font: ftxdumperfuser -t hhea -A f YOUR_FONT.ttf
Once you do this, you might have to adjust your UI accordingly.
For those running OS X El Capitan and coming to this thread, you might have noticed that the Apple Font Tool Suite is no longer compatible (at least for now).
But you can still perform the changes described by kolyuchiy and Joseph Lin with free font editing software FontForge.
Open the font with FontForge and select Element in the top menu, then go to Font Info > OS/2 > Metrics. There you want to edit the HHEad Line Gap and HHead Ascent Offset values.
Once you've done the necessary edits you can just export the font in File > Generate Fonts and select the right font format
Download and Install Apple's Font Tools here: https://developer.apple.com/downloads/index.action?q=font (the download link is in the bottom)
Open the terminal and cd your way to where your font is
Run this command: ftxdumperfuser -t hhea -A d MY_FONT_NAME.ttf
Now you have an xml file with some of the font's properties, edit it in your text editor
Search for the "lineGap" property and add 200 to its value
Save the xml file
Run this command: ftxdumperfuser -t hhea -A f MY_FONT_NAME.ttf
Delete the xml file
Try the configured font on iOS 6 and see if it looks better.
If you need, you can go back to step 3 and add/subtract to the "lineGap" property. (I ended up adding 250 to my configuration)
We had the same issue with one of our custom fonts. We also "fixed" the problem by editing the font ascender property. However, we found that this created other problems and layout issues. For example dynamically setting cell height based on label height would blow up when using our ascender edited font.
What we ended up doing was changing the UIButton contentEdgetInsets property.
yourButton.contentEdgeInsets = UIEdgeInsetsMake(-10, 0, 0, 0);
Not sure which method is better, but just wanted to share another way to fix the problem.
Thanks to the this answer I fixed my problem with Glyphs, but a little bit differently.
I opened my font with Glyphs (also works with Glyphs mini) and found this section there (this from Glyphs mini, to get there push i button in the right top corner):
Just delete all of this alignment zones (or some of them) and it will fix this problem.
Worked perfectly for me.
Creating attributed text from your labels text was the fix for me. Heres an extension:
extension UILabel {
/// You can call with or without param values; without will use default 2.0
func setLineSpacing(lineSpacing: CGFloat = 2.0, lineHeightMultiple: CGFloat = 2.0) {
guard let labelText = self.text else { return }
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpacing
paragraphStyle.lineHeightMultiple = lineHeightMultiple
let attributedString:NSMutableAttributedString
if let labelattributedText = self.attributedText {
attributedString = NSMutableAttributedString(attributedString: labelattributedText)
} else {
attributedString = NSMutableAttributedString(string: labelText)
}
// (Swift 4.2 and above) Line spacing attribute
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
self.attributedText = attributedString
}
}
For my custom font I got the result I need from:
self.myLabel.setLineSpacing(lineSpacing: 1.2, lineHeightMultiple: 1.2)
This works by using the native provided NSMutableParagraphStyle() which contains line height and spacing properties (which are accessible as #IBOutlet properties in the Storyboard too if you are not programming your labels).
Have you tried Core Text? I've had some success rendering custom fonts through Core Text, but I don't know if it would fit your situation.
I used https://github.com/fonttools/fonttools - very easy to use and free. In my case, the change of 'ascender'=1000 and 'lineGap'=0 in 'hhea' table did the trick.
Based on article from Trevor Harmon https://medium.com/#thetrevorharmon/how-to-use-apples-font-tools-to-tweak-a-font-a386600255ae
If your are having trouble with these command line utilities then try fontcreator on window. and change font assender from its setting menu.
For anyone who are struggling to use ftxdumperfuser (kolyuchiy answer) on Mac OS Mojave because of command not found error:
Download the font tools package from Apple. Found them at
https://developer.apple.com/download/more/?q=font, picked the one for
XCode 11.
Mount the dmg file
Enter the disk image cd /Volumes/macOS\
Font\ Tools
Extract the package to a folder of your choosing: pkgutil
--expand-full macOS\ Font\ Tools.pkg ~/font-tools
The CLI tools are now available in ~/font-tools/FontCommandLineTools.pkg/Payload, you
may add the folder to your path (export PATH="$PATH:$HOME/font-tools/FontCommandLineTools.pkg/Payload"), or copy the utils to your bin
folder.
I had a similar issue with iconic "FontAwesome" font in my Sprite Kit game.
Setting the SKLabelNode's SKLabelVerticalAlignmentMode property to .Center worked for me.
myLabel.verticalAlignmentMode = SKLabelVerticalAlignmentMode.Center
Just wanted to share in case somebody would be struggling with the same problem.
Related
iOS UILabel and avoiding clipping of diacritics with custom font
First of all, there are many questions on StackOverflow, but none that fully answer this question. The problem is mainly, but most likely not limited to, Thai and Arabic diacritics when rendered with a custom Latin-only font, using the text property of a UILabel. Which is also intrinsically sized in an auto-layout. I've already done everything Apple suggests, playing with the settings mentioned in their documentation, WWDC videos, as well as questions on StackOverflow (e.g. clipsToBounds = NO, etc.). Keep in mind, only my custom font setup clips in my scenario, not the iOS system font (.SF-UIDisplay), and not even the iOS system provided Helvetica or Helvetic Neue. The custom font has been checked and rechecked, and at this point the conclusion, iOS is the anomaly across all platforms, even macOS. To be even clearer, the same clipping behavior as the custom font can be seen with SF Pro, a font provided by Apple themselves here: https://developer.apple.com/fonts/ This question is about the most proper, least intrusive, and most complete way to do what is necessary to not clip diacritics. Meaning, how would you do this, ideally, from scratch. All of my font research and test runs have led all those involved in this problem to believe that Apple has implemented special treatment specifically for their system fonts in UILabel, to avoid diacritic clipping. So making that an assumption, I'm also assuming the font is ok, and I'm looking for solutions that do not involve editing the font. In my tries to use the font, the first thing to go wrong was vertical clipping of the ascender diacritics of Thai glyphs: นื้ทั้มูHello This means the glyphs of the font Thonburi when they cascade from the custom Latin-only font. The fix from this point, was to use a custom font only for Thai without any Latin characters, so it could be defined as the primary font, and cascade to the previously mentioned Latin-only custom font. After all this, the custom Thai font still has horizontal clipping issues on diacritics that come at the end of the text: Worldฟล์ So now I am at a loss for anything further that font management puppetry can do (though still open to suggestions), and I am moving on to more code-centric fixes. I've seen quite a few questions and answers mentioning subclassing UILabel, but I'd like to know what this would look like that could accomplish what I've described. I'd also like to know if just opting out of UILabel would be an option for anyone. Meaning would writing something from the ground up with TextKit be worth it to avoid all these bugs that seem to only plague iOS, and specifically UILabel.
At first I thought this was a problem with the framework but it's not, it's just a strict enforcement of a font's metrics. And in probably everything but web/app development, fonts are not rendered so strictly, which is why this problem rarely comes up. Fonts have a number of metrics that tell the program rendering it onto the screen how to render it, most importantly how to handle padding. And UILabel (and UITextField, and likely others) applies these metrics strictly. And the problem for us is that some fonts are very decorative and are often too thick or oblique to fit perfectly into the square canvas that each character must fit into (this is especially the case with accents, like umlauts). This isn't a problem outside of web/app development because when a character doesn't fit into its canvas, like a very thick, wide, and oblique W, the program just shows it anyway, and that's why a low-hanging g might spill into the line below it. But if that g was rendered in a single-line UILabel, because of how strict the font-metric enforcement is in iOS, that low-handing g is clipped. Subclassing UILabel (in the case of UILabel) and overriding its intrinsicContentSize to add some extra padding is not a good idea, on further research. For one, it's kind of hacky, but more importantly, it produces constraint warnings in the debugger. The true fix, and the only acceptable fix AFAIK, is to edit the font's metrics. Download a program like Glyphs (https://glyphsapp.com/), open the font, open the Font's Info, and in the Masters tab, give the font the proper ascender and descender values. To best understand how these values work, open the San Francisco font in the program and see how Apple did it (it's the font they made specifically for macOS and iOS development). As a side note, if you use this app, when you're editing the font's info, go into the Features tab as well, delete all of the features (using the minus icon in the lower left) and hit Update to let the program manage the font's features for you. The last hurdle is clipping at the leading edge (not the top and bottom) which the ascender and descender metrics don't address. You can use the Glyphs program to edit the canvas size of individual characters to make sure they all fit but that changes the complexion of the font because it changes the character spacing too noticeably. For this problem, I think the best solution is to simply use attributed strings for your labels and text fields. And that's because attributed strings let you safely edit padding without hacking into intrinsic sizes. An example: someLabel.attributedText = NSAttributedString(string: "Done", attributes: [NSAttributedString.Key.font: UIFont.blackItalic(size: 26), NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.paragraphStyle: NSMutableParagraphStyle.kItalicCenter]) For convenience, I extended NSMutableParagraphStyle since I use this font all over: extension NSMutableParagraphStyle { static var kItalicCenter: NSMutableParagraphStyle { let s = NSMutableParagraphStyle() s.alignment = .center s.firstLineHeadIndent = 2 s.headIndent = 2 return s } } This label will push the font forward a couple of points to prevent clipping.
I was trying to solve similar problem with diacritics in Arabic and found workaround: I have a UITableViewCell with UILabel with arabic text, it's diacritics were cut sometimes I overrided - (void)drawRect:(CGRect)frame to directly draw NSAttributedString on UITableViewCell Also I decreased alpha self.arabicLabel.alpha = 0.1; to draw manually on top of label position, I still keep it to calculate cell's height - (void)drawRect:(CGRect)frame { [super drawRect:frame]; if (self.viewModel == nil) return; NSAttributedString *string = [self.viewModel arabicStringWithTajweed]; CGRect originalRect = [self convertRect:self.arabicLabel.frame fromView:self.arabicLabel]; [string drawInRect:originalRect]; }
The core problem on iOS is font substitution. You are specifying a latin font, the font does not contain glyphs for the characters that will be rendered, the system uses a different font to draw the glyphs, but it is still measuring based on the original font. Option 1, the most robust option, is to manually choose fonts that include glyphs for the characters you will render. When the font assigned to UILabel, or the attributed string it is rendering, contains all the glyphs that will be rendered, and that font has good metrics as most system fonts do, then nothing will be clipped. Option 2, manually measure the string using glyph bounds. Make a subclass of UILabel and override textRectForBounds and possibly drawText. Measure the string with .usesDeviceMetrics. This is slower that measuring by font metrics and produces different results. For example, the strings "a" and "A" will measure differently. Option 3, use baseline offset and line height multiple to make room for the diacritics that are being clipped. Choose or compute constant values for each font for each language, and apply those to the attributed string of the UILabel. This can compensate for the different in font metrics between the font you chose and the font that is actually rendering glyphs. We had localized strings with the worst case clipped characters for each language, and used those to compute the offset and height. Different fonts have different worst case clipping characters.
Font in GVedit Editor
Is it possible to change the font size of the code in in GVedit Editor? I do not mean the font of text in created graphs, but the font size of the source code.
Copy the text from webpage or word to GVEdit, the format will not change. But I haven't find where to config it.
Vertical alignment of iOS custom font in different languages
I am using a custom .ttf font called Classic Robot in my iOS app. I am trying to add Japanese translation and this font appears to not support Japanese characters. This is not a problem initially because it appears iOS automatically changes the font to the system default font which can support Japanese. My issue is that these two fonts have different vertical alignment when rendered by iOS as in the below pictures. As you can see, the Japanese font is aligned near the top of the white box (which is the frame) whereas the English font sits somewhere near the middle. This makes it difficult for me to layout text properly. Does anyone know why this might be the case? I believe it might have to do with the ascender and descender properties on the iOS font I cannot be certain.
Your question is: "Does anyone know why this might be the case?" The answer is that the ascender property of the Japanese font is smaller than the Classic Robot one. This can be fixed by generating a custom Japanese font that has an ascender property large enough to make it match the spacing you get from the other font. This can be done by downloading the Apple Font Tool Suite and following the instructions posted in this answer. Also for buttons you can solve the issue by increasing the insets: myButton.contentEdgeInsets = UIEdgeInsetsMake(15.0, 0.0, 0.0, 0.0); You can specify a different value for each of the four insets (top, left, bottom, right). A positive value shrinks, or insets, that edge—moving it closer to the center of the button. A negative value expands, or outsets, that edge. This works for the button image and button title.
Is it possible to adjust the baseline in NSAttributedString?
I'd like to slightly modify the y position of a character in an NSAttributedString. I know I can subscript (or superscript) using the attribute dictionary: #{(id)kCTSuperscriptAttributeName: #(-1)} Unfortunately the shift caused by this is too large in my case. I'm looking for an option to adjust the baseline in 1-point steps. The attributed string will be displayed in a UIButton using -setAttributedTitle:forState:.
As of iOS 7 the NSBaselineOffsetAttributeName attribute has been added.
Yes you can... but only if you draw the text yourself like I am doing it in my DTCoreText open source project. See line 924ff in DTCoreTextLayoutFrame.m here: https://github.com/Cocoanetics/DTCoreText/blob/master/Core/Source/DTCoreTextLayoutFrame.m Unfortunately that's the ONLY way I know how to. UIKit does not give you this option.
Font positioning error relating to either font-size or font encoding
I've run into a problem where the glyphs are positioned as I expect when I specify line height:1 UNTIL the font-size became greater than 255px. Set the font-size to 256 and bam, the glyphs change position dramatically and become too high on the line. I'm using Google Web fonts to bring in Josefin Sans - http://www.google.com/webfonts/specimen/Josefin+Sans Edit: I'm using Chrome on Fedora, not one of those cool machines with market share and funding Simplified fiddle here - http://jsfiddle.net/jBAnc/ Edit: The fiddle isn't showing the code for me. If you click on "Bacon", it'll toggle between 255 and 256, causing it to bounce back and forth (at least for me). I don't encounter this problem when the font is a basic web-safe font such as Arial, so I assume it has something to do with the google Web-font. Is this a problem with the font's encoding, possibly the program the font was created with (255 seems significant)?
I'm getting inconsistent line-height/spacing issues with this font. I'm beginning to suspect that it's a problem with the construction of Josefin Sans itself. EDIT: after a little more Googlizing, it appears the issue is not so much the font itself, but the Google Webfont API. http://webdesignandsuch.com/fix-fonts-that-dont-work-with-google-font-api-in-internet-explorer-or-chrome-with-font-face/ Short answer: Download and host the font yourself and you should have no issues.
There's nothing wrong at all. You're just expecting all fonts to have the same x-height, descender/extender-heights, and they just don't (9 times out of 10). The following fiddle illustrates the differences between 4 fonts (3 being very common fonts found on Macs, PCs, etc). And Josefin Sans is in the house as well. Pay particular attention to the differences in: the top spacing between the capital Q and its parent's border the various heights of the Xx (especially, the lower-case vs capital) descender of the lower-case G (some actually come out of their parent) _http://jsfiddle.net/suK2U/ To answer your question about 255/256px, I'd venture to say that you just happened upon a 'sweet-spot' between your container and its parent. At 256, it starts colliding (and margins start to collapse, or the like).