Question

I have the following sample code which works on iPhone. It draws the text "Hello World!" on the screen using Core Text.

Dropping this code into a cocoa project in an NSView produces different results. The font size is scaled much bigger and the letters are drawn on top of each other. How do I have the text draw the same in the cocoa app?

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);

    CFStringRef font_name = CFStringCreateWithCString(NULL, "Courier", kCFStringEncodingMacRoman);

    CTFontRef font = CTFontCreateWithName(font_name, 36.0, NULL);

    CFStringRef keys[] = { kCTFontAttributeName };

    CFTypeRef values[] = { font };

    CFDictionaryRef font_attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys, (const void **)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

    CFRelease(font_name);

    CFRelease(font);

    int x = 10;
    int y = 10;
    const char *text = "Hello World!";

    CFStringRef string = CFStringCreateWithCString(NULL, text, kCFStringEncodingMacRoman);

    CFAttributedStringRef attr_string = CFAttributedStringCreate(NULL, string, font_attributes);

    CTLineRef line = CTLineCreateWithAttributedString(attr_string);

    CGContextSetTextPosition(context, x, y);

    // Core Text uses a reference coordinate system with the origin on the bottom-left
    // flip the coordinate system before drawing or the text will appear upside down
    CGContextTranslateCTM(context, 0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CTLineDraw(line, context);

    CFRelease(line);

    CFRelease(string);

    CFRelease(attr_string);

    CGContextRestoreGState(context);
}

iPhone in UIView (Expected Result)

enter image description here

Mac in NSView (Unexpected Result)

enter image description here

Was it helpful?

Solution

As @matt has noted, this is not the Cocoa code, the origin of the coordinate system is "bottom-left" on Cocoa, and UIGraphicsGetCurrentContext() does not exist…

Anyway you need to set the text matrix of the context at least to CGAffineTransformIdentity. But as CGContextSetTextPosition don't set the position for CTDrawLine, you need to translate the text matrix to your desired position.

- (void)drawRect:(NSRect)dirtyRect
{
    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
    CGContextSaveGState(context);

    CFStringRef font_name = CFStringCreateWithCString(NULL, "Courier", kCFStringEncodingMacRoman);

    CTFontRef font = CTFontCreateWithName(font_name, 36.0, NULL);

    CFStringRef keys[] = { kCTFontAttributeName };
    CFTypeRef values[] = { font };

    CFDictionaryRef font_attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys, (const void **)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

    CFRelease(font_name);

    CFRelease(font);

    int x = 10;
    int y = 10;

    CFAttributedStringRef attr_string = CFAttributedStringCreate(NULL, CFSTR("Hello World!"), font_attributes);

    CTLineRef line = CTLineCreateWithAttributedString(attr_string);

    // You need to set the text matrix at least to CGAffineTransformIdentity 
    // Here we translate to the desired position
    CGContextSetTextMatrix(context, CGAffineTransformMakeTranslation(x,y));

    CTLineDraw(line, context);

    CFRelease(line);

    CFRelease(attr_string);

    CGContextRestoreGState(context);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top