Making bezier paths out of text
Making bezier paths out of text
- Subject: Making bezier paths out of text
- From: John Stiles <email@hidden>
- Date: Tue, 16 Sep 2003 16:38:56 -0700
I am working on an app that needs to convert text into a bezier path.
It works about 99% of the time, but sometimes the paths just don't
happen. No errors are reported to my code, but the bezier paths won't
draw anything, and I get the following errors logged in the console.
Sep 16 16:28:55 MafiaHQ (myapp): kCGErrorFailure :
CGContextSetTextMatrix: invalid context
Sep 16 16:28:55 MafiaHQ (myapp): kCGErrorFailure : CGContextSetFont:
invalid context
Sep 16 16:28:55 MafiaHQ (myapp): kCGErrorFailure :
CGContextSetFontSize: invalid context
Sep 16 16:28:55 MafiaHQ (myapp): kCGErrorFailure : CGContextGetFont:
invalid context
Sep 16 16:28:55 MafiaHQ (myapp): kCGErrorFailure :
CGContextGetFontSize: invalid context
Sep 16 16:28:55 MafiaHQ (myapp): kCGErrorFailure :
CGContextGetTextMatrix: invalid context
(this pattern repeats once for every string I try to turn into bezier
paths)
What could cause this? I wish I had a good reproducible case, but it's
just sporadic. It does seem to happen more often after my app has been
running for some time, but that could be coincidence.
Here's some of my code. I have butchered it up a bit to try to remove
unfamiliar constructs and stuff from it, so it probably wouldn't
compile out of the box, but it's mostly all there. Please let me know
if anything seems out of place.
static void CreateBezierPath( NSBezierPath *bezier, NSString *string,
float size, float *height, float *baseline )
{
// Make our text storage and layout.
NSTextStorage *storage = [[NSTextStorage alloc] initWithString:string];
[storage setFont:[NSFont boldSystemFontOfSize:size]];
// We don't hold on to the layout and container objects because the
NSTextStorage
// object retains them for us.
NSLayoutManager *layout = [[[NSLayoutManager alloc] init]
autorelease];
NSTextContainer *container = [[[NSTextContainer alloc] init]
autorelease];
[layout addTextContainer:container];
[storage addLayoutManager:layout];
// Turn off padding in the container; otherwise we get extra space
padding out each style run.
[container setLineFragmentPadding:0.0];
// Make a bezier path that will represent our text.
bezier = [[NSBezierPath alloc] init];
[bezier setCachesBezierPath:YES];
[bezier moveToPoint:NSMakePoint(0.0, 0.0)];
// Find each style run in the NSTextStorage.
int length = [storage length];
int position = 0;
while( position < length )
{
// Ask the string for a range of characters that all use one font.
NSRange range;
NSFont *layoutFont = [storage attribute:NSFontAttributeName
atIndex:position effectiveRange:&range];
// Get the glyphs from the layout that correspond with the range.
AutoMemoryBlock glyphData( (range.length + 1) * sizeof(NSGlyph) );
// this is just a malloc that frees itself when descoped
int glyphCount = [layout
getGlyphs:glyphData.Ptr<NSGlyph>() range:range];
// Create a bezier path for those glyphs using that font.
[bezier appendBezierPathWithGlyphs:glyphData.Ptr<NSGlyph>()
count:glyphCount inFont:layoutFont];
[bezier setLineWidth:(size * 0.1f)];
// Keep track of how many glyphs have been consumed.
position += glyphCount;
// Get the baseline and height for this block of glyphs.
*baseline = max( *baseline, [layoutFont ascender] );
*height = max( *height, *baseline - [layoutFont descender] );
}
// Force the layout manager to layout the text, and then grab its
width.
// (In the real code we save this, but in the sample code we just
jettison it.
// Interestingly, this part seems to work just fine in any case.)
(void) [layout glyphRangeForTextContainer:container];
float width = [layout usedRectForTextContainer:container].size.width;
// Now that we have a bezier path, we no longer need the text layout
objects.
[storage release];
}
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.