preface

I need to use node drawing in the project and return, query the market node drawing library

Drawing library Reasons you don’t want to use it
canvas GTK, GYp, and so on, because py3.0 is already installed and it’s too cumbersome to change.
gm Did not find the library to do the gradient information, other looks good to use

After a bit of digging I thought I could use puppeteer for drawing

introduce

Puppeteer is an official Google Node library that controls Headless Chrome through the DevTools protocol.

You can directly control Chrome through the apis provided by Puppeteer to simulate most user actions to perform UI tests or to crawl pages to collect data.

First, Puppeteer provides many functions to execute code in the Page DOM Environment,

Second, Puppeteer provides ElementHandle and JsHandle to encapsulate elements and objects in the Page DOM Environment into corresponding Node.js objects. In this way, the Page DOM can be manipulated directly by the encapsulation functions of these objects

Puppeteer is a browser that runs inside node and allows you to do things that node can’t, such as generating PDFS for web pages, testing web performance, simulating form submission, crawling web data, etc., as well as puppeteer drawing in Node

gogogo

npm i puppeteer
Copy the code

1. Wrap to get the browser instance

const puppeteer = require('puppeteer')
const mainConfig = require('./mainConfig')
class BrowserManage {
	browserDestructionTimeout // Clean up the browser instance
	browserInstance // Browser instance
	browserState = 'closed' // Browser status
	/** * Close the browser instance */ when no operation has been performed for a long time
	scheduleBrowserForDestruction() {
		clearTimeout(this.browserDestructionTimeout)
		this.browserDestructionTimeout = setTimeout(async() = > {if (this.browserInstance) {
				this.browserState = 'closed'
				await this.browserInstance.close() // Close the browser instance}},5000)}/** * Close the browser instance */ when no operation has been performed for a long time
	async getBrowser() {
		return new Promise(async (resolve, reject) => {
			if (this.browserState === 'closed') {
				this.browserInstance = await puppeteer.launch(mainConfig.config.puppeteer) // Start the browser instance
				this.browserState = 'open'
				resolve(this.browserInstance)
			}
			if (this.browserState === 'open') {
				if (this.browserInstance) {
					resolve(this.browserInstance)
				}
			}
		})
	}
}
module.exports = new BrowserManage()
Copy the code

Here the mainConfig. Config. Puppeteer

{
	args: ['--no-sandbox'.'--disable-setuid-sandbox']}Copy the code

There’s no sandbox here because it’s only drawing so it doesn’t jump to the page, but it’s highly recommended that you sandbox if you’re involved in jumping to the page

reference

Developers.google.com/web/tools/p…

Stackoverflow.com/questions/6…

2. Define the drawing function

Take drawing text as an example

exports.toImgData = async (options) => {
	let fontConfig = {
		baseLine: 5
	}

	function getColorX(i, colors) {
		if (colors instanceof Array) {
			return (i / (colors.length - 1)).toFixed(2)}}return new Promise((resolve, reject) = > {
		let canvas = document.createElement('canvas')
		let ctx = canvas.getContext('2d'),
			font = options.text || 'Abba abba',
			fontSize = Number(options.fontSize || 32),
			fontFamily = options.fontFamily,
			lineHeight = fontSize + fontSize / fontConfig.baseLine
		canvas.width = fontSize * font.length
		canvas.height = lineHeight
		gradient = ctx.createLinearGradient(0.0, canvas.width, 0)
		ctx.shadowColor = options.shadowColor || ' '
		ctx.shadowOffsetX = options.shadowOffsetX || 2
		ctx.shadowOffsetY = options.shadowOffsetY || 2
		if (options.colors instanceof Array) {
			// Implement the gradient color
			for (let i = 0; i < options.colors.length; i++) {
				gradient.addColorStop(getColorX(i, options.colors), options.colors[i])
			}
		} else if (typeof options.colors == 'string') {
			gradient.addColorStop(0, options.colors)
		} else {
			// Default color
			gradient.addColorStop(0.'rgba(241,158,194,1)')
		}
		ctx.font = fontSize + 'px ' + fontFamily
		if(! options.mode || options.mode =='1') {
			//mode ==1
			ctx.fillStyle = gradient
			ctx.fillText(font, 0, fontSize)
		} else if (options.mode == '2') {
			//mode ==2
			ctx.strokeStyle = gradient
			ctx.strokeText(font, 0, fontSize)
		}
		ctx.restore()
		const dataURI = canvas.toDataURL('image/png')
		const base64 = dataURI.substr(22) // 22 =`data:image/png; base64,`.length
		resolve(base64)
	})
}
Copy the code

3. Obtain and use the browser page instance

const browser = await browserManage.getBrowser()
const page = (await browser.pages())[0]
await page.setOfflineMode(true) // Since we don't need to read network resources, this saves bandwidth on my poor server
page.on('console'.(msg) = > console.log(msg.type(), msg.text())) // Listen for the page console event
const base64 = await page.evaluate(toImgData, passedOptions)
browserManage.scheduleBrowserForDestruction()
const buffer = Buffer.from(base64, 'base64')
return buffer // Return the Base64 encoded image
Copy the code

Note the page. Evaluate function here

page.evaluate(pageFunction[, …args])

PageFunction < XSL: | string > to be executed in page instance context method

. args <… The Serializable | JSHandle > to pageFunction parameters

Return: <Promise> pageFunction result of execution

This function is equivalent to an internal eval call to the JS function in the retrieved page instance

So getColorX in toImgData is written inside

You can also pull out getColorX and call it this way

await page.evaluate(getColorX) // declare and define getColorX
const base64 = await page.evaluate(toImgData, passedOptions)
Copy the code
  • Results the following

conclusion

This article describes node drawing using puppeteer.

Note that if you draw Chinese characters in Linux, it will be blank because by default, Chinese characters are not installed in Linux

Installation can refer to the article www.huaweicloud.com/articles/f6…

In Linux, puppeteer cannot be started directly by NPM I. You need to install Chromium or puppeteer

Sudo apt-get install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-3 Libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango 1.0-0 Libpangocairo -1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wgetCopy the code

then

const browser = await puppeteer.launch({
        executablePath: "/usr/bin/chromium-browser".// Configure the Chromium path from executablePath.Copy the code

An error in the

(node:28469) UnhandledPromiseRejectionWarning: Error: Failed to launch chrome! [1025/150325.817887: ERROR: zygote_host_impl_linux. Cc (89)]Copy the code

Because no sandbox is configured, so it starts in no-sandbox mode

const browser = await puppeteer.launch({
  args: ['--no-sandbox'.'--disable-setuid-sandbox']}...Copy the code

Sandbox configuration is recommended

Reference github.com/puppeteer/p…

Example git address github.com/lgldlk/pupp…

Welcome to join the front-end learning discussion group QQ group number: 530496237