Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

printf

macrumors regular
Original poster
Aug 27, 2008
105
0
I have a CGContext that is not associated with any window. I am trying to draw text to it using the following:

Code:
TXNTextBoxOptionsData options = {kTXNUseCGContextRefMask,kATSUStartAlignment,kATSUNoJustification,0,context};
TXNDrawCFStringTextBox(string,&bounds,gDefaultStyle,&options);

this subject isn't covered very well in the docs (the portions i read anyway), so i had to figure this out on my own with the help of google, yet i'm still doing something wrong because the text is written to the current window instead of the context i'm passing in to the TXNTextBoxOptionsData struct.

what do i need to do to get this to work properly?
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
Looks like Apple recommends ATSUDrawText() for this. See Drawing Text Using a Quartz Context.

If you want to draw fancier text you may want to look into using Cocoa to draw the text because the Cocoa classes are quite easier than the C functions. For example, you could put this into a separate .m file and call from your Carbon code (untested):

Code:
void drawTextAtPoint(CFStringRef string, CGPoint point, CFDictionaryRef attributes) {
    static int loaded = 0;
    if (!loaded) {
        NSApplicationLoad(); // load Cocoa frameworks
        loaded = 1;
    }
    [(NSString *)string drawAtPoint:NSMakePoint(point.x, point.y) attributes:(NSDictionary *)attributes];
}
 

printf

macrumors regular
Original poster
Aug 27, 2008
105
0
yeah, i tried that the other day, but i had the same amount of luck. here's my function. it compiles with no errors, warnings, or results, unfortunately:

Code:
void drawText(CGContextRef context){//, CFStringRef str){
	 CFStringRef str = CFSTR("test");
	
     ATSUStyle     myStyle ;
     ATSUTextLayout myTextLayout ;

	 UniChar* unicode_string;	 
	 	 
	 int unicode_length = CFStringGetLength(str); 
    
     ATSUAttributeTag     theTags[] = {kATSUSizeTag} ;
     ATSUAttributeTag     theTagsLayout[] = {kATSUCGContextTag};
     ByteCount          theSizes[] = {sizeof(Fixed)};
     ByteCount          theSizesLayout[] = {sizeof(CGContextRef)};
     Fixed               atsuSize = 10 ;
     ATSUAttributeValuePtr     theValues[] = {&atsuSize};
     ATSUAttributeValuePtr     theValuesLayout[] = {&context};
     
	 ATSUCreateStyle(&myStyle);
	 ATSUSetAttributes(myStyle,1,theTags,theSizes,theValues);
	 ATSUCreateTextLayout(&myTextLayout);    
	 ATSUSetRunStyle(myTextLayout,myStyle,0,unicode_length);
	 ATSUSetLayoutControls(myTextLayout,1,theTagsLayout,theSizesLayout,theValuesLayout);
	 
	 unicode_string = (UniChar*)malloc(unicode_length*sizeof(UniChar));
	 CFStringGetCharacters( str, CFRangeMake( 0, unicode_length ), unicode_string );	 
	 CFRelease( str );

	 ATSUSetTextPointerLocation(myTextLayout,unicode_string,kATSUFromTextBeginning,kATSUToTextEnd,unicode_length);
     
     ATSUDrawText(myTextLayout,kATSUFromTextBeginning,kATSUToTextEnd,0,0);
     ATSUDisposeStyle(myStyle);
}

i know for sure the problem is in this function and not outside as the context renders quite nicely - just with no text :/
 

printf

macrumors regular
Original poster
Aug 27, 2008
105
0
finally got it working thanks to some source i found on apple's developer site:

Code:
static void DrawWithATSUI2(CGContextRef ctx, float posX, float posY, CFStringRef str, Str255 fontName, float fontSize)
{
    size_t textLength = CFStringGetLength(str);
    UniChar* theUnicodeText = (UniChar*)calloc(textLength, sizeof(UniChar));
    CFStringGetCharacters(str, CFRangeMake(0, textLength), theUnicodeText);

    ATSUFontID atsuFontID;
    ATSUFindFontFromName(&fontName[1], fontName[0], kFontFamilyName, kFontNoPlatformCode, kFontNoScriptCode, kFontNoLanguageCode, &atsuFontID);

    Fixed atsuSize = FloatToFixed(fontSize);
    
    ATSUAttributeTag	    theTags  [2] = { kATSUFontTag, kATSUSizeTag };
    ByteCount		    theSizes [2] = { sizeof(ATSUFontID), sizeof(Fixed) };
    ATSUAttributeValuePtr   theValues[2];
    theValues[0] = &atsuFontID;
    theValues[1] = &atsuSize;

    ATSUStyle theStyle;
    ATSUCreateStyle(&theStyle);
    ATSUSetAttributes( theStyle, 2, theTags, theSizes, theValues );

    ATSUTextLayout theLayout;
    ATSUCreateTextLayoutWithTextPtr(theUnicodeText, 0, textLength, textLength, 1, &textLength, &theStyle, &theLayout);

    // Ask ATSUI to use our ctx
    theTags  [0] = kATSUCGContextTag;
    theSizes [0] = sizeof(CGContextRef);
    theValues[0] = &ctx;
    ATSUSetLayoutControls(theLayout, 1, theTags, theSizes, theValues);

    ATSUDrawText(theLayout, kATSUFromTextBeginning, kATSUToTextEnd, FloatToFixed(posX), FloatToFixed(posY) );
    
    free(theUnicodeText);
    ATSUDisposeStyle(theStyle);
    ATSUDisposeTextLayout(theLayout);
}

the only problem is i can't use this any more to use the coordinate system i'm used to with 0,0 being top left:
(see link for more info: http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/chapter_3_section_2.html#//apple_ref/doc/uid/TP30001066-CH203-CJBDCHAC )
Code:
	CGContextTranslateCTM(context, 0, viewBounds.size.height);
	CGContextScaleCTM(context, 1.0, -1.0);
because it flips the text upside-down. now if you know how to use the top-left as 0,0 and not flip the text - that wold be awesome!
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
Usually you need to flip the coordinates in this situation, so you could try creating a CGAffineTransform and rotating with CGAffineTransformRotate().
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.