人间熙攘,好久不见

vuePress-theme-reco Magic    2017 - 2023
人间熙攘,好久不见 人间熙攘,好久不见

Choose mode

  • dark
  • auto
  • light
Home
Category
  • tools
  • Zsh
  • iTerm2
  • Front-end
  • 版本控制-Git
  • Rust
  • skia-safe
  • 第三方对接
  • MQTT
  • Powershell
  • python
  • MD5
  • SHA1
  • wsl2
Tags
TimeLine
GitHub
  • Github (opens new window)
  • Before (opens new window)
author-avatar

Magic

23

文章

15

标签

Home
Category
  • tools
  • Zsh
  • iTerm2
  • Front-end
  • 版本控制-Git
  • Rust
  • skia-safe
  • 第三方对接
  • MQTT
  • Powershell
  • python
  • MD5
  • SHA1
  • wsl2
Tags
TimeLine
GitHub
  • Github (opens new window)
  • Before (opens new window)

skia-safe 文字段落合成:初探

vuePress-theme-reco Magic    2017 - 2023

skia-safe 文字段落合成:初探

Magic 2021-12-23 Rust

# 背景

目前字体生成服务是由后端生成,但是之前的图片还有用户定制图已经切换为使用 rust 开发的图像快照服务,快照服务依赖于 rust-skia (opens new window),最近想要支持 文字段落生成,最好是可以自动排版,所以看到了 ParagraphBuilder 这个api,但是找文档没有发现关于这个api的任何线索 文档地址 (opens new window),话不多说,上代码 😄

# ParagraphBuilder 例子

因为画文字或者图案也是跟前端一样基于 Canvas 来实现的,所以我们基于 SkCanvas 封装了 Canvas 库来在项目中使用。

在同一个项目使用多个需要自己实现的库都是要基于 rust 的 workspace 哈哈哈哈哈。

可以在 src 同级目录中 新建 examples 文件夹,然后新建 paragraph.rs 文件,通过 cargo run --example 文件名 来先熟悉一下 对应库的 使用。

  • 先来个 examples











 
 
 
 






use std::fs::{ File, read };
use std::io::Write;
use canvas::{
  Canvas, Color, Point, textlayout, EncodedImageFormat, FontMgr,
};

fn main() {
  ...
  let mut paragraph_builder = textlayout::ParagraphBuilder::new(&paragraph_style, font_collection);
  paragraph_builder.push_style(&text_style);
  paragraph_builder.add_text("我是测试");
  // 画到画布上去
  let mut paragraph = paragraph_builder.build();
  paragraph.layout(200.0);
  ctx.with_canvas(|can| {
    paragraph.paint(can, Point::new(0.0, 0.0));
    can.save();
  });
  ...
}

其中关键方法是通过查看源码才知道的 哈哈哈哈哈

  • text_style: 文字样式

    let mut text_style = textlayout::TextStyle::new();
    text_style
      .set_color(Color::RED)
      .set_font_size(20.6)
      .set_font_families(&["HYMiaoHunTiW"]) // set_font_families 首先要确保 font_collection 有这个字体,否则设置不成功
      .set_letter_spacing(100.2);
      // .set_word_spacing(1000000000.0); 这个设置不起作用
    
  • paragraph_style: 段落样式

    let mut paragraph_style = textlayout::ParagraphStyle::new();
    paragraph_style.set_text_align(textlayout::TextAlign::Center);
    paragraph_style.set_text_direction(textlayout::TextDirection::RTL);
    
  • font_collection: 字体集合

    let mut font_collection = textlayout::FontCollection::new();
    let font_mgr = FontMgr::new();
    font_collection.set_default_font_manager(font_mgr, None);
    if let Some(font_typeface_in) = font_typeface.clone() {
        let mut assets = textlayout::TypefaceFontProvider::new();
        assets.register_typeface(font_typeface_in, Some(text_attr.font_family.to_owned()));
        font_collection.set_asset_font_manager(Some(assets.into()));
    }
    

# 怎么设置 横纵排列呢?

  • 关键在于 paragraph.layout 这个,这个是设置 布局 width 的,只有通过设置这个才能决定横纵排列

那怎么拿到 ParagraphBuilder 最终产生的段落大小呢?必须在 设置完 paragraph.layout 之后,才能通过 paragraph.longest_line()、 paragraph.height() 拿到宽高,代码如下:








 
 
 







...
let mut paragraph = paragraph_builder.build();

let mut layout_width = INFINITY;
if text_attr.font_layout == FontLayout::Vertical {
    layout_width = text_attr.font_size;
}
paragraph.layout(layout_width);
let img_dims = (paragraph.longest_line(), paragraph.height());
let mut canvas = Canvas::new(img_dims.0 as i32, img_dims.1 as i32);
let ctx = canvas.get_context();
ctx.with_canvas(|can| {
    paragraph.paint(can, Point::new(0.0, 0.0));
    can.save();
});'
...

# 如果是 两列布局呢?

  • 目前不知道怎么设置 两列布局,暂时想到的想法是 再次 新建 ParagraphBuilder,然后在 画布 上绘制,相当于 按列 分割,有几列就新建几个,然后再依次绘制到画布上。。。

参考:

  • skia 文档 (opens new window)
  • rust-skia (opens new window)
  • skia-canvas (opens new window)
欢迎来到 人间熙攘,好久不见
看板娘