惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园_首页
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
ThreatConnect
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 聂微东
H
Help Net Security
T
Threat Research - Cisco Blogs
Blog — PlanetScale
Blog — PlanetScale
A
Arctic Wolf
G
Google Developers Blog
量子位
U
Unit 42
I
InfoQ
V
V2EX
F
Fox-IT International blog
P
Privacy & Cybersecurity Law Blog
V
Visual Studio Blog
J
Java Code Geeks
大猫的无限游戏
大猫的无限游戏
C
CERT Recently Published Vulnerability Notes
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
T
Tailwind CSS Blog
SecWiki News
SecWiki News
Know Your Adversary
Know Your Adversary
MyScale Blog
MyScale Blog
宝玉的分享
宝玉的分享
The Hacker News
The Hacker News
Project Zero
Project Zero
Application and Cybersecurity Blog
Application and Cybersecurity Blog
月光博客
月光博客
Recent Commits to openclaw:main
Recent Commits to openclaw:main
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY
C
Cisco Blogs
I
Intezer
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
Recorded Future
Recorded Future
T
Tenable Blog
W
WeLiveSecurity
腾讯CDC
Stack Overflow Blog
Stack Overflow Blog
T
The Blog of Author Tim Ferriss
www.infosecurity-magazine.com
www.infosecurity-magazine.com
D
Docker
C
Cybersecurity and Infrastructure Security Agency CISA
PCI Perspectives
PCI Perspectives

文章列表

我是如何解决将 c++ 编译成可以在 node.js 中使用的 *.node,中间出现的一大堆问题的(指纹浏览器基石篇) eSIM Plus 爱沙尼亚手机号彻底翻车?“永久有效”悄然变成了一年! 接码平台 SMS-Activate 余额可以转移到新平台使用,截止日期:2026年1月29日 是时候将 hugo-theme-kiwi 主题提交到 themes.gohugo.io 站点上了 Flux2 刚开源就凉了?Z-Image 本地部署狠狠打了个样 声音的未来:Chatterbox —— 用「夸张度旋钮」提升表现力的开源 TTS 向导 还以为那只是换个背景?Qwen-Image-Edit 在 ComfyUI 中能做到更离谱的事 Windows 结合最新版 ComfyUI 部署阿里最新开源的 Qwen-Image 图像大模型 从零样本到跨场景:Seed-VC语音转换技术的革命性突破 大语音模型轻量化革命:MegaTTS3 如何重新定义文本生成语音的技术边界(windows篇) 竞赛级编程大模型OlympicCoder-7B之本地部署(Windows篇) 阿里开源了端到端全模态大模型Qwen-2.5-Omini-7B之本地部署(windows篇) 语音识别之whisper本地部署(实时语音之开篇) 甭管是个人还是企业都能部署的Mistral-Small3.1,远超同级别的模型 文生音乐开源项目DiffRhythm,8G显存本地部署之Windows篇 阿里QwQ-32B本地部署指南:用Ollama轻松运行320亿参数大模型 基于Qwen2.5大模型的Spark-TTS,零样本语音克隆,CPU可运行之本地部署(Windows篇) 智谱开源了文生图CogView4-6B模型,支持中文提示词之本地部署(Windows篇) 基于歌词生成整首歌的开源AI音乐模型,支持中、英、日、韩等多种语言,本地化部署YuE(windows篇) 阿里云开源的文生视频万相 Wan2.1之本地部署Wan2.1-T2V-1.3B模型 互动式开源AI图像编辑神器,Windows11本地部署 MagicQuill 本地部署Qwen2.5-VL-7B-Instruct多模态视觉大模型(Windows篇) 保持角色一致性的绘本生成AI开源项目之Story-Adapter本地部署Windows篇 本地部署 Stable Diffusion 3.5(最新 ComfyUI记录篇) 谁说Win7安装不了Node.js最新版的呢?都2025年,还不更新系统到Win11 vs code远程调试Linux服务器上的php代码 浏览器定制 | Windows11 编译 Chromium 133.0.6885.0(截稿前Chromium最新版之编译篇[一]) 不说是彻底搞懂,至少让你不再惧怕c/c++指针,以及各种奇葩指针变种 解决windows下php8.x及以上版本,在Apache2.4中无法加载CURL扩展的问题 在 Windows8.1 下编译 Chromium (103.0.5060.68 之三) 安装 depot_tools 和 Windows 10 SDK 为在Windows下构建基于 chromium 的浏览器(103.0.5060.68 之二) Windows构建基于 Chromium 的浏览器之环境准备篇安装 Visual Studio(103.0.5060.68 之一) 为什么网站加载速度总是那么不尽如人意呢?(网站优化篇) 海外云服务器安装 Redis 6.2.x (Ubuntu 18.04 记录篇三) 海外云服务器安装 MariaDB 10.6.X (Ubuntu 18.04 记录篇二) 海外云服务器安装 JDK8 (Ubuntu 18.04 记录篇) 虚拟机 Linux 安装 JDK(Vagrant 之二 CentOS7 篇) 怎样快速搭建 Linux 虚拟机呢?(vagrant 篇) 个人站点迁移之gitlab.com pages 绑定自定义域名 不要你掏腰包,就能搭建个人网站之 gitlab.com Pages 托管服务 国内 gitee.com Pages 下线了,致使众多站长纷纷改用其他托管平台 其实,低成本甚至免费的,也是可以搭建个人网站的哦! 腾讯云COS托管静态网站,以及如何解决访问出现了下载网页的情况 错误分析 (Machine Learning 研习十九) 多类别分类器(Machine Learning 研习十八) 使用CSS计数器,在目录名称前加上了序号,让目录看起来更加井然有序 使用 golang 以及 Gin 框架,将上传的图片在不保存至本地的情况下添加水印,并上传至阿里云 OSS 绘制特征曲线-ROC(Machine Learning 研习十七) 网站引入 Prism,使得代码高亮显示,并一键复制代码块 精确率(召回率)的权衡(Machine Learning 研习十六) 对模型性能进行评估(Machine Learning 研习十五) 图像识别之入门案例之数字识别(Machine Learning 研习十四) 微调模型——续(Machine Learning 研习之十三) 微调模型(Machine Learning 研习之十二) 解决 github.com port 443: Timed out 的问题 选择和训练模型(Machine Learning 研习之十一) 回望这风雨飘摇的一年过后,我们终将要整束行囊继续前行 一套由 Hugo 驱动的博客主题 hugo-theme-kiwi 开源啦 机器学习中的 Transformation Pipelines(Machine Learning 研习之十) 特征缩放和转换以及自定义Transformers(Machine Learning 研习之九) 为机器学习算法准备数据(Machine Learning 研习之八) 端到端的机器学习项目之探索数据(Machine Learning 研习之七) 端到端的机器学习项目(Machine Learning 研习之六) 机机器学习的测试和验证(Machine Learning 研习之五) 机器学习的主要挑战和任务(Machine Learning 研习之四) 对于大量数据集的解决方案便是在线学习或是增量学习(Machine Learning 研习之三) 现实生活中机器学习的具体示例(Machine Learning 研习之二) 让机器学习不再是过门不入,带您一起详解机器学习(机器学习 Machine Learning 研习之一) 把握住golang中的template,方能驾驭得了Hugo主题的template 云服务器到期,站点迁移,Nginx配置SSL以备后续只需! 玩以太坊链上项目的必备技能(内联汇编 [inline assembly]-Solidity之旅十八) 玩以太坊链上项目的必备技能(库 [library]-Solidity之旅十七) 玩以太坊链上项目的必备技能(Constant 和 Immutable 状态变量-Solidity之旅十六) 玩以太坊链上项目的必备技能(修改器 [modifier]-Solidity之旅十五) 玩以太坊链上项目的必备技能(错误处理以及异常-Solidity之旅十四) 玩以太坊链上项目的必备技能(函数及其可见性和状态可变性-Solidity之旅十三) 玩以太坊链上项目的必备技能(事件-Solidity之旅十二) 玩以太坊链上项目的必备技能(OOP-接口-Solidity之旅十一) 玩以太坊链上项目的必备技能(OOP-抽象合约-Solidity之旅十) 玩以太坊链上项目的必备技能(OOP-合约继承-Solidity之旅九) 玩以太坊链上项目的必备技能(流程控制-Solidity之旅八) 玩以太坊链上项目的必备技能(单位以及全局变量-Solidity之旅七) 玩以太坊链上项目的必备技能(基本类型转换以及推断-Solidity之旅六) 玩以太坊链上项目的必备技能(变量作用域-Solidity之旅五) 玩以太坊链上项目的必备技能(类型-映射类型-Solidity之旅四) 玩以太坊链上项目的必备技能(类型-引用类型-Solidity之旅三) 花了不到1块5,玩了下全网最火的ChatGPT 玩以太坊链上项目的必备技能(类型-值类型-Solidity之旅二) 玩以太坊链上项目的必备技能(初识智能合约语言-Solidity之旅一) 在构建 Web3 前,需先知道什么是区块链,毕竟 Web3 是基于区块链 Web3 来了,让我们展开双手拥抱它吧! Go 语言中的 Moduels 管理(Let's Go 三十四) Go 语言中的包(Let's Go 三十三) Go 语言中的错误处理(Let's Go 三十二) Go 语言中的带有缓冲 Channel(Let's Go 三十一) Go 语言中的单向 Channel(Let's Go 三十) Go 语言中的 Channel(Let's Go 二十九) Go 语言中的并发编程(Let's Go 二十八) Go 语言中的空接口(Let's Go 二十七) Go 语言中的类型断言(Let's Go 二十六)
canvas绘制文本时,该如何处理首行缩进、自动换行、多内容以省略号结束、竖排的呢?
2024-08-03 · via

实现如标题所示的这些文本效果,在css看来,不就是一两行css属性。然而,对于canvas来讲,要想呈现这样的文字样式,就没css那么轻松简便了。

既然如此,那为何还要使用对文本支持度不友好的canvas来绘制文字呢?而不是采用对文本天然支持的css呢?

canvas 绘制文本的场景

在给为何弃对文本天然支持的 css而不用,拣起了文本支持度不友好的canvas的答复之时。不妨先来看看,究竟是在什么样的场景下,需要用到canvas去绘制文本呢?

常逛商场的,总会不时地看到一些商家为了吸引客流而制作出的一张精美海报;再看艺术展前,也总能在大门看到本次参展的“艺术家”们最为得意的艺术及简介,所绘制的一张海报;去电影院观看的,大都是被该片前期在各大商场及公共场合宣传的那张海报而吸引来的。……

是咯,照这样看来,海报的确可以作为事物的重要途径,虽然海报承载的内容有限,但一张足够优美的海报,总是能把人们的目光给吸引过来的,好比去书店买书,总是会翻到书的背面。

甭管对前沿技术的学习,抑或是为了解决问题而去搜寻资料,你总免不了在各大博客(如:秋码记录 )、论坛社区以及生活类情感博客等网站游离,那些博文、贴文等总能解决你的燃眉之急的问题,而你也会在兴奋之余随手将该文分享给朋友。

很显然,文章分享功能可以说是各大网站的基础功能,网站运营者也热衷于你把文章分享出去,从而悄无声息的向你朋友推荐了该网站。所以,网站运营者是绝不会错失这样一个向用户宣传网站媒介之一的机会。然而,社会分享组件(第三方分享:诸如 QQ、微信、微薄……)并不能很好的推介网站,基于这种状况,一张既有文章的概要,又有网站的简介的海报便应运而生了。(秋码记录 便能为文章生成一张精美的海报)。

网站生成海报的几种方案

无论是线下的,还是线上的海报,它都是一张。对于线下,想要制作出一张海报,只需将事先做好的海报图打印出来即可,但就线上而言,网站页面结构主要由htmlcssjavascript构成,而文章内容及文章封面图都是不一样的,那么,在这样的情况下,又该如何为文章生成一张海报呢?

既然知道了,海报是一张,而文章页面结构又是html,那么只需将html转变成不就成了吗?

没错,要想为文章生成海报,只需把html转成图片即可,而且还有开源第三方实现。

  • 1、html2canvas.js:从其命名上来看,一眼便能知晓,它是将页面的html转成canvas。这也是众多网站生成海报的首选之一。它的便捷在于你想要为海报生成什么款式的,你只需像修改你网站那样去修改就好。(目前 秋码记录 是采用这种方式来为文章生成海报
  • 2、dom-to-image.js:与html2canvas.js大致差不多。
  • 3、canvas:直接使用canvas绘制而生成的海报,基于wordpress的很多主题也都使用它来生成海报。( 秋码记录 即将采用这种方案)

canvas绘制文本

在使用canvas绘制文本之前,有必要了解下什么是canvas

其实,canvas也是作为html标签而存在于html结构中,而它常常被用来绘制图形及图形动画。

在现实生活中,艺术家想要画出一张画,有两样东西是必不可少的——素描纸(写生纸)、HB铅笔

而在canvas中,同样需要设置画布的大小——widthheight

canvas绘制文本API

CanvasRenderingContext2D.fillText(text, x, y [, maxWidth]);
  • texttext是需要绘制的文本。
  • xx是文本绘制的水平参考点坐标。随着CanvasRenderingContext2D.textAlign的设置不同,x的坐标位置也不同。可以表示这段文字内容左侧坐标,或水平中心坐标,或右侧坐标。
  • yy是文本绘制的垂直参考点坐标。随着CanvasRenderingContext2D.textBaseline的设置不同,y的坐标位置也不同。支持多种基线类型(CSS中也有对应概念),MDN上有一张图可以很好地表示文本基线和文本垂直位置的关系。
  • **maxWidth**maxWidth表示文本内容占据的最大宽度。这里的maxWidth概念和CSS中的max-width差别很大,其最终的文本表现是:当文本占据宽度超过maxWidth的后,所有的文本自动变窄以适应这个最大宽度限制。表现类似这样:

canvas 如何实现文本首行缩进、自动换行、内容过多省略号呢?

虽然到目前为止,canvas API中还并没有提供文本首行、自动换行、内容过多以省略号结束等的支持,但还是可以通过计算X Y偏移量来实现的。

首行缩进

对于文本首行缩进,也就是在首行空出相对应的字符个数的空白位置,从而使得与其它行在视觉上达到了缩进的效果。

那么,canvas要想绘制出如css那样的首行缩进的文本样式效果,只需将X水平向右偏移相应的像素(pixel)即可。

内容过多以省略号结尾

无论是海报,还是书本的封面,总不肯多写几个字,倒像是一个惜字如命的家伙,生怕自己写多了,给自个儿带来了寿命减少几秒钟的担忧。那么,这时候,省略号这时候便闪亮登场了,很好地诠释着这一足够吸引用户眼球的重要任务。

而在canvas绘制文本时,只需判断是否绘制到文本的最后,若是,便在最后给原有文本追加上...即可。

自动换行

相对于首行缩进来讲,canvas要想实现文本自动换行,不单单只是计算X水平偏移量那么简单咯!

而还要计算Y纵向(垂直)偏移量,为了让你能够理解Y纵向偏移,我举个通俗的例子,我们平时不管是拿笔在纸上写字,还是在电子设备上敲击着文字,文本内容无不是由上而下自上而下从上而下的顺序呈现在我们的面前。由于纸或电子设备的宽度所限制,文本不得不另起一行,而这另起一行与之前的一行,就存在着纵向关系——另起一行是在之前的一行的下面(下方/ under),而之前的一行则就在另起一行的上方(上面 / upper)。

在实现自动换行这一效果时,我们应考虑到canvas该如何知道绘制当前在哪个位置(X水平位置)确需另起一行呢?这一点很重要,也是实现canvas自动换行的核心所在。

还是拿我们在纸张上写字或在电子设备上敲击文本时,我们知道换行(那是由于在纸张写的字大小差不多,一行只能容纳这么多文字)或电子设备设定好了字体大小,以此来推算出你写到哪个文字时,让你另起一行

那么,canvas实现自动换行可以通过计算文字字体大小`及纵向(Y)偏移量的。

canvas提供了CanvasRenderingContext2D.measureText(text)这个API,它可以用来计算字符的宽度。

canvas 是以左上角为原点,也就是说,X轴 水平向右是`正数`,反之亦然;Y 轴纵向则是以向下为`正数`,反向则负。

要让canvas知道该在哪个位置自动换行,只需将文本的每个字符宽度进行累加,判断总字符宽度是否达到了canvas所设定的画布宽度,若是,则另起一行继续绘制剩余的文本字符,当然咯,在另起一行时,纵向 Y偏移量是要往下移动。

 function drawMoreLines(canvas, style, content) {
     const ctx = canvas.getContext('2d')
     //从字体中解析字体大小 如:  font: '25px Helvetica'
     const fontHeight = parseInt(style.font.match(/\d+/), 10)
     //设置 canvas 文本属性
     ctx.font = style.font
     ctx.fillStyle = style.color
     ctx.textBaseline = 'top'
     ctx.textAlign = 'left'
     
     // X 轴水平偏移量 根据实际情况自行修改
     let alignX = 40
     //行宽
     let lineWidth = 0
     //文本内容截取的最后一个索引
     let lastSubStrIndex = 0
     //Y 轴 纵向偏移量
     let offsetY = 0
     
     //遍历文本字符
     for (let i = 0; i < content.length; i++) {
         //计算并累加每个字符的宽度
         lineWidth += ctx.measureText(content[i]).width;
         //判断累加后的字符宽度是否大于 画布宽度 减去 某个特定值(根据实际情况自行修改)
         if (lineWidth > canvas.width - 140) {

             //判断是否是首行
             if(lastSubStrIndex == 0 && style.textIndent){
                 //首行 X 轴水平向右偏移 style.textIndent 个像素
                 ctx.fillText(content.substring(lastSubStrIndex, i + 1), alignX + style.textIndent , offsetY);
             }else {
                 //非首行
                 
                 //判断是否是最后一行
                 if(style.ellipsis && i == content.length - 1){
                     //将在原有文本字符末尾追加上 ...
                     ctx.fillText(content.substring(lastSubStrIndex, i ) + '...', alignX , offsetY);

                 }else{
                     //按照正常的方式绘制文本字符
                     ctx.fillText(content.substring(lastSubStrIndex, i + 1), alignX , offsetY);

                 }


             }


             //另起一行,Y 轴偏移量是通过累加 字体大小 乘以 字符 行高
             offsetY += fontHeight * style.lineHeight
             //新的一行,将 lineWidth 重新设置为 0
             lineWidth = 0
             //文本内容截取索引设置为 另起一行 前 循环的索引
             lastSubStrIndex = i


         }
       
     }
 }

通过以下方式进行测试:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>秋码记录</title>
</head>
<body>
    
    <canvas id="content" width="500" height="400"></canvas>

    <script>
        const contentStyle = {
            font: '25px Helvetica',
            lineHeight: 1.5,
            position: 'left',
            color: 'rgba(88, 88, 88, 1)',
            textIndent: 40,
            ellipsis: true
        }
        
        let text = '自 秋码记录 没再为云服务器续费那会儿起,便选用了由Hugo驱动的博客主题,来迁移秋码记录 上的所有文章,然而,在众多Hugo博客主题之列,竟找不出一套属于自己想要的风格的主题,故而,也只能暂且'
 '
       
       let $content = document.getElementById('content')
       drawMoreLines($content, contentStyle, text);
    </script>

image-20240803144329594

canvas 绘制竖排文本

css中,要想实现文字竖排,只需改变writing-mode文档流的方向即可。然而只需这一行属性便可实现竖排文本的效果,使用canvas却不是那么容易的事情。

function verticalText(canvas,style,content){

        const ctx = canvas.getContext('2d')
        
        //设置 canvas 文本属性
        ctx.font = style.font
        ctx.fillStyle = style.color
        ctx.textBaseline = 'top'
        ctx.textAlign = 'left'

         // X 轴水平偏移量 根据实际情况自行修改
        let alignX = 40
        //Y 轴 纵向偏移量
        let offsetY = 10

         // 开始逐字绘制
        for (let i = 0; i < content.length; i++) {
            // 确定下一个字符的纵坐标位置
            let letterWidth = ctx.measureText(content[i]).width;

            if( i > 0){
                offsetY += (ctx.measureText(content[i - 1]).width) / 2
            }

            ctx.fillText(content[i], alignX , offsetY);
            // 旋转坐标系还原成初始态
            ctx.setTransform(1, 0, 0, 1, 0, 0);
            // 确定下一个字符的纵坐标位置
            letterWidth =  ctx.measureText(content[i]).width;
            offsetY += letterWidth;
        }

        // 水平垂直对齐方式还原
        ctx.textAlign = 'left';
        ctx.textBaseline = 'top';

       }
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>秋码记录</title>
</head>
<body>

    <canvas id="vertical-text" width="100" height="300"></canvas>
    
    <script>
         let verText = '你关注的领域,'

        let $varticleText = document.getElementById('vertical-text')
        verticalText($varticleText , contentStyle, verText);
    </script>
    
    </body>
</html>

image-20240803154133810

至于竖排自动换行不在本文的话题中,其实,能实现水平(X 轴)自动换行,那么 Y 轴(纵向)文本自动换行,不就是判断文字字体高度累加是否达到了canvas画布的高度,若是,则 X 轴水平向右移动(X 轴偏移量多少取决于文字的宽度及字间距`)。

还是来看看 秋码记录 为文章生成的海报(目前还是基于 html2canvas.js实现的,迟早会换掉的)

image-20240803155400744