olikraus / u8g2

U8glib library for monochrome displays, version 2
Other
5.01k stars 1.04k forks source link

u8g2_GetUTF8Width problem on cyrillic strings #693

Closed karawin closed 6 years ago

karawin commented 6 years ago

It seems that the function u8g2_GetUTF8Width has a problem on utf8 cyrillic (and may be other) strings.

The string "Супердискотека 90Ñ…" ie:"Супердискотека 90х" return 19

While the string "Virgin Radio New" return 80

lcd SH1106

define U8G2_16BIT

olikraus commented 6 years ago

Which font did you use?

karawin commented 6 years ago

u8g2_font_6x13_t_cyrillic

olikraus commented 6 years ago

Ok, good. Can you post the complete code?

karawin commented 6 years ago

It is a big project https://github.com/karawin/Ka-Radio32 but the github is not up to date. output of scrollU8g2 function x= 128,scroll: +iline[i]= 0, len=43, x-onechar= 124 scroll: len=19, num= 20, str=Супердискотека 90х

The concerned module is addonu8g2.c `/**

define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE

include

include

include

include "u8g2_esp32_hal.h"

include "addon.h"

include "app_main.h"

include "gpio.h"

include

include "esp_log.h"

include "logo.h"

include "interface.h"

include "eeprom.h"

define TAG "addonu8g2"

// nams <--> num of line

define STATIONNAME 0

define STATION1 1

define STATION2 2

define IP 3

define GENRE 2

define TITLE1 3

define TITLE2 4

define VOLUME 5

define TIME 6

define BUFLEN 256

define LINES 5

static uint16_t y ; //Height of a line static uint16_t yy; //Height of screen static uint16_t x ; //Width static uint16_t z ; // an internal offset for y

//static struct tm *dt; static char strsec[30]; static uint16_t volume;

static char station[BUFLEN]; //received station static char title[BUFLEN]; // received title static char nameset[BUFLEN]; // the local name of the station

static char* lline[LINES] ; // array of ptr of n lines static uint8_t iline[LINES] ; //array of index for scrolling static uint8_t tline[LINES] ; static uint8_t mline[LINES] ; // mark to display

static char nameNum[5] ; // the number of the current station static char genre[BUFLEN/2]; // the local name of the station

/*static uint8_t charset = false;

//////////////////////////////////////// uint8_t getCharset() { return charset; } void setCharset(uint8_t cy) { charset = cy; } / //////////////////////////////////////// typedef enum sizefont {small, text,middle,large} sizefont; void setfont8(sizefont size) { // printf("setfont8 size: %d, yy: %d\n",size,yy); switch(size) { case small: switch(yy) { case 200: u8g2_SetFont(&u8g2,u8g2_font_6x12_tf); break; case 128: u8g2_SetFont(&u8g2,u8g2_font_6x12_tf); break; case 32: u8g2_SetFont(&u8g2,u8g2_font_u8glib_4_tr); break; case 64: default: // u8g2_SetFont(&u8g2, u8g2_font_5x8_tr); ; } break; case text: switch(yy) { / case 200: charset?u8g2_SetFont(&u8g2,u8g2_font_7x13_t_cyrillic):u8g2_SetFont(&u8g2,u8g2_font_7x14_tf);// break; case 128: charset?u8g2_SetFont(&u8g2,u8g2_font_7x13_t_cyrillic):u8g2_SetFont(&u8g2, u8g2_font_7x14_tf);// break; case 32: charset?u8g2_SetFont(&u8g2,u8g2_font_5x7_t_cyrillic):u8g2_SetFont(&u8g2,u8g2_font_5x7_tf);// break; case 64: default: // charset?u8g2_SetFont(&u8g2, u8g2_font_haxrcorp4089_t_cyrillic ):u8g2_SetFont(&u8g2, u8g2_font_6x12_tf); */ case 200: u8g2_SetFont(&u8g2, u8g2_font_8x13_t_latcyr);// break; case 128: u8g2_SetFont(&u8g2, u8g2_font_8x13_t_latcyr);// break; case 32: u8g2_SetFont(&u8g2, u8g2_font_5x7_t_latcyr);// break; case 64: default: // // u8g2_SetFont(&u8g2, u8g2_font_6x12_t_latcyr); u8g2_SetFont(&u8g2, u8g2_font_6x13_t_cyrillic); } break; case middle: switch(yy) { case 200: u8g2_SetFont(&u8g2, u8g2_font_9x18_tf); break; case 128: u8g2_SetFont(&u8g2, u8g2_font_9x18_tf); break; case 32: u8g2_SetFont(&u8g2, u8g2_font_5x8_tf); break; case 64: default: // u8g2_SetFont(&u8g2, u8g2_font_7x14_tf); ;

    }
    break;
    case large:
    switch(yy)
    {
        case 200:
        u8g2_SetFont(&u8g2, u8g2_font_helvR24_tf);
        break;
        case 128:
        u8g2_SetFont(&u8g2, u8g2_font_helvR24_tf);
        break;
        case 32:
        u8g2_SetFont(&u8g2,  u8g2_font_7x14_tf);
        break;
        case 64:
        default: // 
        u8g2_SetFont(&u8g2, u8g2_font_ncenR18_tf);
        ;       
    }
    break;
    default:
    printf("Default for size %d\n",size);
}

}

//////////////////////////////////////// char* getNameNumU8g2() { return nameNum; }

void setVolumeU8g2(uint16_t vol){ volume = vol;}

static uint8_t getFontLineSpacing() { return (u8g2_GetAscent(&u8g2) - u8g2_GetDescent(&u8g2)); } //////////////////////////////////////// // Clear all buffers and indexes void clearAllU8g2() { title[0] = 0; station[0]=0; for (int i=1;i<LINES;i++) {lline[i] = NULL;iline[i] = 0;tline[i] = 0;;mline[i]=1;} } //////////////////////////////////////// void cleartitleU8g2(uint8_t froml) { title[0] = 0; for (int i = froml;i<LINES;i++) // clear lines { lline[i] = NULL; iline[i] = 0; tline[i] = 0; mline[i] = 1; }
}

// Mark the lines to draw void markDrawU8g2(int i) { mline[i] = 1; }

//////////////////////////////////////// // scroll each line void scrollU8g2() { unsigned len , onechar; for (int i = 0;i < LINES;i++) { if (tline[i]>0) { if (tline[i] == 4) {iline[i]= 0;markDrawU8g2(i);} tline[i]--;
} else { if ((lline[i] != NULL)) { onechar = u8g2_GetUTF8Width(&u8g2,"M"); len = u8g2_GetUTF8Width(&u8g2,lline[i]+iline[i]); if (i == 0) printf("scroll: len=%d, num= %d, str=%s\n",len,u8g2_GetUTF8Width(&u8g2,nameNum),lline[i]+iline[i]); if (i == 0) len += u8g2_GetUTF8Width(&u8g2,nameNum)+ onechar; if (i == 0) printf("x= %d,scroll: +iline[i]= %d, len=%d, x-onechar= %d\n",x,iline[i],len,x-onechar); if (len >= x-onechar) {iline[i]++;markDrawU8g2(i);} else tline[i] = 6; } } } }

// Bottom of screens static void screenBottomU8g2() { //VOLUME u8g2_DrawFrame(&u8g2,0,yy-3,x-1,3); u8g2_DrawHLine(&u8g2,0,yy-2,((uint16_t)(x*volume)/255));
//TIME if (yy != 32) // not enough room { setfont8(small); u8g2_DrawUTF8(&u8g2,x/2-(u8g2_GetUTF8Width(&u8g2,strsec)/2),yy-y-3,strsec);
}
}

// draw the screen from buffer void drawLinesU8g2() { u8g2_SendBuffer(&u8g2); }

//Thanks to Max void eraseSlashes(char str) { //Symbols: \" \' \ \? \/ char sym = str, sym1; if (str != NULL) { while (sym != 0) { if (sym == 0x5c) { sym1 = sym + 1; if (sym1 == 0x22 || sym1 == 0x27 || sym1 == 0x5c || sym1 == 0x3f || sym1 == 0x2f) { *sym = 0x1f; //Erase \ to non-printable symbol sym++; }
} sym++; } }
} //-Max

//////////////////////////////////////// // draw all lines void drawFrameU8g2(uint8_t mTscreen,struct tm *dt) { u8g2_ClearBuffer(&u8g2); if (getDdmm()) sprintf(strsec,"%02d-%02d-%04d %02d:%02d:%02d",dt->tm_mday,dt->tm_mon+1,dt->tm_year+1900, dt->tm_hour, dt->tm_min,dt->tm_sec); else sprintf(strsec,"%02d-%02d-%04d %02d:%02d:%02d",dt->tm_mon+1,dt->tm_mday,dt->tm_year+1900, dt->tm_hour, dt->tm_min,dt->tm_sec);

setfont8(text);
u8g2_SetDrawColor(&u8g2, 1);
y = getFontLineSpacing();
u8g2_SetFontRefHeightText(&u8g2); 
{
    u8g2_DrawHLine(&u8g2,0,((yy==32)?3:4*y) - (y/2)-1,x);
    u8g2_DrawBox(&u8g2,0,0,x-1,y);
}
for (int i = 0;i < LINES;i++)
{
    if (i == 0){
        u8g2_SetDrawColor(&u8g2, 0);
    }
    else {
        if (i >=3) z = y/2+2 ; else z = 1;
        u8g2_SetDrawColor(&u8g2, 1);
    }

    int zz = y*i;
    if (yy==32)
    {
        if ((i==STATION2)||(i==TITLE2)) continue;
        if (i==TITLE1) zz = y*GENRE;
    }

    if (lline[i] != NULL)
    {
        //Max
        eraseSlashes(lline[i]);
        if (i == 0) 
        {       
            if (nameNum[0] ==0)  u8g2_DrawUTF8(&u8g2,1,0,lline[i]+iline[i]);
            else 
            {
                u8g2_DrawUTF8(&u8g2,1,0,nameNum);
                u8g2_DrawUTF8(&u8g2,u8g2_GetUTF8Width(&u8g2,nameNum)-1,0,lline[i]+iline[i]);
            }
        }      
        else u8g2_DrawUTF8(&u8g2,0,zz+z,lline[i]+iline[i]);
    }

}
screenBottomU8g2();

}

////////////////////////// void drawTTitleU8g2(char* ttitle) { setfont8(middle); uint16_t xxx = (x/2)-(u8g2_GetUTF8Width(&u8g2,ttitle)/2); u8g2_SetDrawColor(&u8g2, 1); u8g2_DrawBox(&u8g2,0,0,x,getFontLineSpacing()+1); u8g2_SetDrawColor(&u8g2, 0); u8g2_DrawUTF8(&u8g2,xxx,1,ttitle);

u8g2_SetDrawColor(&u8g2, 1);

} ////////////////////////// void drawNumberU8g2(uint8_t mTscreen,char irStr) { char ststr[] = {"Number"}; u8g2_ClearBuffer(&u8g2); drawTTitleU8g2(ststr);
setfont8(large); uint16_t xxx = (x/2)-(u8g2_GetUTF8Width(&u8g2,irStr)/2); u8g2_DrawUTF8(&u8g2,xxx,yy/3, irStr);
screenBottomU8g2();
} ////////////////////////// void drawStationU8g2(uint8_t mTscreen,char
snum,char* ddot) { int16_t len; char ststr[] = {"Station"}; u8g2_ClearBuffer(&u8g2); drawTTitleU8g2(ststr);
if (ddot != NULL) { u8g2_DrawUTF8(&u8g2,(x/2)-(u8g2_GetUTF8Width(&u8g2,snum)/2),yy/3-2, snum); len = (x/2)-(u8g2_GetUTF8Width(&u8g2,ddot)/2); if (len <0) len = 0; u8g2_DrawUTF8(&u8g2,len,yy/3+4+y, ddot); } screenBottomU8g2();
}

void drawVolumeU8g2(uint8_t mTscreen,char* aVolume) { char vlstr[] = {"Volume"}; volume = atoi(aVolume); u8g2_ClearBuffer(&u8g2); drawTTitleU8g2(vlstr) ;
setfont8(large);
uint16_t xxx = (x/2)-(u8g2_GetUTF8Width(&u8g2,aVolume)/2);
u8g2_DrawUTF8(&u8g2,xxx,yy/3,aVolume); screenBottomU8g2(); }

void drawTimeU8g2(uint8_t mTscreen,struct tm *dt,unsigned timein) { char strdate[23]; char strtime[20]; // printf("DRAW TIME U8G2 mtscreen : %d\n",mTscreen); u8g2_ClearBuffer(&u8g2); if (getDdmm()) sprintf(strdate,"%02d-%02d-%04d", dt->tm_mday, dt->tm_mon+1, dt->tm_year+1900); else sprintf(strdate,"%02d-%02d-%04d", dt->tm_mon+1, dt->tm_mday, dt->tm_year+1900); sprintf(strtime,"%02d:%02d:%02d", dt->tm_hour, dt->tm_min,dt->tm_sec); drawTTitleU8g2(strdate); setfont8(large);
u8g2_DrawUTF8(&u8g2,(x/2)-(u8g2_GetUTF8Width(&u8g2,strtime)/2),(yy/3)+4,strtime); // draw ip setfont8(small); sprintf(strdate,"IP: %s", getIp()); u8g2_DrawUTF8(&u8g2,(x/2)-(u8g2_GetUTF8Width(&u8g2,strdate)/2),yy-getFontLineSpacing(),strdate);

}

//////////////////////////////////////// void separatorU8g2(char from) { char interp; while (from[strlen(from)-1] == ' ') from[strlen(from)-1] = 0; // avoid blank at end while ((from[0] == ' ') ){ strcpy( from,from+1); } interp=strstr(from," - "); if (from == nameset) {lline[0] = nameset;lline[1] = NULL;lline[2] = NULL;return;} if ((interp != NULL) && (yy != 32)) { from[interp-from]= 0; lline[(from==station)?1:3] = from; lline[(from==station)?2:4] = interp+3; } else { lline[(from==station)?1:3] = from; } }

//cli.meta void metaU8g2(char* ici) { cleartitleU8g2(3); strcpy(title,ici+7);
separatorU8g2(title);
}

//cli.icy4 void icy4U8g2(char ici) { strcpy(genre,ici+7); lline[2] = genre; } //cli.icy0 void icy0U8g2(char ici) { clearAllU8g2(); if (strlen(ici+7) == 0) strcpy (station,nameset); else strcpy(station,ici+7); separatorU8g2(station);
}

//cli.stopped or label void statusU8g2(char label) { cleartitleU8g2(3); strcpy(title,label); lline[TITLE1] = title; } //cli.nameset void namesetU8g2(char ici) { strcpy(nameset,ici+8); ici = strstr(nameset," "); if (ici != NULL) { clearAllU8g2(); strncpy(nameNum,nameset,ici-nameset+1); nameNum[ici - nameset+1] = 0; setFuturNum(atoi(nameNum));
} strcpy(nameset,nameset+strlen(nameNum)); lline[STATIONNAME] = nameset; }

// cli.playing void playingU8g2() { if (strcmp(title,"STOPPED") == 0) { cleartitleU8g2(3); separatorU8g2(title); } }

void lcd_initU8g2(uint8_t lcd_type) { const u8g2_cb_t rotat; u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT; if (*lcd_type & LCD_SPI) // BW SPI { u8g2_esp32_hal.clk = PIN_NUM_CLK; u8g2_esp32_hal.mosi = PIN_NUM_MOSI; u8g2_esp32_hal.cs = PIN_LCD_CS; u8g2_esp32_hal.dc = PIN_LCD_A0; u8g2_esp32_hal.reset = PIN_LCD_RST; } else //BW I2C { u8g2_esp32_hal.sda = PIN_I2C_SDA; u8g2_esp32_hal.scl = PIN_I2C_SCL; u8g2_esp32_hal.reset = PIN_I2C_RST; } u8g2_esp32_hal_init(u8g2_esp32_hal);

if (getRotat())
    rotat = U8G2_R2;
else
    rotat = U8G2_R0;

switch (*lcd_type){
case LCD_I2C_SH1106:
    u8g2_Setup_sh1106_i2c_128x64_noname_f(
        &u8g2,
        rotat,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
    break;
case LCD_I2C_SSD1306NN:
    u8g2_Setup_ssd1306_i2c_128x64_noname_f(
        &u8g2,
        rotat,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
    break;      
case LCD_I2C_SSD1306:
    u8g2_Setup_ssd1306_i2c_128x64_vcomh0_f(
        &u8g2,
        rotat,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
    break;      
case LCD_I2C_SSD1309:   
    u8g2_Setup_ssd1309_i2c_128x64_noname2_f(
        &u8g2,
        rotat,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
    break;  
case LCD_I2C_SSD1325:   
    u8g2_Setup_ssd1325_i2c_nhd_128x64_f(
        &u8g2,
        rotat,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure

    break;  
case LCD_I2C_SSD1309NN: 
    u8g2_Setup_ssd1309_i2c_128x64_noname0_f(
        &u8g2,
        rotat,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
    break;      
case LCD_I2C_SSD1306UN:
    u8g2_Setup_ssd1306_i2c_128x32_univision_f(
        &u8g2,
        rotat,
        u8g2_esp32_i2c_byte_cb,
        u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
    break;

//B/W spi case LCD_SPI_SSD1306NN: u8g2_Setup_ssd1306_128x64_noname_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_SSD1306:
u8g2_Setup_ssd1306_128x32_univision_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_SSD1309:
u8g2_Setup_ssd1309_128x64_noname2_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_SSD1309NN: u8g2_Setup_ssd1309_128x64_noname0_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_ST7565_ZOLEN:
u8g2_Setup_st7565_zolen_128x64_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_SSD1322_NHD:
u8g2_Setup_ssd1322_nhd_256x64_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_IL3820_V2: //E Paper u8g2_Setup_il3820_v2_296x128_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_SSD1607: //E Paper u8g2_Setup_ssd1607_200x200_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_LS013B7DH03:
u8g2_Setup_ls013b7dh03_128x128_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break;
case LCD_SPI_ST7920:
u8g2_Setup_st7920_s_128x64_f( &u8g2, rotat, u8g2_esp32_spi_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure
break; default: ESP_LOGE(TAG,"Unknown lcd lcd_type %d. Fall back to type 0",lcd_type); lcd_type = 0; u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT; u8g2_esp32_hal.sda = PIN_I2C_SDA; u8g2_esp32_hal.scl = PIN_I2C_SCL; u8g2_esp32_hal_init(u8g2_esp32_hal); u8g2_Setup_sh1106_128x64_noname_f( &u8g2, rotat, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); // init u8g2 structure }

    ESP_LOGD(TAG,"lcd init BW type: %d",*lcd_type);
    if (*lcd_type < LCD_SPI) u8x8_SetI2CAddress(&u8g2.u8x8,0x78);
    u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
    u8g2_SetPowerSave(&u8g2, 0); // wake up display
    u8g2_ClearBuffer(&u8g2);
    u8g2_ClearDisplay(&u8g2);
    yy = u8g2.height;
    x  = u8g2.width;
    z = 0;
    u8g2_SetFontPosTop(&u8g2);
    setfont8(text);
    y = getFontLineSpacing();
    if (yy>= logo_height)
         u8g2_DrawXBM( &u8g2,x/2-logo_width/2, yy/2-logo_height/2, logo_width, logo_height, logo_bits);
    else u8g2_DrawXBM( &u8g2,x/2-logo_width/2, 0, logo_width, logo_height, logo_bits);
    u8g2_SendBuffer(&u8g2);
    printf("X: %d, YY: %d, Y: %d\n",x,yy,y);
    vTaskDelay(100);
    z = 0;  

}

`

olikraus commented 6 years ago

hmmm... thats too much. Let me ask differently. Can you provide a small piece of complete code, which demonstrates the problem?

karawin commented 6 years ago

I don't have an arduino installed with u8g2 but it may be something like

include

include "u8g2.h"

int main() {

char str1[100]; char str2[100];

unsigned int len1,len2;

strcpy(str1,"Супердискотека 90х"); strcpy(str2,"Virgin Radio New");

u8g2_t u8g2; u8g2_Begin(&u8g2);

u8g2_SetFont(&u8g2, u8g2_font_6x13_t_cyrillic);

len1 = u8g2_GetUTF8Width(&u8g2,str1); len2 = u8g2_GetUTF8Width(&u8g2,str2);

printf("len1: %d, str1: %s\n",len1,str1); printf("len2: %d, str2: %s\n",len2,str2);

return 0;

}

olikraus commented 6 years ago

It works as expected. The output is:

len1: 107, str1: Супердискотека 90х
len2: 95, str2: Virgin Radio New

issue693

Code is here: https://github.com/olikraus/u8g2/blob/master/sys/sdl/issue693/main.c#L26

karawin commented 6 years ago

Ok thanks. I think i made a beginner bug in the logic of the code. Thanks for your help and sorry.

olikraus commented 6 years ago

no problem

karawin commented 6 years ago

I made a set of fonts with latin and cyrillic all in one bult with bdfconv.exe -v -f 1 -m "$20-$ff,$a0-$ff,$a0-$17F,$0400-$045f" ...... at https://github.com/karawin/Ka-Radio32/blob/master/components/u8g2/csrc/u8g2_karadio32_fonts.c and integrated in https://github.com/karawin/Ka-Radio32/blob/master/components/u8g2/csrc/u8g2.h

Thanks for your work. Is ucglib utf8 planned ?

karawin commented 6 years ago

Hum bdfconv.exe -v -f 1 -m "$20-$7f,$a0-$17F,$0400-$045f" ......

olikraus commented 6 years ago

There is a utf8 add on lib for the adafruit gfx lib for TFT displays.

karawin commented 6 years ago

May be;-) but i wrote hal for your libs. Both in one code with only one configuration parameter to choose the type of lcd. Thanks JP