View Full Version : drawing text to a CGContext
printf
Oct 11, 2008, 05:49 PM
I have a CGContext that is not associated with any window. I am trying to draw text to it using the following:
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
Oct 11, 2008, 06:21 PM
Looks like Apple recommends ATSUDrawText() for this. See Drawing Text Using a Quartz Context (http://developer.apple.com/documentation/Carbon/Conceptual/ATSUI_Concepts/atsui_chap4/chapter_4_section_7.html).
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):
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
Oct 11, 2008, 09:46 PM
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:
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
Oct 12, 2008, 05:04 AM
finally got it working thanks to some source i found on apple's developer site:
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 )
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
Oct 12, 2008, 11:46 AM
Usually you need to flip the coordinates in this situation, so you could try creating a CGAffineTransform and rotating with CGAffineTransformRotate().
vBulletin® v3.8.6, Copyright ©2000-2012, Jelsoft Enterprises Ltd.