TI/TDA3

Draw2D를 이용해 한글 표시

728x90

본 글은 TDA3 플랫폼에서 화면에 UTF-8 인코딩 기반의 한글 문자를 표시하기 위한 Draw2D 기반의 문자 출력 작업을 단계별로 정리한 가이드입니다. 

1. 기본 개념: 화면 출력 원리

  • 디스플레이 출력은 픽셀 단위로 점을 찍는 방식입니다.
  • 문자를 표시하려면 **글자마다 픽셀의 점 활성/비활성 상태를 갖는 font data가 필요합니다.

2. Font 데이터 생성 준비

기본적으로 제공된 Draw2D 문자 데이터는 ASCII 데이터를 기반으로 합니다. 

핵심

  • 한자/한글 문자를 표시하려면 글자별 Dot(점) 형태의 비트맵 데이터가 있어야 합니다.
  • 이를 위해 다음 도구를 사용할 수 있습니다:
    • font generator 소프트웨어

font.py
0.00MB

server@server-MS-7B23:~/work$ python3 font.py 
한글 문자열을 입력하세요: 조 
폰트 크기(px)를 입력하세요 (예: 16, 24, 32): 16

// ====================================================
// TEXT = "조"
// Font size = 16x16, 1bit, LSB-left
// ====================================================

{ "조", { 0x00,0x00,0x00,0x00,0xF8,0x0F,0x00,0x0E,0x00,0x06,0x00,0x03,0xC0,0x03,0xE0,0x07,0x38,0x1C,0x8C,0x31,0x80,0x01,0x80,0x01,0xFE,0x7F,0x00,0x00,0x00,0x00,0x00,0x00 } },

// ASCII preview: "조"
················
················
···█████████····
·········███····
·········██·····
········██······
······████······
·····██████·····
···███····███···
··██···██···██··
·······██·······
·······██·······
·██████████████·
················
················
················

위 프로그램은 PC에서 TTF 한글/영문 폰트를 16x16 같은 고정 크기 에서 1bit 비트맵으로 변환하여, TI Draw2D에서 바로 쓸수 있게 C 배열로 변환하는 프로그램 입니다.

 

3. 데이터 구조 작성

UTF-8 기반 중요 포인트

  • 한글은 UTF-8 인코딩에서 3바이트 사용 → 따라서 널 종료 포함하여 4바이트 형태로 처리.
  • 만든 비트맵 데이터를 사용합니다.

코드 예시

#include <utils/draw2d/include/draw2d.h>

static const UInt32 gDraw2D_Font_BytesPerPixel = 2;
static const UInt32 gDraw2D_Font_CharNum = 2;        /* 현재 한글 문자 개수 */
static const UInt32 gDraw2D_Font_CharWidth = 24;
static const UInt32 gDraw2D_Font_CharHeight = 24;

static const typFNT_KR24 gDraw2D_Font_KR24[] =
{
    { "조", { 0x00,0x00,0x00,0x00,0xF8,0x0F,0x00,0x0E,0x00,0x06,0x00,0x03,0xC0,0x03,0xE0,0x07,0x38,0x1C,0x8C,0x31,0x80,0x01,0x80,0x01,0xFE,0x7F,0x00,0x00,0x00,0x00,0x00,0x00 } },
    { "준", { 0x00,0x00,0xF8,0x0F,0x00,0x0F,0xC0,0x03,0xF0,0x0F,0x1C,0x38,0x00,0x00,0x00,0x00,0xFE,0x7F,0x80,0x01,0x80,0x01,0x98,0x01,0x18,0x00,0x18,0x00,0xF8,0x1F,0x00,0x00 } },
  }
};

주의:

  • Index[4]UTF-8 3바이트 + 널 종료 구성.
  • Dot 데이터는 폭×높이×bpp 계산값이며, 여기서는 24×24×2byte 기준.

4. 속성 함수 구현

Int32 Draw2D_getFontPropertyKorea24x24(Draw2D_FontProperty *pProp)
{
    if(pProp == NULL)
        return SYSTEM_LINK_STATUS_EFAIL;

    pProp->width       = gDraw2D_Font_CharWidth;
    pProp->height      = gDraw2D_Font_CharHeight;
    pProp->addrKorea24   = (typFNT_KR24 *)gDraw2D_Font_KR24;
    pProp->num         = gDraw2D_Font_CharNum;
    pProp->bpp         = gDraw2D_Font_BytesPerPixel;
    pProp->lineOffset  = pProp->num * pProp->width * pProp->bpp;
    pProp->colorFormat = SYSTEM_DF_BGR16_565;

    return SYSTEM_LINK_STATUS_SOK;
}

주요 속성 세팅

  • width, height
  • 문자 수(num)
  • 픽셀 포맷(colorFormat)
  • 메모리 오프셋 계산(lineOffset)

5. 한글 문자열 출력 함수 구현

UInt8 *Draw2D_getKoreaFontCharAddr(Draw2D_FontProperty *font, char *c)
{
    UInt16 i = 0;

    if (font == NULL || c == NULL)
        return NULL;

    for (i = 0; i < font->num; i++)
    {
        if (strcmp(font->addrKorea24[i].Index, c) == 0)
        {
            /* 일치하는 문자 찾음 */
            break;
        }
    }

    return ((UInt8 *)font->addrKorea24 + i * sizeof(typFNT_KR24));
}
  • UTF-8 문자열에 대응하는 블록 주소 반환.
  • strcmp로 일치 여부 확인.

6. Draw2D를 이용한 한자 문자열 출력 함수

핵심: 문자 → 픽셀

static inline UInt32 utf8_char_bytes(const char *s)
{
    unsigned char c = (unsigned char)*s;

    if ((c & 0x80) == 0x00)      /* 0xxxxxxx: 1바이트 (ASCII) */
        return 1;
    else if ((c & 0xE0) == 0xC0) /* 110xxxxx: 2바이트 */
        return 2;
    else if ((c & 0xF0) == 0xE0) /* 1110xxxx: 3바이트 (한글) */
        return 3;
    else if ((c & 0xF8) == 0xF0) /* 11110xxx: 4바이트 */
        return 4;
    else
        return 1;  /* 에러 시 기본값 */
}

Int32 Draw2D_drawKoreaString_rot(Draw2D_Handle pCtx,
                                 UInt32 startX,
                                 UInt32 startY,
                                 char *str,
                                 Draw2D_FontPrm *pPrm,
                                 UInt32 rotate)
{
    Draw2D_Obj *pObj = (Draw2D_Obj *)pCtx;

    uint32_t h, w, px, py, charIndex;
    uint8_t *fontAddr;
    uint8_t byte, bit;
    uint16_t color;
    Draw2D_FontProperty font;

    /* UTF-8 문자 임시 버퍼: 최대 3바이트 + '\0' */
    char strTmp[4];
    const char *p;
    UInt32 charBytes;

    /* rotate는 호환성을 위해 유지하지만 현재 미사용 */
    (void)rotate;

    /* 폰트 속성(폭/높이/테이블 주소 등) 세팅 */
    Draw2D_getKoreaFontProperty(pPrm, &font);

    /* 시작 위치가 화면 밖이면 종료 */
    if (startX >= pObj->bufInfo.bufWidth)
        return 0;
    if (startY >= pObj->bufInfo.bufHeight)
        return 0;

    color = pPrm->textColor;

    /* 문자열을 UTF-8 단위로 파싱하며 렌더링 */
    p = str;
    charIndex = 0;

    while (*p != '\0')
    {
        /* 현재 문자의 바이트 수 계산 */
        charBytes = utf8_char_bytes(p);

        /* strTmp를 0으로 채워 '\0' 보장 */
        memset(strTmp, 0, sizeof(strTmp));

        /* UTF-8 문자 복사 (실제 바이트 수만큼만) */
        memcpy(strTmp, p, charBytes);

        /* 해당 글자의 폰트 구조체 시작 주소 얻기 */
        fontAddr = Draw2D_getKoreaFontCharAddr(&font, strTmp);
        if (fontAddr == NULL)
        {
            /* 폰트 테이블에 없는 문자는 건너뛰고 다음 문자로 */
            p += charBytes;
            charIndex++;
            continue;
        }

        /*
         * typFNT_KR16 구조체에서 Index 영역을 건너뛰고 bitmap 데이터 시작 위치로 이동.
         * - Index가 char[4]라고 가정하면 sizeof(Index)=4
         * - 만약 구조체 정의가 다르면 오프셋이 틀어짐(offsetof 사용이 더 안전)
         */
        fontAddr += sizeof(font.addrKorea16->Index);

        /* 현재 글자 출력 위치 */
        px = startX + charIndex * font.width;
        py = startY;

        /*
         * 폰트는 1bit bitmap이라고 가정:
         * - width=16이면 한 줄은 16bit = 2바이트(font.width/8)
         * - (font.width/8) * h 로 h번째 행의 시작 주소 계산
         */
        for (h = 0; h < font.height; h++)
        {
            for (w = 0; w < (font.width / 8); w++)
            {
                /* h번째 행의 w번째 바이트 */
                byte = *(fontAddr + w + (font.width / 8) * h);

                /* 이 바이트가 0이면 8픽셀 모두 꺼짐 → skip */
                if (byte == 0)
                    continue;

                /*
                 * bit 0..7을 검사해서 켜진 픽셀만 Draw2D_drawPixel 호출
                 * 현재 구현은 LSB가 "왼쪽" 픽셀이라고 가정(LSB-first, left-to-right)
                 * 만약 폰트 데이터가 MSB-first면 (1 << (7-bit))로 바꿔야 함.
                 */
                for (bit = 0; bit < 8; bit++)
                {
                    if (byte & (1 << bit)) /* ✅ LSB-left */
                    {
                        Draw2D_drawPixel(
                            pCtx,
                            px + (w * 8 + bit),  /* X: 좌→우 */
                            py + h,              /* Y: 상→하 */
                            color,
                            font.colorFormat
                        );
                    }
                }
            }
        }

        /* 다음 문자로 이동 */
        p += charBytes;
        charIndex++;
    }

    return SYSTEM_LINK_STATUS_SOK;
}
  • UTF-8 문자열 길이만큼 루프 - 한글을 3바이트 영어나 특수문자는 1바이트, 다 처리 할 수 있게 바이트 수 처리하여 동작
  • 각 문자 글자폭만큼 점 찍기
  • 비트 검사로 채움/배경 색 결정

7. 테스트 & 확인

예제 호출:

Draw2D_drawKoreaString(handle,
    stringObj->startX,
    stringObj->startY,
    stringObj->context,   // UTF-8 문자열
    &stringObj->font,
    0);
  • 화면에 출력 확인

참고 : 

https://blog.csdn.net/AIRKernel/article/details/125503932?spm=1001.2014.3001.5501

 

728x90

'TI > TDA3' 카테고리의 다른 글

Vision SDK에서 NDK 네트워크 통신 구성하기  (0) 2026.03.20
UART2 추가 가이드  (0) 2026.02.19
I2C SLAVE MODE  (0) 2025.06.03
Vision SDK Usecase 사용 방법  (0) 2025.04.16
CSL Example 프로그램 사용 방법  (0) 2025.04.12