zlgopen / awtk-linux-fb

awtk port for linux framebuffer
108 stars 49 forks source link

如何快速将文字转换成图片. #11

Closed V1ki closed 5 years ago

V1ki commented 5 years ago

如何快速将文字转换成图片? 库中是否有相应的工具函数?

xianjimli commented 5 years ago

这样做的目的是什么?

V1ki commented 5 years ago

在海思平台下录像,需要做OSD ,想将文字转换成 图片数据后,然后画在region 中.

V1ki commented 5 years ago

这样做的目的是什么?

另外 我看awtk 中有canvas ,最初的设想是画到canvas 中,然后将canvas 转换成 位图数据,但是发现 canvas 好像没有此类方法,所以看有没有其他的快捷的方法.

V1ki commented 5 years ago

这样做的目的是什么?

在浏览canvas 的代码中发现可以通过lcd_mem 来创建lcd,并初始化canvas,然后将文字画到canvas 中,最后将lcd 中的buff写入到region 中. 不知这种方法是否可行,我先测试一下.

V1ki commented 5 years ago

这样做的目的是什么?

 canvas_t canvas;
  font_manager_t font_manager;
  font_manager_init(&font_manager, NULL);

  uint8_t* region_datas = (uint8_t*)(stBitmap.pData);
  lcd_t* lcd = lcd_mem_rgba8888_create_single_fb(64, 64, region_datas);
  canvas_t* c = canvas_init(&canvas, lcd, &font_manager);

  ret_t ret = RET_FAIL;
  color_t fill_color = color_init(0xff, 0xff, 0xff, 0xff);

  rect_t r = rect_init(0, 0, 64, 64);
  canvas_begin_frame(c, &r, LCD_DRAW_NORMAL);

  ret = canvas_set_fill_color(c, fill_color);
  printf("canvas_set_fill_color:%d\n", ret);
  ret = canvas_fill_rect(c, 0, 0, 64, 64);
  printf("canvas_fill_rect:%d\n", ret);

  canvas_draw_text(c, L"Hello AWTK", 10, 20, 20);
  // printf("canvas_draw_text:%d\n", ret);

  color_t color = lcd_get_point_color(c->lcd, 10, 10);
  printf("color:%#x -- fill_color:%#x\n", color.color, fill_color.color);

  canvas_end_frame(&canvas);  

单独显示颜色已经可以,但是 在draw_text的时候,出现了 Segmentation fault 了.

V1ki commented 5 years ago

发现崩溃出现在:

static ret_t canvas_draw_text_impl(canvas_t* c, const wchar_t* str, uint32_t nr, xy_t x, xy_t y) {
  glyph_t g;
  uint32_t i = 0;
  xy_t left = x;

  printf("111111111111111111111111\n");
  uint32_t start_time = time_now_ms();

  printf("2222222222222222222222\n");
  font_size_t font_size = c->font_size;

  y -= font_size * 1 / 3;
  for (i = 0; i < nr; i++) {
    wchar_t chr = str[i];
    if (chr == ' ') {
      x += 4;
    } else if (chr == '\r') {
      if (str[i + 1] != '\n') {
        y += font_size;
        x = left;
      }
    } else if (chr == '\r') {
      y += font_size;
      x = left;
    } else if (font_get_glyph(c->font, chr, c->font_size, &g) == RET_OK) {
      xy_t xx = x + g.x;
      xy_t yy = y + font_size + g.y;

      canvas_draw_glyph(c, &g, xx, yy);
      x += g.advance + 1;
    } else {
      x += 4;
    }
  }

  y = time_now_ms() - start_time;

  return RET_OK;
}

1 和2 中间的 time_now_ms 里了 . 下面的是报错日志:

canvas_set_fill_color:0
canvas_fill_rect:0
111111111111111111111111
Segmentation fault
V1ki commented 5 years ago

大概是因为我没有在系统初始化之前继续调用?

xianjimli commented 5 years ago

使用font manager全局对象试试:

canvas_t* c = canvas_init(&canvas, lcd, font_manager());
V1ki commented 5 years ago

使用font manager全局对象试试:

canvas_t* c = canvas_init(&canvas, lcd, font_manager());

目前我将update 的方法放在tk_thread 中进行执行.

     tk_thread_t* thread = tk_thread_create(osd_thread_entry, NULL);
   tk_thread_start(thread);

    canvas_t canvas;
    // font_manager_t font_manager;
    // font_manager_init(&font_manager, NULL);

    uint8_t* region_datas = (uint8_t*)(stBitmap.pData);
    lcd_t* lcd = lcd_mem_rgba8888_create_single_fb(64, 64, region_datas);
    canvas_t* c = canvas_init(&canvas, lcd, font_manager());

    ret_t ret = RET_FAIL;
    color_t fill_color = color_init(0x0, 0x0, 0x0, 0xff);

    rect_t r = rect_init(0, 0, 64, 64);
    canvas_begin_frame(c, &r, LCD_DRAW_NORMAL);

    ret = canvas_set_fill_color(c, fill_color);
    printf("canvas_set_fill_color:%d\n", ret);
    ret = canvas_fill_rect(c, 0, 0, 64, 64);
    printf("canvas_fill_rect:%d\n", ret);

    canvas_draw_text(c, L"Hello AWTK", 10, 20, 20);
    // printf("canvas_draw_text:%d\n", ret);

    color_t color = lcd_get_point_color(c->lcd, 10, 10);
    printf("color:%#x -- fill_color:%#x\n", color.color, fill_color.color);

    canvas_end_frame(&canvas);

使用的是font manager 的全局对象,但是还是会出现 Segmentation fault ,日志如下:

window main open
111111111111111111111111
2222222222222222222222
111111111111111111111111
HI_MPI_RGN_GetCanvasInfo Success! canvas.size:(64,64)  u32Stride:128-- 
canvas_set_fill_color:0
canvas_fill_rect:0
111111111111111111111111
2222222222222222222222
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
font_get_glyph:26 f != NULL && f->get_glyph != NULL && g != NULL
color:0xff000000 -- fill_color:0xff000000
HI_MPI_RGN_UpdateCanvas Success! 
2222222222222222222222
111111111111111111111111
2222222222222222222222
111111111111111111111111
2222222222222222222222
111111111111111111111111
2222222222222222222222
111111111111111111111111
2222222222222222222222
111111111111111111111111
2222222222222222222222
111111111111111111111111
2222222222222222222222
111111111111111111111111
2222222222222222222222
111111111111111111111111
2222222222222222222222
111111111111111111111111
2222222222222222222222
Segmentation fault
V1ki commented 5 years ago

感觉很像是tk_thread 执行完成后出的错误.

V1ki commented 5 years ago

感觉很像是tk_thread 执行完成后出的错误.

排查了一下,并不是 tk_thread 执行完成的问题, 那 是 font 的问题 ?

xianjimli commented 5 years ago

设置字体之后,运行正常。

canvas_set_font(c, NULL, 18);
V1ki commented 5 years ago

设置字体之后,运行正常。

canvas_set_font(c, NULL, 18);

这个我之前有试过,但是还是不行,依旧会出现 Segmentation fault

V1ki commented 5 years ago

设置字体之后,运行正常。

canvas_set_font(c, NULL, 18);

我将之前加上的 111,222给删除了,另外 在font中加上了ch : %c 的打印

ret_t font_get_glyph(font_t* f, wchar_t chr, font_size_t font_size, glyph_t* g) {
  printf("chr:%c\n",chr);
  return_value_if_fail(f != NULL && f->get_glyph != NULL && g != NULL, RET_BAD_PARAMS);

  return f->get_glyph(f, chr, font_size, g);
}

报错日志如下:

canvas_set_fill_color:0
canvas_fill_rect:0
chr:H
Segmentation fault

实现代码如下:


void* osd_thread_entry(void* args) {
  // while (TRUE) {
    s32Ret = HI_MPI_RGN_GetAttr(Handle, &stRgnAttrSet);
    if (HI_SUCCESS != s32Ret) {
      printf("HI_MPI_RGN_GetAttr failed! s32Ret: 0x%x.\n", s32Ret);
      return;
    }

    s32Ret = HI_MPI_RGN_GetCanvasInfo(Handle, &stCanvasInfo);
    if (HI_SUCCESS != s32Ret) {
      printf("HI_MPI_RGN_GetCanvasInfo failed! s32Ret: 0x%x.\n", s32Ret);
      return;
    }
    printf("HI_MPI_RGN_GetCanvasInfo Success! canvas.size:(%d,%d)  u32Stride:%d-- \n",
           stCanvasInfo.stSize.u32Width, stCanvasInfo.stSize.u32Height, stCanvasInfo.u32Stride);

    stBitmap.pData = (HI_VOID*)stCanvasInfo.u32VirtAddr;
    stSize.u32Width = stCanvasInfo.stSize.u32Width;
    stSize.u32Height = stCanvasInfo.stSize.u32Height;

    canvas_t canvas;
    // font_manager_t* fontm = font_manager();
    //font_manager_add_font(font_manager(), font_dummy_0("demo0", 10));
    // font_manager_init(&font_manager, NULL);

    uint8_t* region_datas = (uint8_t*)(stBitmap.pData);
    lcd_t* lcd = lcd_mem_rgba8888_create_single_fb(64, 64, region_datas);

    canvas_t* c = canvas_init(&canvas, lcd, font_manager());

    ret_t ret = RET_FAIL;
    color_t fill_color = color_init(0x0, 0x0, 0x0, 0xff);

    rect_t r = rect_init(0, 0, 64, 64);
    canvas_begin_frame(c, &r, LCD_DRAW_NORMAL);
    canvas_set_font(c, NULL, 20);
    color_t tc = color_init(0, 0, 0, 0xff);
    canvas_set_text_color(c, tc);
    ret = canvas_set_fill_color(c, fill_color);
    printf("canvas_set_fill_color:%d\n", ret);
    ret = canvas_fill_rect(c, 0, 0, 64, 64);
    printf("canvas_fill_rect:%d\n", ret);

    canvas_draw_text(c, L"Hello AWTK", 10, 20, 20);
    // printf("canvas_draw_text:%d\n", ret);

    color_t color = lcd_get_point_color(c->lcd, 10, 10);
    printf("color:%#x -- fill_color:%#x\n", color.color, fill_color.color);

    canvas_end_frame(&canvas);
    // font_manager_deinit(&font_manager);
    //lcd_destroy(lcd);

    s32Ret = HI_MPI_RGN_UpdateCanvas(Handle);
    if (HI_SUCCESS != s32Ret) {
      printf("HI_MPI_RGN_UpdateCanvas failed! s32Ret: 0x%x.\n", s32Ret);
      return;
    }

    printf("HI_MPI_RGN_UpdateCanvas Success! \n");

    return NULL ;
  // }
}
#ifdef USE_GUI_MAIN
int gui_app_start(int lcd_w, int lcd_h) {
  tk_init(lcd_w, lcd_h, APP_MOBILE, NULL, NULL);
#else

#ifdef WIN32
#include <windows.h>
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) {
#else
int main(void) {
#endif

  int lcd_w = 800;
  int lcd_h = 480;
#if defined(LCD_W) && defined(LCD_H)
  lcd_w = LCD_W;
  lcd_h = LCD_H;
#endif

  lcd_w = 720;
  lcd_h = 576;
  Hi_OPENFB();
#ifdef WITH_FS_RES
  char res_root[MAX_PATH + 1];
  char app_root[MAX_PATH + 1];
  path_app_root(app_root);
  memset(res_root, 0x00, sizeof(res_root));
  path_build(res_root, MAX_PATH, app_root, "res", NULL);

  LOG("res_root:%s lcd_w:%d lcd_h:%d\n", res_root, lcd_w, lcd_h);

  tk_init(lcd_w, lcd_h, APP_MOBILE, NULL, res_root);
#else
  tk_init(lcd_w, lcd_h, APP_MOBILE, NULL, NULL);
#endif

#endif

//#define WITH_LCD_PORTRAIT 1
#if defined(USE_GUI_MAIN) && defined(WITH_LCD_PORTRAIT)
  if (lcd_w > lcd_h) {
    tk_set_lcd_orientation(LCD_ORIENTATION_90);
  }
#endif /*WITH_LCD_PORTRAIT*/

#ifdef WITH_LCD_LANDSCAPE
  if (lcd_w < lcd_h) {
    tk_set_lcd_orientation(LCD_ORIENTATION_90);
  }
#endif /*WITH_LCD_PORTRAIT*/

  /* 初始化资源 */
  assets_init();

  /* 初始化扩展控件 */
  tk_ext_widgets_init();

  /* 打开主屏幕 */
  //application_init();

  //  tk_thread_t* thread = tk_thread_create(venc_thread_entry, NULL);
  //  tk_thread_start(thread);

     tk_thread_t* thread = tk_thread_create(osd_thread_entry, "args");
   tk_thread_start(thread);

  /* 进入awtk事件循环 */
  tk_run();
  return 0;
}
V1ki commented 5 years ago

我在canvas.cfont.c 中加上了一些打印. 报错日志如下:

canvas_set_fill_color:0
canvas_fill_rect:0
start_time:2151426
font_size:18
font_get_glyph font_name:default -- chr:H
Segmentation fault

加的打印如下 .

static ret_t canvas_draw_text_impl(canvas_t* c, const wchar_t* str, uint32_t nr, xy_t x, xy_t y) {
  glyph_t g;
  uint32_t i = 0;
  xy_t left = x;
  uint32_t start_time = time_now_ms();

  printf("start_time:%d\n",start_time);
  font_size_t font_size = c->font_size;

  printf("font_size:%d\n",font_size);

  y -= font_size * 1 / 3;
  for (i = 0; i < nr; i++) {
    wchar_t chr = str[i];
    if (chr == ' ') {
      x += 4;
    } else if (chr == '\r') {
      if (str[i + 1] != '\n') {
        y += font_size;
        x = left;
      }
    } else if (chr == '\r') {
      y += font_size;
      x = left;
    } else if (font_get_glyph(c->font, chr, c->font_size, &g) == RET_OK) {
      xy_t xx = x + g.x;
      xy_t yy = y + font_size + g.y;

     printf("before canvas_draw_glyph:(%d,%d)\n",xx, yy);
      canvas_draw_glyph(c, &g, xx, yy);
      x += g.advance + 1;
    } else {
      x += 4;
    }
  }

  y = time_now_ms() - start_time;

  return RET_OK;
}
ret_t font_get_glyph(font_t* f, wchar_t chr, font_size_t font_size, glyph_t* g) {

  return_value_if_fail(f != NULL && f->get_glyph != NULL && g != NULL, RET_BAD_PARAMS);
  printf("font_get_glyph font_name:%s -- chr:%c\n",f->name,chr);
  return f->get_glyph(f, chr, font_size, g);
}

可以看到 before canvas_draw_glyph 并没有打印出来.

V1ki commented 5 years ago

定位到问题, @xianjimli 日志如下:

canvas_set_fill_color:0
canvas_fill_rect:0
start_time:1525029
font_size:18
font_get_glyph font_name:default -- chr:H
font_stb_get_glyph --  font_name:default -- chr:H
stbtt_ScaleForPixelHeight --  scale:0.006659 -- sf->numGlyphs:100
glyph_cache_lookup --- glyph_t:(-128,94) -- cache->size:0
Segmentation fault

发现问题出在 font_loader_stb.c 中的font_stb_get_glyph 方法里, stbtt_GetCodepointBitmap 的时候出现了该问题,


static ret_t font_stb_get_glyph(font_t* f, wchar_t c, font_size_t font_size, glyph_t* g) {
  int x = 0;
  int y = 0;
  int w = 0;
  int h = 0;
  int lsb = 0;
  int advance = 0;
  printf("font_stb_get_glyph --  font_name:%s -- chr:%c\n",f->name,c);
  font_stb_t* font = (font_stb_t*)f;
  stbtt_fontinfo* sf = &(font->stb_font);
  float scale = stbtt_ScaleForPixelHeight(sf, font_size);

  printf("stbtt_ScaleForPixelHeight --  scale:%f -- sf->numGlyphs:%d\n",scale,sf->numGlyphs);

  if (glyph_cache_lookup(&(font->cache), c, font_size, g) == RET_OK) {
    return RET_OK;
  }

  g->data = stbtt_GetCodepointBitmap(sf, 0, scale, c, &w, &h, &x, &y);

 printf("stbtt_GetCodepointBitmap --  [w,h,x,y] : [%d,%d,%d,%d]\n",w,h,x,y);

  stbtt_GetCodepointHMetrics(sf, c, &advance, &lsb);

  printf("stbtt_GetCodepointHMetrics --  advance:%d -- lsb:%d\n",advance,lsb);

  g->x = x;
  g->y = y;
  g->w = w;
  g->h = h;
  g->advance = advance * scale;

  if (g->data != NULL) {
    glyph_t* gg = glyph_clone(g);
    if (gg != NULL) {

  printf("before glyph_cache_add \n");
      glyph_cache_add(&(font->cache), c, font_size, gg);
    } else {
      STBTT_free(g->data, NULL);
      log_warn("out of memory\n");
      g->data = NULL;
    }
  }

  return g->data != NULL ? RET_OK : RET_NOT_FOUND;
}

应该如何解决.

xianjimli commented 5 years ago

你放到UI线程试一下。

V1ki commented 5 years ago

我直接放在main 中的时候,发现还是会出现, main 中 不是UI线程吗?

xianjimli commented 5 years ago

昨天我放在button的click事件里,测试是正常的。

V1ki commented 5 years ago

准备使用SDL_ttf来完成OSD相关功能了.