39

On an iPhone how do I calculate the size of a character in pixels for a given point size?

Naaff
  • 9,213
  • 3
  • 38
  • 43
Ian1971
  • 3,666
  • 7
  • 33
  • 61

8 Answers8

65

Point sizes are defined as 1/72 of an inch. That is, a 72-point font is approximately 1 inch from the lowest descent to the highest ascent. So the maximum height of a glyph in a 72pt font is about 1 inch.

Apple's iphone tech specs page claims that the iPhone currently has a resolution of 163 pixels per inch. So 72 points is 163 pixels, or about 2.2639 pixels per point. Just remember that every glyph varies in height and width, so this is a very rough estimate of size. Generally, the distance between baselines will be a bit larger than the font's point size so that lines of text don't crash into each other.

If you need exact measurements (and you probably do) then you'll need to actually measure the font glyphs using the font metric information. You can do this by using NSString's UIKit additions, which will let you measure the size of a particular string when rendered on screen.

Naaff
  • 9,213
  • 3
  • 38
  • 43
  • 10
    Also worth noting that the iPhone is not the only iPhone-OS device. The iPod touch is 160 dpi. So, already, not all iPhone-OS devices have the same resolution. If Apple ever doubles it, introduces a tablet, introduces a wristwatch, or whatever, and you're assuming fixed numbers of pixels, you're screwed. Be resolution independent, because if you don't, your app will someday break. – Peter Hosey Jul 02 '09 at 02:38
  • 6
    Hey, guess what - Apple introduced a tablet with a different dpi :-) – philsquared Mar 27 '10 at 11:12
  • also, Apple made a phone and ipod with higher dpi... your app would surely break :) – Richard J. Ross III Feb 17 '11 at 18:54
  • 2
    Hey guess what - Apple introduced a watchband for their iPod Nano so they have technically also launched a wristwatch. :) – Tony Bolero Jan 12 '12 at 08:30
  • 1
    @philsquared that doesnt matter because the systems assumes you are allways coding for 72 dpi, and then upscales at run time automatically. – Sabobin Oct 30 '12 at 14:14
  • Link to NSString UIKit Additions is broken – shim Jun 15 '16 at 18:04
  • and where example? – user924 Mar 29 '18 at 11:48
32

To match font sizes (in Points) on the iPhone4 with font sizes (in Points) in Photoshop you have to set your Photoshop document to 144dpi. I have run a number of tests and that's the resolution that produces 1:1 results.

Steps:

  • Take a screenshot of “Settings » General » Accessibility » Large Text” on an iPhone4
  • Open the screenshot in Photoshop
  • Change the resolution from 72dpi to 144dpi with “Resample Image” off
  • Retype the text in Photoshop (in Points) to match size in the screenshot

I have gone through a number of different resolutions, including the 163dpi that was mentioned in the answer above, and I found that 144dpi produces 1:1 results. I have also tested this against a native app where I know the point sizes and the 144dpi was match there too.

Max von Hippel
  • 2,856
  • 3
  • 29
  • 46
Kai
  • 451
  • 4
  • 5
  • 3
    and 125% for every whitespace seems to fit perfectly –  Aug 07 '12 at 09:13
  • 1
    not sure it's answering the question, but it's exactly what I was looking for, you should eventually move this answer to "how to match font size in Photoshop and iOS/xcode" – Hugues BR May 12 '14 at 17:02
  • This works greate for me. Of course, it applies to resolutions of 1x rather than 2x (Retina). So, for example, on an iPad layout, use a resolution of 768x1024 at 144 dpi to match font sizes. – Mark Nugent Jan 23 '15 at 17:31
  • 144 works for iPhone 4s & 5, but it appears that to match iPhone 6 and 6+ requires a resolution of 216dpi in Photoshop. – Ben Thielker Jul 31 '15 at 20:55
  • Links are down. – Max von Hippel May 17 '18 at 19:49
5

Our graphic artist was very specific on certain devices to use pixel sizes instead of point size. The function below will return a font based on pixel size. It uses a brute force method to find the closet font, but then caches the results so next time the return will be very fast. I always appreciate comments on how this code could be made better. I use this function as a static class member in class called utils. You can easily paste into any class you are using. Hope it is of some help.

/** return a font as close to a pixel size as possible
example:
    UIFont *font = [Utils fontWithName:@"HelveticaNeue-Medium" sizeInPixels:33];
 @param fontName name of font same as UIFont fontWithName
 @param sizeInPixels size in pixels for font
 */
+(UIFont *) fontWithName:(NSString *) fontName sizeInPixels:(CGFloat) pixels {
    static NSMutableDictionary *fontDict; // to hold the font dictionary
    if ( fontName == nil ) {
        // we default to @"HelveticaNeue-Medium" for our default font
        fontName = @"HelveticaNeue-Medium";
    }
    if ( fontDict == nil ) {
        fontDict = [ @{} mutableCopy ];
    }
    // create a key string to see if font has already been created
    //
    NSString *strFontHash = [NSString stringWithFormat:@"%@-%f", fontName , pixels];
    UIFont *fnt = fontDict[strFontHash];
    if ( fnt != nil ) {
        return fnt; // we have already created this font
    }
    // lets play around and create a font that falls near the point size needed
    CGFloat pointStart = pixels/4;
    CGFloat lastHeight = -1;
    UIFont * lastFont = [UIFont fontWithName:fontName size:.5];\

    NSMutableDictionary * dictAttrs = [ @{ } mutableCopy ];
    NSString *fontCompareString = @"Mgj^";
    for ( CGFloat pnt = pointStart ; pnt < 1000 ; pnt += .5 ) {
        UIFont *font = [UIFont fontWithName:fontName size:pnt];
        if ( font == nil ) {
            NSLog(@"Unable to create font %@" , fontName );
            NSAssert(font == nil, @"font name not found in fontWithName:sizeInPixels" ); // correct the font being past in
        }
        dictAttrs[NSFontAttributeName] = font;
        CGSize cs = [fontCompareString sizeWithAttributes:dictAttrs];
        CGFloat fheight =  cs.height;
        if ( fheight == pixels  ) {
            // that will be rare but we found it
            fontDict[strFontHash] = font;
            return font;
        }
        if ( fheight > pixels ) {
            if ( lastFont == nil ) {
                fontDict[strFontHash] = font;
                return font;
            }
            // check which one is closer last height or this one
            // and return the user
            CGFloat fc1 = fabs( fheight - pixels );
            CGFloat fc2 = fabs( lastHeight  - pixels );
            // return the smallest differential
            if ( fc1 < fc2 ) {
                fontDict[strFontHash] = font;
                return font;
            } else {
                fontDict[strFontHash] = lastFont;
                return lastFont;
            }
        }
        lastFont = font;
        lastHeight = fheight;
    }
    NSAssert( false, @"Hopefully should never get here");
    return nil;
}
bret
  • 796
  • 9
  • 5
3

I believe you're looking for the UIFont NSString extensions that allow you to calculate the size of a string given a UIFont.

Here is the Link

Specifically the sizeWithFont methods.

iBug
  • 2,334
  • 3
  • 32
  • 65
CynicismRising
  • 940
  • 4
  • 5
1

You can't reliably convert points to pixels as the ppi (points-per-inch) will change from monitor to monitor. Have a read;

http://hsivonen.iki.fi/units/

Convert Pixels to Points

That said, some people have put together a few reference tables and calculators that may get you started;

http://www.unitconversion.org/typography/postscript-points-to-pixels-x-conversion.html

http://sureshjain.wordpress.com/2007/07/06/53/

Community
  • 1
  • 1
Mathew
  • 8,203
  • 6
  • 37
  • 59
  • 4
    I'm pretty sure people aren't plugging monitors into their iPhones. – Mike Daniels Jun 29 '09 at 16:38
  • 3
    What if Apple change the resolution of the iPhone without changing the physical screen size? The PPI would change and so any point to pixel conversions made at the old PPI would be redundant. – Mathew Jun 29 '09 at 17:40
  • MatW - I agree that is something to consider but in that event I will most likely have to retest my app anyway. I imagine quite a few apps out there would have issues. – Ian1971 Jun 30 '09 at 07:30
  • also, I think the NSString UIKit additions mentioned would get around this problem. – Ian1971 Jun 30 '09 at 07:31
  • 1
    Mike Daniels: It doesn't matter. Not all iPhone-OS devices have the same resolution; the iPod touch is slightly lower-res. Moreover, Apple could, someday, add the ability for applications to address a TV or monitor that the device is connected to through a dock. – Peter Hosey Jul 02 '09 at 02:40
  • 1
    Peter Hosey doesn't know what he is talking about. All iPhone OS devices have the same underlaying metrics when it comes to pixels. And I'll eat my hat if any future iOS device doesn't. – mxcl Feb 23 '11 at 18:47
1

The easiest way to get the pixel height for a given font and size is to use the boundingRect method on NSString. (I'm using @"Ap" here to make sure it contains a descender and an ascender.)

- (CGFloat)heightForFont:(UIFont *)font
{
    NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
    CGRect boundingRect = [@"Ap" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:context];
    return boundingRect.size.height;
}
voidStern
  • 3,678
  • 1
  • 29
  • 32
0

I will add them as I figure them out:

A sizedToFit UILabel with a 12pt systemFont is 15px high.

mxcl
  • 26,392
  • 12
  • 99
  • 98
0

You can calculate the pixel size on the fly by rendering a NSAttributedString and getting its size.

extension UIFont {
    var pixelSize: CGFloat {
        let string = "AWZgjpq"
        let attributedString = NSMutableAttributedString(string: string)
        attributedString.setAttributes([.font: self], range: NSRange(location: 0, length: string.count))
        return attributedString.size().height
    }
}

Further optimizations could be to add a lookup dictionary and cache results and/or make the test string not a variable (but the call itself is really fast). Also, if your font has some very irregular glyphs you can add them to the test string as well.

Usage: let pixelSize = label.font.pixelSize

Markus
  • 599
  • 1
  • 5
  • 18