UNPKG

node-image-from-html

Version:

This single-dependency library provides a simple API to render HTML content using <a href="https://github.com/puppeteer/puppeteer">Puppeteer</a> (A headless chromium brower) into png and jpeg images, insuring security and efficiency in the process. Writte

172 lines (131 loc) 8.05 kB
<h1 align="center">Node-Image-From-HTML🖼️</h1> <p align="center"> <a href="https://discord.gg/tamVs2Ujrf"> <img src="https://discordapp.com/api/guilds/769020183540400128/widget.png?style=banner2" alt="Discord Banner 2"/> </a> <div align="center"> <img src="https://img.shields.io/bundlephobia/min/node-image-from-html"> <a href="https://badge.fury.io/js/node-image-from-html"><img src="https://badge.fury.io/js/node-image-from-html.svg" alt="npm version" height="18"></a> <img src="https://img.shields.io/npm/dw/node-image-from-html"> </div> </p> # About This single-dependency library provides a simple API to render HTML content using <a href="https://github.com/puppeteer/puppeteer">Puppeteer</a> (A headless chromium brower) into png and jpeg images, insuring security and efficiency in the process. Written in TypeScript, it comes with native typings, supporting both CommonJS & ES6 imports. &nbsp; > Question: Why use this over other libraries? This library is actively maintained, and uses a persistant browser instance to render the content, allowing it to render images within a matter of milliseconds after starting. On top of this, Network Requests & Javascript can be disabled within the rendering process to avoid any potential security issues. > Question: What processing power is needed? Anything that's able to run an instance of chrome is able to render images, only one instance of chromium is open at a time, with each 'concurrent' instance just being an additional tab on the browser, so the overhead isn't too bad. > Question: Can I use CSS? Yes, all css is supported, and can be done inline or as a \<style>\</style> block. > Question: Why can't the library do xyz? If it can't do something, create an issue for it and i'll be happy to add any missing features! # Usage: <p> <ul> <li> <a href = "#Simple-Rendering">Simple Rendering</a> </li> <li> <a href = "#Multiple-Renders">Multiple Renders / Selector</a> </li> <li> <a href = "#Embedding-Images">Rendering embedded images</a> </li> </ul> </p> # Configuration: <h2 align="center">BrowserHandlerOptions</h2> <p align="center"> | Name | Description | Type | |-------------|---------------------------------------------------------|--------| | concurrency | The amount of tabs/render jobs that can process at once | number | | timeout | The max timeout a tab should wait before giving up. | number | | disableJavaScript | Disable JavaScript in the browser. | boolean | | disableNetwork | Disable network in the browser. | boolean | </p> <h2 align="center">ScreenshotOptions</h2> <p align="center"> | Name | Description | Type | |-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------| | omitBackground | An optional parameter to disable the white background behind the image when rendering a PNG. | boolean | | selector | An optional parameter to select which element to render an image of. If unspecified, the entire page will be rendered. View https://www.w3schools.com/cssref/css_selectors.asp for more information on CSS selectors. | string | | fullPage | A **deprecated** parameter to choose to screenshot the whole page or a portion of it. | boolean | | quality | An optional number from 1 to 100 to determine the quality of a JEPG exported image. | number | | type | An optional parameter to choose the type of image to take. jpeg, png, or webp, (PNG being the default.) | string | </p> # Examples ## Simple Rendering ```js // In an Async Context, const NodeImageFromHtml = require("node-image-from-html"); const fs = require("fs"); const engine = new NodeImageFromHtml.BrowserHandler(); await engine.start(); const rendered = await engine.render("<h1>Node-Image-From-HTML</h1>"); // Write the rendered buffer fs.writeFileSync("renderedImage.png", rendered); ``` <hr> ## Multiple Renders In the situation where there's more rendering jobs than there are available tabs, the engine will automatically queue the jobs, only processing a new one when the previous one is finished, while still making sure that all the tabs are rendering. ```js const NodeImageFromHtml = require(".."); const fs = require("fs"); // 5 concurrent rendering jobs. const engine = new NodeImageFromHtml.BrowserHandler({ concurrency: 5 }); // Using an IIFE to provide an async context. (async () => { await engine.start(); const renders = 25; // Giving the element a unique id allows us to only screenshot the element using a CSS selector, // https://www.w3schools.com/cssref/css_selectors.asp const html = "<h1 id='title'>Node-Image-From-HTML</h1>"; const promises = []; // Add the promises to queue for (let i = 0; i < renders; i++) { promises.push(engine.render(html, { omitBackground: true, fullPage: false, selector: "#title" })); } // Write the files once they finish. const startTime = Date.now(); const results = await Promise.all(promises) console.log(`Finished in ${Date.now() - startTime}ms`); for (let i = 0; i < results.length; i++) { fs.writeFileSync(`renderedImage${i}.png`, results[i]); } })() ``` ## Embedding Images The library exposes a 'utils' object, containing methods useful for the library. In this case, we can transform an image buffer into a data URI, letting us insert into the rendered image. ```js const NodeImageFromHtml = require(".."); const fs = require("fs"); const engine = new NodeImageFromHtml.BrowserHandler(); (async () => { await engine.start(); const buffer = fs.readFileSync("./myImage.png"); const html = ` <div id="ImageExample"> <h1>An embedded image!</h1> <img src="${NodeImageFromHtml.utils.toDataUri(buffer)}" /> </div> `; const rendered = await engine.render(html, { selector: "#ImageExample" }); fs.writeFileSync("myImage.png", rendered); engine.dispose(); })() ``` # Commit Guidelines The latest version of the code base will always be under the '**next**' branch! - All pull requiests must provide a valid reason for the change or implementation - All **CORE CHANGES** require an issue with reasoning made before a PR will even be addressed. - All PR's must follow the general structure of the code base - If you have questions, feel free to make an issue and i'll get to it right away! <hr> <div style="text-align: center"> <a href="https://www.buymeacoffee.com/ether" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a> </div>