整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Node.js实现将文字与图片合成技巧

Node.js实现将文字与图片合成技巧


者:诀九 前端名狮

转发链接:https://mp.weixin.qq.com/s/BMg8bFUwa4gmm6v2acAe7Q

着 Web 技术的发展,有很多需要将 HTML 内容转换为 PDF 文档并下载的场景,比如常见的收据、发票、电子报告、对账清单、文档翻译等等。

本文将研究当前比较流行的基于 Node.js 技术栈的 HTML 转 PDF 库:Puppeteer、jsPDF 和 PDFKit,大纲如下:

  • Puppeteer 及优缺点
  • jsPDF 及优缺点
  • PDFKit 及优缺点
  • Puppeteer vs jsPDF vs PDFKit 功能对比

1.Puppeteer

1.1.使用 Puppeteer 生成 PDF

Puppeteer 是谷歌开发的一个 Node.js 库,为控制无头(或完整)Chrome 或 Chromium 浏览器提供了一个高级 API。它是最流行的开源 HTML 到 PDF 转换器,支持 HTML、CSS 和 JavaScript。

Puppeteer 允许您自动化Web浏览器中的各种任务,例如 Web 抓取、网站测试、截图创建和 PDF 生成。它利用 Chrome 或 Chromium Web 浏览器的功能将 HTML 内容呈现为 PDF 文件。

下面使用 Puppeteer 快速初始化一个项目:

nvm use 20.6.1

mkdir puppeteer-demo

cd puppeteer-demo

npm init -y

npm install puppeteer

touch index.js

index.js 中添加如下代码:

import puppeteer from 'puppeteer';

(async ()=> {
  const browser=await puppeteer.launch({
    headless: 'new',
  });

  const page=await browser.newPage();

  await page.setContent(
    `<!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <style>
        body {
          display: grid;
          place-items: center;
          margin: 0;
          background-color: #ccc;
          min-height: 100vh;
        }
      </style>
      <h1>Hello, Puppeteer!</h1>
    </body>
    </html>`
  );

  await page.pdf({ path: 'result.pdf', format: 'A4' });

  await browser.close();
})();

在上面的代码中,我们导入 Puppeteer 库,启动无头 Chromium 浏览器,并在浏览器中创建一个新页面。我们还会根据页面内容和指定选项(如路径和格式)生成 PDF,生成完成后关闭浏览器并释放资源。

1.2.优点

  • 您可以完全控制要在 PDF 中包含网页的哪些部分。您可以指定具体的元素、部分或整个页面
  • Puppeteer 提供了自定义选项,如指定页面大小、边距、页眉和页脚,使您可以根据特定需求定制 PDF 布局
  • Puppeteer 可以捕捉 PDF 中的交互元素,如超链接和表单字段,适用于生成交互式 PDF 文件。

1.3.缺点

  • 使用 Puppeteer 生成的 PDF 有时可能比使用类似库生成的PDF要大。这会影响下载时间和存储成本。
  • 使用 Puppeteer 渲染复杂或大型网页可能会消耗资源,导致PDF生成变慢和内存使用增加。

2.PDFKit

PDFKit 是 JavaScript 生态系统中最古老和最成熟的 PDF库 之一。目前仍得到良好维护并定期更新。该库通常使用 Node.js 在服务器端环境中创建和操作 PDF 文档。它允许您通过定义每个页面的内容、布局和格式来以程序方式生成PDF文件。

PDFKit 提供了用于 PDF 文档生成的高级 API,并支持各种功能,使其成为创建自定义 PDF 的多功能工具。作为 PDFKit 的包装器,已开发出多个 PDF 库,支持自定义字体和图像嵌入。

2.1.使用 PDFKit 生成 PDF

让我们来快速初始化一个 PDFKit 项目:

nvm use 20.6.1

mkdir pdfkit-demo

cd pdfkit-demo

npm init -y

npm install pdfkit

touch index.js

index.js 中添加如下代码:

import fs from 'node:fs';
import PDFDocument from 'pdfkit';

const doc=new PDFDocument();

const stream=fs.createWriteStream('example.pdf');

doc.pipe(stream);
doc.fontSize(12).text('Hello, PDFKit!', { align: 'center' });
doc.end();

stream.on('finish', ()=> {
  console.log('success');
});

执行 node index.js 后,可以看到 PDF 可以生成生成,并触发 finish 事件的回调函数执行,打印出了 success

2.2.优点

  • 由于它是开源的,并由社区积极维护,PDFkit 可以不断改进和更新
  • PDFKit 可对 PDF 文档的内容、布局和格式进行精细控制。您可以根据自己的特定需求创建高度定制的 PDF 文档
  • PDFKit 是根据用户请求、数据或其他服务器端进程动态生成 PDF 的绝佳选择

2.3.缺点

  • 创建具有高级布局和功能的复杂 PDF 可能具有挑战性,可能需要充分了解库的 API
  • 对于新手来说,PDFKit 的学习曲线可能比更直接的 HTML 到 PDF 转换工具更陡峭,因为它需要对文档结构进行更多的手动控制

3.jsPDF

jsPDF 是一个流行的 JavaScript PDF 生成器,允许用户动态在 Web 浏览器中生成 PDF 文件。这个库维护良好,稳定易用,并且有丰富的文档。

jsPDF 在客户端操作,非常适合在 Web 应用程序中生成 PDF ,无需在服务器端生成。它可以修改现有布局,并允许用户通过自定义来控制他们的 PDF。还可以用来编辑现有的 PDF 文档或从头创建一个,包括图像、表格和形状等内容。

3.1.使用 jsPDF 生成 PDF

示例中使用官方提供的 CDN 地址 https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
  </head>
  <body>
    <style>
      body {
        display: grid;
        place-items: center;
        margin: 0;
        background-color: #ccc;
        min-height: 100vh;
      }
    </style>
    <h1>Hello, jsPDF!</h1>
    <script>
      document.addEventListener("DOMContentLoaded", function () {
        const pdf=new window.jsPDF();
        const element=document.body;

        pdf.html(element, {
          callback: function (pdf) {
            // Save the PDF to a file or display it
            pdf.save("output.pdf");
          },
        });
      });
    </script>
  </body>
</html>

文档地址:http://raw.githack.com/MrRio/jsPDF/master/docs/index.html

3.2.优点

  • jsPDF 完全在客户端(页面)上运行,这使它成为在 Web 应用程序中生成 PDF 的一个很好的选择,而无需外部服务
  • jsPDF 相对易于使用,尤其是对于基本的 PDF 生成任务。您只需几行 JavaScript 代码即可创建 PDF 文档
  • 由于 jsPDF 是一个 JavaScript 库,它可以与 Web 应用程序无缝集成,并可以与其他 JavaScript 库和框架一起使用

3.3.缺点

  • 在客户端生成 PDF 可能会耗费大量资源,尤其是大型或复杂文档。这会影响浏览器性能或导致内存消耗问题
  • jsPDF 在现代 Web 浏览器中得到广泛支持,但在旧的浏览器或具有较少 JavaScript 支持的环境中可能无法按预期工作
  • 与 PDFKit 等服务器端 PDF 生成库不同,jsPDF 具有有限的高级功能和能力。它可能不适用于复杂的PDF要求。

4.Puppeteer、jsPDF 和 PDFKit 功能比较

为便于大家参考,下面总结了 Puppeteer、jsPDF 和 PDFKit 库在 PDF 生成、文件大小、浏览器集成和社区支持方面的比较:

5.结论

当为 HTML 转 PDF 需求选择实现方案时,可以参考以上实现方案。如果你想从头开始生成 PDF,PDFKit 可能是你最好的选择。要通过 HTML 或者 SVG 内容快速转换为 PDF,jsPDF 可能更合适。对应网页渲染和交互式内容,强烈建议你选择 Puppeteer。

最后,方案选择在很大程度上还取决于你的项目类型、规范及开发者个人喜好。


如果文章对你有帮助,欢迎关注和转发,感谢你的支持!

ode.js 自发布以来,已成为业界重要破局者之一。Uber、Medium、PayPal 和沃尔玛等大型企业,纷纷将技术栈转向 Node.js。Node.js 支持开发功能强大的应用,例如实时追踪 App、视频 / 文本聊天引擎、社交媒体 App 等,当前已成为开发人员热衷的一项技能。本文作者基于自身实施经历,给出一张 Node.js 学习路线图。建议开发人员考虑深入掌握 Node.js 之前,必须明确自己构建的目标,否则容易半途而废。目标导向有助于在学习中聚焦关键技能,而非纠结于是否值得去学习。


必备技能


JavaScript


对于一名前端开发人员,在考虑掌握后端技能时,无需花费大量的精力学习去 JavaScript。而对于完全小白,如果想要在尽可能短的时间内掌握 Node.js,在深入前必须领会如下概念:


  • 箭头函数(Arrow Functions)
  • 类型(Types)
  • 表达式(Expressions)
  • 函数(Functions)
  • 语法结构(Lexical Structures)
  • this
  • 循环(Loops)和作用域(Scope)
  • 数组对象(Arrays)
  • 字面量模板(Template Literals)
  • 严格模式(Strict Mode)
  • ES6/ES7


此外,Node.js 中涉及大量的异步编程处理,推荐掌握如下概念:


  • 定时器(Timers)
  • Promises
  • 闭包(Closures)
  • 事件循环(Event Loop)
  • 异步编程(Async programming)和回调(callbacks)


npm 软件包管理


Node 软件包管理(Node Package Manager,npm)提供当前规模最大的注册软件库,其中提供 80 多万种软件包。正确使用 npm,可极大地降低软件包管理的复杂度,非常便于解决应用开发中的依赖问题。


npm 提供三个组成模块:


  • 命令行接口(Command Line Interface,CLI):CLI 是大部分开发人员的首选方式,提供本机终端环境运行。
  • 注册软件库(Registry):提供大规模开放式 JavaScript 软件和元信息数据库。
  • Web 站点:可查找新的软件包,并提供其它一些 npm 功能。


npm 还可管理各版本的代码及依赖。如果使用 npx,无需下载软件包即可运行软件包。


Node.js 基础知识


事件发射器(Event Emitter):做为 Node.js 中的对象,Event Emitter 在操作执行完成后发送消息,触发特定的事件。开发人员也可编写代码,监听 Event Emitter 发出的事件。例如,一旦完成特定的前端操作,诸如鼠标点击、按键和鼠标移动等交互操作,需在后端做进一步处理。这时后端的 Node.js 环境使用 EventEmitter 类,构建相应的事件处理模块,用于处理操作事件。


回调(Callback):回调是特定任务执行完成后调用的函数,不影响其它代码的同时执行,避免了异步处理产生阻塞。鉴于 Node.js 中需处理大量的异步任务,因此回调无处不在。回调是实现应用无缝快速执行的关键,其运作机制如下图所示:



Buffer 类:设计用于处理原始二进制数据的 Node.js 类,操作 V8 引擎外分配的内存。Buffer 类实现为大小不可调整的整数数组,并提供一整套二进制数据操作方法。例如,对于表示范围在 0 到 255 之间字节值的内存中整数,使用 console.log() 输出该 Buffer 实例,会给出一系列十六进制值。


模块系统(Module System):使用 Node.js 生态系统提供的模块,可实现一些复杂功能。模块是可复用的 JavaScript 代码,实现特定的功能。


开发技能


版本管理系统:掌握 git、GitHub 等的使用。开发中,应尽量避免交叉修改代码导致的更改不可逆。因此,在大型项目中需使用版本控制系统管理。要熟悉版本控制系统的使用,开发人员应该具备扎实的基础知识。


HTTP/HTTPS 协议:一位优秀的 Node.js 开发人员,应具备传输协议数据传输的基础知识,因为每位后端开发人员都需要深入理解 HTTP/HTTPS 的工作机制。HTTPS 使用称为 TLS(Transport Layer Security)的加密协议加密通信。后端环境中有大量要学习的知识点,这对于 Web 小白是颇具难度的。简而言之,基本的 Web 通信主要包括六种请求方法:


  • GET: 获取资源的表示;
  • POST: 创建新资源;
  • PUT: 更新资源;
  • PATCH: 局部修改资源;
  • DELETE: 删除 URL 指定的资源
  • OPTIONS: 请求指定 URL/ 服务器所支持的通信。


Web 框架


注意:本文仅列出了部分推荐 Web 框架。使用 Node.js 构建个人项目时,为降低学习难度,推荐从中选定一种框架,否则学习难度很高。


Express.js:提供构建应用所需的最小化接口和工具,非常灵活易用,大量 npm 模块可直接插入 Expresss 使用。


Meteor.js:一种构建 JavaScript 应用的万事通框架,提供内建的 MongoDB,支持 GraphQL。运行 meteor create myapp,即可生成一个具有 MongoDB 后端的 HTML/JavaScript 页面。使用 Meteor.js 可有效助降低项目开发时间,并简化项目的维护。当然如果只是构建一个简单的 Web 应用,还是推荐使用 Express。


Sails.js:一种支持快速构建 REST API、单页应用(SPA)和实时 APP 的 MVC 框架。如果开发人员考虑实操一些重要技能,例如使用 WebSockets 支持实时操作,使用按约定编程(convention over configuration)方法等,推荐学习 Sails.js。


Koa.js:如果开发人员考虑构建一个经得起时间考验、易于维护的鲁棒应用,Koa.js 无疑是很好的选择。Koa 应用实现为包含一组中间件函数数组的对象,其中函数以堆栈方式执行。


Nest.js:该框架继承了 Angular 的理念,使用 TypeScript 构建,并且在底层使用了 Express.js,因此兼容大多数 Express 中间件。Nest 提供很好的模块化结构,代码组织在不同模块中,进而构建高效、良好扩展的应用。


数据库管理


学习 Node.js 需要掌握大量的后端技能。对于一名小白,开始可选择 MySQL 等数据库。只有厘清后端系统设计的基础知识,才能根据项目的需求,考虑在 MySQL 等基本 SQL 数据库之外选取后端。


注意:关系数据库依然是主流。例如,在建模产品、类比、标签等时依然主要使用关系表结构。类似于电子表格,关系表由行和列组成。


关系数据库管理系统


SQL Server:微软的关系数据库产品,支持标准 ANSI SQL,也提供产品独有的 SQL 实现。


MySQL:一款优秀的关系数据库管理系统,时由 Oracle 提供的开源后端软件,具备按需改进代码的灵活性。MySQL 可很好地替代 Oracle、Microsoft SQL server 等商业数据库产品。


PostgreSQL:具有大规模开发团队支持的开源产品,可运行在 Linux、UNIX 和 Windows 等大多数主流操作系统上。PostgreSQL 支持绝大多数标准 SQL 查询,还提供复杂 SQL 查询、外键、触发器、事务、MVCC、流复制等特性。


MariaDB:MySQL 的改进版,额外内建了多种特性、安全和性能改进。简而言之,MariaDB 性能优于 MySQL,推荐在大型应用中使用 MariaDB。例如,MariaDB 的大型连接池支持超过 20 万的并发连接,显著优于 MySQL。


云数据库服务


Azure CosmosDB:一种全球分布式数据库服务,支持远程管理数据。对于大型应用,云数据库在扩展型和可管理性上具有优势。Microsoft Azure 完全简化了可扩展和分布能力,在同一后端上支持多种数据模型,即可同时用于文档、键值、关系和图模型。该服务不依赖于任何模式,因此可称为 NoSQL 数据库,但可使用支持 ACID 交易的查询语言。


Amazon DynamoDB:非常适用于具有 SQL 经验的用户,提供全托管 NoSQL 数据库服务,具有高性能,可预测,扩展性很好。DynamoDB 支持创建关系表,可存储并检索任何规模的数据,提供任何服务等级的请求。


NoSQL 数据库


MongoDB:面向文档的 NoSQL 数据库,适用于大规模数据存储。类似于表是关系数据库的基础,MongoDB 使用集合(Collection)和文档(Document)。其中,文档包含了键值对,是 MongoDB 的基本数据单元。集合包含一系列文档和函数,对标关系数据库中的表。


Redis:可用于数据库、缓存和消息代理(Message Broker)。Redis 使用字符串、哈希、列表、集合、位图、hyperloglog 和时空索引等数据结构,以键值形式存储数据。下面举例说明:


假设应用必须处理授权用户的不同操作。每次验证用户身份,都必须获取应用中访问权限控制模块的授权。实现此类安全机制的方案很多。例如,标准的 JOSE(JavaScript 对象签名和加密)框架可确保应用数据的安全性。但面对多种授权时,应用同样很难扩展。除了发送授权列表给用户,另一种解决方案是将用户授权以某种形式的数据库存储。授权以键值对(也称为令牌)形式提供,用户必须提供键值进行验证。


Apache Cassandra:Facebook 创建的高度可扩展、高性能的分布式数据库,设计针对物理上分布的海量数据,实现无单点故障的存储。不同于其它关系数据库系统,Cassandra 在分布式设计上参考了 Amazon DynamoDB,数据模型使用 Google BigTable。


LiteDB:一款超轻量级、高性能的 .NET NoSQL 嵌入数据库,实现无服务器的文档存储。LiteDB 使用于小型的桌面应用、Web 应用,可根据每个用户的每个账户建立一个独立数据库。


搜索引擎


注意:为什么需要了解搜索引擎技术,下面举例说明。如果使用谷歌搜索引擎,它本身就是一个完整的 Web 应用。对于 Solr 和 ElasticSearch 等后端框架,它们会对所有类型数据集创建索引,进而在服务器提供搜索功能。Solr 支持百万级用户的搜索引擎网站。


ElasticSearch:一种基于 Apache Lucene 使用 Java 开发的搜索和分析引擎,实现海量数据的实时存储和分析。其高性能来自于对索引而非文本的搜索,核心基于结构化文档,而非关系表和模式,提供丰富的 REST API 存储和搜索数据。ElasticSearch 可认为是一台处理 JSON 请求并返回 JSON 数据的服务器。


Solr:提供包括字段搜索、布尔查询、短语查询、模糊查询、语法检查、自动填全等高级实时搜索功能。


缓存


注意:缓存使用内存中存储文件拷贝,降低网络调用,提供更快的网络响应。


内存缓存


该技术大多数情况下使用服务器的内存,因此通常称为内存缓存。服务器的一部分内存用作缓存,存储降低应用网络调用所需的所有数据。Node.js 提供的节点缓存(node-cache)和内存缓存(memory-cache)软件库,很好地处理了 Node 服务器上的内存缓存。


分布式缓存


分布式缓存将多个网络内存整合为单一的内存数据存储,进而用于缓存最终数据,提供对数据的快速访问。该技术尤其适用于大规模数据和大量网络调用的情况,通过在群集中添加更多的服务器实现缓存容量的增量扩展和扩容。Redis 是目前最广为使用的 分布式内存,推荐进一步了解 Memcached。



模板引擎


模板引擎支持在应用开发中使用静态模板文件,并在运行时替换模板文件中的变量为实际值,生成发送给客户的 HTML 文件。下面列出了一些广为使用的模板引擎。


  • Mustache.js
  • Handlebars
  • EJS


实时通信


Socket.io:对于起步接触后端开发的学习者,了解 Socket.io 的实时通信需要补充很多知识,主要底层逻辑在客户端和服务器之间。Socket.io 支持客户和服务器间的双向数据流,可视为实现两个终端间实时通信的同步数据流行为。这需要客户在浏览器支持 Socket.IO,并且服务器端继承了 Socket.IO 软件包,进而数据才能以 JSON 请求的形式发送。


API 客户端


REST


在 REST 提出之前,API 使用远程过程调用(RPC)开发,类似于本地执行的代码。期间许多技术使用了类似于 RPC 的技术栈,并未从根本上解决问题,直到 REST 提出以更好的方式构建基于 Web 的 API。


REST 架构使用基本 HTTP 调用进行通信,避免了使用 COBRA、COM +,RPC 等复杂方式通信。在 REST 中,调用是基于消息的,依赖 HTTP 标准描述消息。在 Node.js 生态中,推荐使用 node-rest-client 和 Axios。这两个软件库为快速 Web 应用提供了很好的支持。


GraphQL


GraphQL 可很好地替代 REST。它使用 API 优先为客户准确提供所请求的数据,是一种灵活并且对开发人员友好的替代方案,可使用 GraphiQL IDE 部署。GraphQL 具有多项优点,包括在不影响现有查询情况下添加和禁用数据域,以及支持多种方式构建 API。


测试


单元测试框架


单元测试实现各单元和组件的隔离测试。其中,单元可以是应用中的最小可测试代码部分。下面列出 Node.js 的最好的单元测试框架:


  • Jest:一款由 Facebook 提供的测试框架,因其简洁性而广为使用。Jest 相比其它所有测试框架而言具有最好的文档,支持并行测试,这意味可使用单独进程独立运行各个测试,实现性能最大化。
  • Mocha:为 Node 应用提供原始标准的单元测试框架,支持回调等异步操作,支持使用高度可扩展和自定义断言的 Promise。
  • Chai:支持与 Mocha 一同使用,可做为 Node.js 的 TDD/BDD 断言库,可匹配任何基于 JavaScript 的测试框架。


模拟测试(Mocking)


单元测试的规模越小越好,并尽可能轻量级执行。但在一些情况下,测试对象存在对其他对象的依赖。


例如,对于需要与域服务器或 Web Service 通信的对象,无法执行快速、轻量级的测试,这时就需要 Mocking 测试。运行 Mocking 测试不需要任何实际数据库,或是任何类型的连接,只返回给出预期结果的对象。Mocking 测试只使用一些基本对象,模拟给出实际测试结果,因此可摆脱所有局限更快地运行测试。


推荐阅读: 下面资料分别介绍了如何使用 Sinon 和 Jasmine 实现 Mocking 测试:


  • Sinon
  • https://stackabuse.com/using-mocks-for-testing-in-javascript-with-sinon-js/
  • Jasmine
  • https://eclipsesource.com/blogs/2014/03/27/mocks-in-jasmine-tests/


Node.js 软件库推荐:


  • Async.js
  • PM2
  • Commander.js
  • Nodemailer


原文链接:


https://js.plainenglish.io/node-js-developer-roadmap-for-2021-2ae9c057bff4