Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

awtk中如何实现这种黑边白底的字体? #907

Open
Tracker647 opened this issue Oct 15, 2024 · 16 comments
Open

awtk中如何实现这种黑边白底的字体? #907

Tracker647 opened this issue Oct 15, 2024 · 16 comments

Comments

@Tracker647
Copy link

image
像这样

@xianjimli
Copy link
Member

这个设置一下背景颜色和字体颜色就可以吧。

@Tracker647
Copy link
Author

主要是字体黑边框,光设置字体颜色只有纯色,黑边框都是针对控件的,不知道有没有针对字体的,看Qt上是用画布实现,不知道在awtk上有没有类似的方法。
image

@xianjimli
Copy link
Member

没看太明白

@Tracker647
Copy link
Author

这个设置一下背景颜色和字体颜色就可以吧。

有直接的设置案例吗?或者只能用画布代码实现?

@Tracker647
Copy link
Author

没看太明白

就是字体的黑边,有什么方法实现吗?

@Tracker647
Copy link
Author

不想用图片值,图片值的话英文字母无法覆盖。

@xianjimli
Copy link
Member

不知道这样行不:先画一个大的作为背景,再画个小的。

@Tracker647
Copy link
Author

不行,并不好对上。
image

@xianjimli
Copy link
Member

不想用图片值,图片值的话英文字母无法覆盖。
可以用图片值,图片值可以显示英文字符,但是不能显示中文字符。
比如你要显示:11.8v/36.0°C
把它转换成: 11.8v/36.0c 作为 format设置进去,value不会生效。如果图片的前缀为num_,最终对应的图片为:

  [0] = "num_1", [1] = "num_1", [2] = "num_dot", [3] = "num_8", [4] = "num_v", [5] = "num_slash", [6] = "num_3", [7] = "num_6", [8] = "num_dot", [9] = "num_0", [10] = "num_c",

num_c对应的图片显示成 °C即可。

注意需要把:IMAGE_VALUE_MAX_CHAR_NR定义大一点,目前为8,上面的情况不够用。

@Tracker647
Copy link
Author

问了老板,这个用freetype实现,写了个例子显示成功,然后看awtk里面有个font_get_glyph正好能和freetype的FT_Load_Char对标,参考了下如何绘制旋转文字写了个控件例子,但是显示起来效果不行,我不清楚哪里的问题?
code:


static bitmap_t* draw_border_text_to_bitmap(widget_t *widget, canvas_t* canvas, wchar_t* str) {
 
  border_text_t* border_text = BORDER_TEXT(widget);
  style_t *style = widget->astyle;
  color_t text_color = color_init(255, 255, 255, 255);  
  color_t border_color = color_init(0, 0, 0, 255);
  
  glyph_t glyph;
  uint32_t x = 0, y = 0, i = 0, img_w = 0, h = 0, ox = 0;
  font_vmetrics_t vm;
  uint32_t* image_data = NULL;
  uint32_t baseline = 0;
  bitmap_t* bitmap = NULL;
  uint32_t font_size = canvas->font_size;
  font_manager_t* fm = canvas->font_manager;
  font_t* font = font_manager_get_font(fm, canvas->font_name, font_size);
  return_value_if_fail(font != NULL, NULL);

  vm = font_get_vmetrics(font, font_size);
  h = vm.ascent - vm.descent;
  return_value_if_fail(h > 0, NULL);

  baseline = vm.ascent;
  for (i = 0; str[i]; i++) {
    return_value_if_fail(font_get_glyph(font, str[i], font_size, &glyph) == RET_OK, NULL);
    img_w += glyph.advance + 1;
  }

  bitmap = bitmap_create_ex(img_w, h, 0, BITMAP_FMT_RGBA8888);
  return_value_if_fail(bitmap != NULL, NULL);

  image_data = (uint32_t*)bitmap_lock_buffer_for_write(bitmap);
  memset(image_data, 0x00, img_w * h * 4);

  int border_size = 2;

  for (i = 0; str[i]; i++) {
    return_value_if_fail(font_get_glyph(font, str[i], font_size, &glyph) == RET_OK, NULL);
    int char_x = ox + glyph.x;
    int char_y = baseline + glyph.y;

    //绘制字体边框
    for(int bx = -border_size; bx <= border_size; ++bx){
      for(int by = -border_size; by <= border_size; ++by){
          if (bx == 0 && by == 0) continue; // 跳过中心点

          for (y = 0; y < glyph.h; y++) {
            for (x = 0; x < glyph.w; x++) {
              int32_t img_x = char_x + x + bx;
              int32_t img_y = char_y + y + by;

              uint32_t* pixel = image_data + img_y * img_w + img_x;
              if(img_x >= 0 && img_x < bitmap->w && img_y >= 0 && img_y < bitmap->h){
                const uint8_t* grey = glyph.data + y * glyph.w + x;
                border_color.rgba.a = *grey;
                *pixel = border_color.color;
              }            
            }
          }
      }
    }

    // 绘制字体
    for (y = 0; y < glyph.h; y++) {
      for (x = 0; x < glyph.w; x++) {
        int32_t img_x = char_x + x;
        int32_t img_y = char_y + y;

        uint32_t* pixel = image_data + img_y * img_w + img_x;
        const uint8_t* grey = glyph.data + y * glyph.w + x;

        text_color.rgba.a = *grey;
        *pixel = text_color.color;
      }
    }
    ox += glyph.advance + 1;
  }
  bitmap_unlock_buffer(bitmap);
  bitmap->flags |= BITMAP_FLAG_CHANGED;

  return bitmap;
}

static ret_t border_text_on_paint_self(widget_t* widget, canvas_t* c) {
  border_text_t* border_text = BORDER_TEXT(widget);
  style_t *style = widget->astyle;
  int font_size = style_get_int(style, STYLE_ID_FONT_SIZE, 25);
  color_t text_color = color_init(255, 255, 255, 255);  
  color_t border_color = color_init(0, 0, 0, 255);
  
  canvas_set_text_align(c, ALIGN_H_CENTER, ALIGN_V_MIDDLE);
  canvas_set_text_color(c, text_color);
  rect_t r = rect_init(0, 0, widget->w, widget->h);
  
  canvas_set_font(c, "default", font_size);
  bitmap_t *bm = draw_border_text_to_bitmap(widget, c, L"Hello World");
  rect_t dst = {0, 0, widget->w, widget->h};
  rect_t src = {0, 0, bm->w, bm->h};
  canvas_draw_image(c, bm, &src, &dst);
  bitmap_destroy(bm);
  return RET_OK;
}

@Tracker647
Copy link
Author

Tracker647 commented Oct 27, 2024

freetype的例子:
my_freetype_show_font.txt

@Tracker647
Copy link
Author

freetype显示效果和awtk对比:
image

image

@Tracker647
Copy link
Author

问了老板,这个用freetype实现,写了个例子显示成功,然后看awtk里面有个font_get_glyph正好能和freetype的FT_Load_Char对标,参考了下如何绘制旋转文字写了个控件例子,但是显示起来效果不行,我不清楚绘制边框的那段代码是哪里的问题? code:


static bitmap_t* draw_border_text_to_bitmap(widget_t *widget, canvas_t* canvas, wchar_t* str) {
 
  border_text_t* border_text = BORDER_TEXT(widget);
  style_t *style = widget->astyle;
  color_t text_color = color_init(255, 255, 255, 255);  
  color_t border_color = color_init(0, 0, 0, 255);
  
  glyph_t glyph;
  uint32_t x = 0, y = 0, i = 0, img_w = 0, h = 0, ox = 0;
  font_vmetrics_t vm;
  uint32_t* image_data = NULL;
  uint32_t baseline = 0;
  bitmap_t* bitmap = NULL;
  uint32_t font_size = canvas->font_size;
  font_manager_t* fm = canvas->font_manager;
  font_t* font = font_manager_get_font(fm, canvas->font_name, font_size);
  return_value_if_fail(font != NULL, NULL);

  vm = font_get_vmetrics(font, font_size);
  h = vm.ascent - vm.descent;
  return_value_if_fail(h > 0, NULL);

  baseline = vm.ascent;
  for (i = 0; str[i]; i++) {
    return_value_if_fail(font_get_glyph(font, str[i], font_size, &glyph) == RET_OK, NULL);
    img_w += glyph.advance + 1;
  }

  bitmap = bitmap_create_ex(img_w, h, 0, BITMAP_FMT_RGBA8888);
  return_value_if_fail(bitmap != NULL, NULL);

  image_data = (uint32_t*)bitmap_lock_buffer_for_write(bitmap);
  memset(image_data, 0x00, img_w * h * 4);

  int border_size = 2;

  for (i = 0; str[i]; i++) {
    return_value_if_fail(font_get_glyph(font, str[i], font_size, &glyph) == RET_OK, NULL);
    int char_x = ox + glyph.x;
    int char_y = baseline + glyph.y;

    //绘制字体边框
    for(int bx = -border_size; bx <= border_size; ++bx){
      for(int by = -border_size; by <= border_size; ++by){
          if (bx == 0 && by == 0) continue; // 跳过中心点

          for (y = 0; y < glyph.h; y++) {
            for (x = 0; x < glyph.w; x++) {
              int32_t img_x = char_x + x + bx;
              int32_t img_y = char_y + y + by;

              uint32_t* pixel = image_data + img_y * img_w + img_x;
              if(img_x >= 0 && img_x < bitmap->w && img_y >= 0 && img_y < bitmap->h){
                const uint8_t* grey = glyph.data + y * glyph.w + x;
                border_color.rgba.a = *grey;
                *pixel = border_color.color;
              }            
            }
          }
      }
    }

    // 绘制字体
    for (y = 0; y < glyph.h; y++) {
      for (x = 0; x < glyph.w; x++) {
        int32_t img_x = char_x + x;
        int32_t img_y = char_y + y;

        uint32_t* pixel = image_data + img_y * img_w + img_x;
        const uint8_t* grey = glyph.data + y * glyph.w + x;

        text_color.rgba.a = *grey;
        *pixel = text_color.color;
      }
    }
    ox += glyph.advance + 1;
  }
  bitmap_unlock_buffer(bitmap);
  bitmap->flags |= BITMAP_FLAG_CHANGED;

  return bitmap;
}

static ret_t border_text_on_paint_self(widget_t* widget, canvas_t* c) {
  border_text_t* border_text = BORDER_TEXT(widget);
  style_t *style = widget->astyle;
  int font_size = style_get_int(style, STYLE_ID_FONT_SIZE, 25);
  color_t text_color = color_init(255, 255, 255, 255);  
  color_t border_color = color_init(0, 0, 0, 255);
  
  canvas_set_text_align(c, ALIGN_H_CENTER, ALIGN_V_MIDDLE);
  canvas_set_text_color(c, text_color);
  rect_t r = rect_init(0, 0, widget->w, widget->h);
  
  canvas_set_font(c, "default", font_size);
  bitmap_t *bm = draw_border_text_to_bitmap(widget, c, L"Hello World");
  rect_t dst = {0, 0, widget->w, widget->h};
  rect_t src = {0, 0, bm->w, bm->h};
  canvas_draw_image(c, bm, &src, &dst);
  bitmap_destroy(bm);
  return RET_OK;
}

@Tracker647
Copy link
Author

Tracker647 commented Oct 27, 2024

OK, 查了点文章,字体从主体到边框是有灰度的过渡的,a值不一定是255,可以通过看a值是不是255来区分字体或者边框,修改了下,总算能看了,就是锯齿明显,勉强用了。

    //绘制字体边框
   //https://blog.codingnow.com/2013/09/edge_font.html
    for(int bx = -border_size; bx <= border_size; ++bx){
      for(int by = -border_size; by <= border_size; ++by){
        for (y = 0; y < glyph.h; y++) {
          for (x = 0; x < glyph.w; x++) {
            int img_x = char_x + bx + x;
            int img_y = char_y + by + y;

            uint32_t* pixel = image_data + img_y * img_w + img_x;
            const uint8_t* grey = glyph.data + y * glyph.w + x;
            if(*grey > 0){
              border_color.rgba.a = 255;
              *pixel = border_color.color;
            }
          }
        }
      }
    }

    

    // 绘制字体
    for (y = 0; y < glyph.h; y++) {
      for (x = 0; x < glyph.w; x++) {
        int img_x = char_x + x;
        int img_y = char_y + y;

        uint32_t* pixel = image_data + img_y * img_w + img_x; 
        const uint8_t* grey = glyph.data + y * glyph.w + x;

        if(*grey > 0){
          text_color.rgba.a = 255;
          *pixel = text_color.color;
        }
      }
    }

image

@Tracker647
Copy link
Author

Tracker647 commented Oct 27, 2024

最简单暴力方法GET

static ret_t border_text_on_paint_self(widget_t* widget, canvas_t* c) {
  border_text_t* border_text = BORDER_TEXT(widget);
  style_t *style = widget->astyle;
  int font_size = style_get_int(style, STYLE_ID_FONT_SIZE, 25);
  const char *font_name = style_get_str(style, STYLE_ID_FONT_NAME, "default");
  color_t text_color = color_init(255, 255, 255, 255);  
  color_t border_color = color_init(0, 0, 0, 255);
  
  canvas_set_text_align(c, ALIGN_H_CENTER, ALIGN_V_MIDDLE);
  
  canvas_set_font(c, font_name, font_size);
  canvas_set_text_color(c, border_color);
  for(int j = 0; j < 3; j++){
    for(int i = 0; i < 3; i++){
      rect_t r = rect_init(i, j, widget->w, widget->h);
      canvas_draw_text_in_rect(c, widget->text.str, widget->text.size, &r);
    }
  }

  canvas_set_text_color(c, text_color);
  rect_t r = rect_init(1, 1, widget->w, widget->h);
  canvas_draw_text_in_rect(c, widget->text.str, widget->text.size, &r);
  return RET_OK;
}

直接canvas_draw_text_in_rect重复画几遍就行了,结果发现出来的效果边框还比自己用控件拼的更整齐??奇妙。
image

@xianjimli
Copy link
Member

666

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants