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' 카테고리의 다른 글

I2C SLAVE MODE  (0) 2025.06.03
Vision SDK Usecase 사용 방법  (0) 2025.04.16
CSL Example 프로그램 사용 방법  (0) 2025.04.12
TDA3-EVM PDK Build  (0) 2025.04.12
mflash  (0) 2025.03.19