Text height for printing (fixed width)

  • I have a NSString s, a NSFont f, a width w (float) and I want the height of
    s in f font in a rect of width w. It could (very often) have more than one
    line (because of "true" line breaks or lines too long).

    I've tried 2 methods :
        - one from Apple Text NSLayout Programming Guide
        - one from a Matt Neuburg post in MacOSX-dev mailing-list
    They both seems to give wrong results : more there are lines, too smaller is
    the height returned.

    I've written a small app for this problem : there is a NSTextView and a
    custom view which simulates printing. You can try the two methods above.

        http://www.maestric.com/shared/cocoa/NSTextViewPrinting.zip

    Am I wrong somewhere ?
    Thanks.
  • Le 3 janv. 06, à 17:12, Jerry Krinock a écrit :

    > Sorry I have not read these or your project, but it sounds similar to
    > the
    > question in this recent thread:
    >
    > http://www.cocoabuilder.com/archive/message/cocoa/2005/12/20/152875

    You're right, it was my question. You gave the Apple NSLayout Guide
    method. But it didn't really satisfy me, because you said :

    > You may find that you need to add a little margin.  I don't know why,
    > but to guarantee no wrapping I have to add 15 pixels to the returned
    > measurement.  The required margin may depend on your font, size, etc.

    It's true : sometimes (and only sometimes !), it needs a margin. To
    have a font independent margin , I just add a breakline at the end of
    the string when there isn't :

      if( ! [aString hasSuffix:@"\n"])
      aString = [NSString stringWithFormat:@"%@\n", aString];

    It's isn't perfect because there is sometimes a small extra vertical
    space.

    The complete method :
    // from Apple Text NSLayout Programming Guide
    - (float) heightForStringDrawingV1:(NSString *)aString withFont:(NSFont
    *)aFont andWitdh:(float)myWidth
    {
    if( ! [aString hasSuffix:@"\n"])
      aString = [NSString stringWithFormat:@"%@\n", aString];

    NSTextStorage *textStorage = [[[NSTextStorage alloc]
    initWithString:aString] autorelease];
    NSTextContainer *textContainer = [[[NSTextContainer alloc]
    initWithContainerSize:NSMakeSize(myWidth,1e7)] autorelease];
    NSLayoutManager *layoutManager = [[[NSLayoutManager alloc] init]
    autorelease];
    [layoutManager addTextContainer:textContainer];
    [textStorage addLayoutManager:layoutManager];

    [textStorage addAttribute:NSFontAttributeName value:aFont
    range:NSMakeRange(0,[textStorage length])];
    [textContainer setLineFragmentPadding:0.0];

    (void) [layoutManager glyphRangeForTextContainer:textContainer];
    return [layoutManager
    usedRectForTextContainer:textContainer].size.height;
    }

    Thanks for your help Jerry, it's your post which gave me this idea ! _______________________________________________
    Do not post admin requests to the list. They will be ignored.
    Cocoa-dev mailing list      (<Cocoa-dev...>)
    Help/Unsubscribe/Update your Subscription:
    http://lists.apple.com/mailman/options/cocoa-dev/<cocoa...>

    This email sent to <cocoa...>
  • Jérôme,

    What you (and others) are observing here is the typesetter behavior
    difference between measurement and rendering.

    You're using one of string drawing convenience to render text, but
    using NSLayoutManager for measurement.

    Currently the string drawing convenience methods defined in
    NSStringDrawing.h are using
    NSTypesetterBehavior_10_2_WithCompatibility whereas the default
    setting for NSLayoutManager is NSTypesetterLatestBehavior.

    This causes line height calculation mismatch.

    A easy solution for your problem is to add the following line in -
    heightForStringDrawingV1:withFont:andWitdh:.
    [layoutManager
    setTypesetterBehavior:NSTypesetterBehavior_10_2_WithCompatibility];

    Ideally, you should use the same layout manager you used to measure
    for rendering (especially for performance).

    Aki

    > Le 3 janv. 06, à 17:12, Jerry Krinock a écrit :
    >
    >> Sorry I have not read these or your project, but it sounds similar
    >> to the
    >> question in this recent thread:
    >>
    >> http://www.cocoabuilder.com/archive/message/cocoa/2005/12/20/152875
    >
    >
    > You're right, it was my question. You gave the Apple NSLayout Guide
    > method. But it didn't really satisfy me, because you said :
    >
    >> You may find that you need to add a little margin.  I don't know why,
    >> but to guarantee no wrapping I have to add 15 pixels to the returned
    >> measurement.  The required margin may depend on your font, size, etc.
    >
    > It's true : sometimes (and only sometimes !), it needs a margin. To
    > have a font independent margin , I just add a breakline at the end
    > of the string when there isn't :
    >
    > if( ! [aString hasSuffix:@"\n"])
    > aString = [NSString stringWithFormat:@"%@\n", aString];
    >
    > It's isn't perfect because there is sometimes a small extra
    > vertical space.
    >
    > The complete method :
    > // from Apple Text NSLayout Programming Guide
    > - (float) heightForStringDrawingV1:(NSString *)aString withFont:
    > (NSFont *)aFont andWitdh:(float)myWidth
    > {
    > if( ! [aString hasSuffix:@"\n"])
    > aString = [NSString stringWithFormat:@"%@\n", aString];
    >
    > NSTextStorage *textStorage = [[[NSTextStorage alloc]
    > initWithString:aString] autorelease];
    > NSTextContainer *textContainer = [[[NSTextContainer alloc]
    > initWithContainerSize:NSMakeSize(myWidth,1e7)] autorelease];
    > NSLayoutManager *layoutManager = [[[NSLayoutManager alloc] init]
    > autorelease];
    > [layoutManager addTextContainer:textContainer];
    > [textStorage addLayoutManager:layoutManager];
    >
    > [textStorage addAttribute:NSFontAttributeName value:aFont
    > range:NSMakeRange(0,[textStorage length])];
    > [textContainer setLineFragmentPadding:0.0];
    >
    > (void) [layoutManager glyphRangeForTextContainer:textContainer];
    > return [layoutManager
    > usedRectForTextContainer:textContainer].size.height;
    > }
    >
    > Thanks for your help Jerry, it's your post which gave me this
    > idea ! _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<aki...>
    >
    > This email sent to <aki...>
  • Thanks a lot for your crystal clear explanations, Aki.
    Your solution gives the good text height, issue closed.
    Jérôme

    2006/1/3, Aki Inoue <aki...>:
    >
    > Jérôme,
    >
    > What you (and others) are observing here is the typesetter behavior
    > difference between measurement and rendering.
    >
    > You're using one of string drawing convenience to render text, but
    > using NSLayoutManager for measurement.
    >
    > Currently the string drawing convenience methods defined in
    > NSStringDrawing.h are using
    > NSTypesetterBehavior_10_2_WithCompatibility whereas the default
    > setting for NSLayoutManager is NSTypesetterLatestBehavior.
    >
    > This causes line height calculation mismatch.
    >
    > A easy solution for your problem is to add the following line in -
    > heightForStringDrawingV1:withFont:andWitdh:.
    > [layoutManager
    > setTypesetterBehavior:NSTypesetterBehavior_10_2_WithCompatibility];
    >
    > Ideally, you should use the same layout manager you used to measure
    > for rendering (especially for performance).
    >
    > Aki
    >
    >> Le 3 janv. 06, à 17:12, Jerry Krinock a écrit :
    >>
    >>> Sorry I have not read these or your project, but it sounds similar
    >>> to the
    >>> question in this recent thread:
    >>>
    >>> http://www.cocoabuilder.com/archive/message/cocoa/2005/12/20/152875
    >>
    >>
    >> You're right, it was my question. You gave the Apple NSLayout Guide
    >> method. But it didn't really satisfy me, because you said :
    >>
    >>> You may find that you need to add a little margin.  I don't know why,
    >>> but to guarantee no wrapping I have to add 15 pixels to the returned
    >>> measurement.  The required margin may depend on your font, size, etc.
    >>
    >> It's true : sometimes (and only sometimes !), it needs a margin. To
    >> have a font independent margin , I just add a breakline at the end
    >> of the string when there isn't :
    >>
    >> if( ! [aString hasSuffix:@"\n"])
    >> aString = [NSString stringWithFormat:@"%@\n", aString];
    >>
    >> It's isn't perfect because there is sometimes a small extra
    >> vertical space.
    >>
    >> The complete method :
    >> // from Apple Text NSLayout Programming Guide
    >> - (float) heightForStringDrawingV1:(NSString *)aString withFont:
    >> (NSFont *)aFont andWitdh:(float)myWidth
    >> {
    >> if( ! [aString hasSuffix:@"\n"])
    >> aString = [NSString stringWithFormat:@"%@\n", aString];
    >>
    >> NSTextStorage *textStorage = [[[NSTextStorage alloc]
    >> initWithString:aString] autorelease];
    >> NSTextContainer *textContainer = [[[NSTextContainer alloc]
    >> initWithContainerSize:NSMakeSize(myWidth,1e7)] autorelease];
    >> NSLayoutManager *layoutManager = [[[NSLayoutManager alloc] init]
    >> autorelease];
    >> [layoutManager addTextContainer:textContainer];
    >> [textStorage addLayoutManager:layoutManager];
    >>
    >> [textStorage addAttribute:NSFontAttributeName value:aFont
    >> range:NSMakeRange(0,[textStorage length])];
    >> [textContainer setLineFragmentPadding:0.0];
    >>
    >> (void) [layoutManager glyphRangeForTextContainer:textContainer];
    >> return [layoutManager
    >> usedRectForTextContainer:textContainer].size.height;
    >> }
    >>
    >> Thanks for your help Jerry, it's your post which gave me this
    >> idea ! _______________________________________________
    >> Do not post admin requests to the list. They will be ignored.
    >> Cocoa-dev mailing list      (<Cocoa-dev...>)
    >> Help/Unsubscribe/Update your Subscription:
    >> http://lists.apple.com/mailman/options/cocoa-dev/<aki...>
    >>
    >> This email sent to <aki...>
    >
    >
  • Aki Inoue wrote:
    > Jérôme,
    >
    > What you (and others) are observing here is the typesetter behavior
    > difference between measurement and rendering.
    >
    > You're using one of string drawing convenience to render text, but
    > using NSLayoutManager for measurement.
    >
    > Currently the string drawing convenience methods defined in
    > NSStringDrawing.h are using
    > NSTypesetterBehavior_10_2_WithCompatibility whereas the default
    > setting for NSLayoutManager is NSTypesetterLatestBehavior.
    >
    > This causes line height calculation mismatch.
    >
    > A easy solution for your problem is to add the following line in -
    > heightForStringDrawingV1:withFont:andWitdh:.
    > [layoutManager
    > setTypesetterBehavior:NSTypesetterBehavior_10_2_WithCompatibility];
    >
    > Ideally, you should use the same layout manager you used to measure
    > for rendering (especially for performance).
    >
    > Aki
    This is the exact problem I was having as well. Thanks too.
previous month january 2006 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today
MindNode
MindNode offered a free license !