[App 개발] Xcode 2.2 에서 카본 프로그램 만들자 (4) ATSUI
본문
애플의 텍스트 엔진은 ATSUI (Apple Type Service for Unicode Imaging) 라고 합니다. 이름에서도 나와 있듯이 유니코드를 지원하는 놈입니다. 유니코드를 지원하는 것은 좋은데, 그것때문에 프로그램을 짜는 사람이 덤태기로 써야 하는 고생이 이만저만이 아니게 되었다는 것이 문제이겠습니다.
퀵드로우에서는 DrawString 이나 DrawText 를 부르는 것으로 끝이지만, ATSUI 에서는 텍스트 하나를 부르기 위해서 엄청나게 많은 노력이 들어야 합니다. 먼저 폰트 스타일을 정의해야 하고, 그 다음은 레이아웃을 작성한 다음 그것을 화면에 출력하게 됩니다. 한편으로 각국의 다양한 텍스트를 완벽하게 지원할 수 있고, 일반 소프트웨어 레벨에서도 워드프로세서급의 텍스트 에디터를 만들 수 있다는 장점이 있겠습니다.
그러나 우리에게 중요한 것은 장점이 아니라 당장 화면에 글 한 줄 올리는 것이 너무 힘겹다는 것이 문제이겠습니다. ㅡㅡ;
그리하여, 간편하게 텍스트를 출력할 수 있는 간이 함수를 하나 구현해 보았습니다. 이 한 줄을 내보내기 위해서 어떤 피나는 노력을 쏟아부었는지 보시지요.
--- MyDraw.h ---
#include <Carbon/Carbon.h>
void InstallMyDraw( WindowRef window ) ;
OSStatus MyDrawEventHandler( EventHandlerCallRef myHandler,
EventRef event,
void *userData ) ;
OSStatus MyDraw( EventRef event, WindowRef window ) ;
void CreateStyle( void ) ;
void DeleteStyle( void ) ;
void CreateLayout( CGContextRef myContext, HIRect bounds ) ;
void DeleteLayout( void ) ;
void MyDrawText( CGContextRef myContext, char *str, int px, int py ) ;
--- MyDraw.c ---
#include "MyDraw.h"
HIViewRef myHIView ;
void InstallMyDraw( WindowRef window )
{
HIViewID myHIViewID = { 'mVue', 130 } ;
EventTypeSpec myHIViewSpec[] = {
{ kEventClassControl, kEventControlDraw },
} ;
OSStatus err ;
HIViewFindByID( HIViewGetRoot( window ), myHIViewID, &myHIView ) ;
err = InstallEventHandler( GetControlEventTarget( myHIView ),
NewEventHandlerUPP( MyDrawEventHandler ),
GetEventTypeCount( myHIViewSpec ),
myHIViewSpec,
(void *)myHIView,
NULL ) ;
}
OSStatus MyDrawEventHandler( EventHandlerCallRef myHandler,
EventRef event,
void *userData )
{
OSStatus err = eventNotHandledErr ;
switch( GetEventClass( event ) ) {
case kEventClassControl :
{
switch( GetEventKind( event ) )
{
case kEventControlDraw:
err = MyDraw( event, (WindowRef)userData ) ;
break ;
}
break ;
}
default:
break ;
}
return err ;
}
#define kFontName "AppleMyungjo Regular"
#define kFontSize 36
ATSUStyle styleMyungjo ;
ATSUFontID font ;
void CreateStyle( void )
{
Fixed pointSize ;
ATSUAttributeTag tag ;
ByteCount size ;
ATSUAttributeValuePtr value ;
ATSUCreateStyle( &styleMyungjo ) ;
ATSUFindFontFromName( kFontName, strlen( kFontName ),
kFontFullName, kFontNoPlatform,
kFontNoScript, kFontNoLanguage, &font ) ;
tag = kATSUFontTag ;
size = sizeof( ATSUFontID ) ;
value = &font ;
ATSUSetAttributes( styleMyungjo, 1, &tag, &size, &value ) ;
pointSize = Long2Fix( kFontSize ) ;
tag = kATSUSizeTag ;
size = sizeof( Fixed ) ;
value = &pointSize ;
ATSUSetAttributes( styleMyungjo, 1, &tag, &size, &value ) ;
}
void DeleteStyle( void )
{
ATSUDisposeStyle( styleMyungjo ) ;
}
ATSUTextLayout layout ;
void CreateLayout( CGContextRef myContext, HIRect bounds )
{
ATSUAttributeTag tag ;
ByteCount size ;
ATSUAttributeValuePtr value ;
ATSUCreateTextLayout( &layout ) ;
tag = kATSUCGContextTag ;
size = sizeof( CGContextRef ) ;
value = &myContext ;
ATSUSetLayoutControls( layout, 1, &tag, &size, &value ) ;
CGContextTranslateCTM( myContext, 0, bounds.size.height ) ;
CGContextScaleCTM( myContext, 1.0, -1.0 ) ;
}
void DeleteLayout( void )
{
ATSUDisposeTextLayout( layout ) ;
}
void MyDrawText( CGContextRef myContext, char *str, int px, int py )
{
CFStringRef string ;
UniChar *text ;
UniCharCount length ;
string = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8 ) ;
length = CFStringGetLength( string ) ;
text = (UniChar *)malloc( length * sizeof( UniChar ) ) ;
CFStringGetCharacters( string, CFRangeMake( 0, length ), text ) ;
CFRelease( string ) ;
ATSUSetTextPointerLocation( layout, text, kATSUFromTextBeginning, kATSUToTextEnd, length ) ;
ATSUSetRunStyle( layout, styleMyungjo, kATSUFromTextBeginning, kATSUToTextEnd ) ;
ATSUDrawText( layout, kATSUFromTextBeginning, kATSUToTextEnd, X2Fix(px), X2Fix(py) ) ;
free(text) ;
}
OSStatus MyDraw( EventRef event, WindowRef window )
{
OSStatus status = noErr ;
CGContextRef myContext ;
HIRect bounds ;
status = GetEventParameter( event,
kEventParamCGContextRef,
typeCGContextRef,
NULL,
sizeof( CGContextRef ),
NULL,
&myContext ) ;
HIViewGetBounds( (HIViewRef) window, &bounds ) ;
///
CreateLayout( myContext, bounds ) ;
MyDrawText( myContext, "여러분 안녕", 15, bounds.size.height - 100 ) ;
MyDrawText( myContext, "저는 악명높은", 15, bounds.size.height - 150 ) ;
MyDrawText( myContext, "애플 명조예요. -_-;", 15, bounds.size.height - 200 ) ;
CGContextFlush( myContext ) ;
SetPortWindowPort( window ) ;
DeleteLayout() ;
return status ;
}
추가된 함수중에서 먼저 CreateStyle() 과 DeleteStyle() 이 있습니다. 글꼴을 읽어서 그것을 ATSUStyle 형으로 선언하는 작업을 수행합니다. 이 함수는 프로그램의 맨 처음부분인 main() 함수 맨 앞부분에서 CreateStyle() 을 불렀다가 프로그램이 종료되기 전에 DeleteStyle() 을 부르시면 되겠습니다.
CreateLayout() 과 DeleteLayout() 함수는 화면을 그리는 MyDraw() 함수에서 텍스트를 출력하는 첫부분에서 불러주시면 되겠습니다. 코어 그래픽스 컨텍스트를 이용하기 때문에 코어 그래픽스에서 지원하는 각종 효과를 모두 선택할 수 있는 장점이 있습니다. 참고로, 코어 그래픽스에서 지원하는 텍스트 출력 함수는 한글이 지원되지 않습니다. 사실 한글 지원 문제가 이 간이 함수를 만든 이유입니다.
문제의 MyDrawText() 함수가 글자 출력을 담당하는 함수입니다. 프로그램 소스를 UTF-8 로 맞추었다면 간단히 스트링 상수에서 한글을 정의하여 출력할 수 있으므로 아주 편합니다. 한편, 이 소스에서는 화면 좌표를 좌하단을 기준으로 정렬해야 했습니다. 폰트가 거꾸로 출력되었기 때문이죠. ㅡㅡ; 아직 연구가 더 필요한 듯...
최신글이 없습니다.
최신글이 없습니다.
댓글목록 1
악동시니님의 댓글
오늘 집에가서 해봐야겠습니다..