@aborrol/resvg-js-tolty
v2.6.2-ab41
Published
Fork: resvg-js with advanced custom text layout (textLayout, letterSpacing, opacity, font buffers) by Aborrol
Maintainers
Readme
Reusing fonts in Node (ResvgFontManager)
Чтобы не парсить и не загружать шрифты на каждый new Resvg(...), можно создать ResvgFontManager один раз и переиспользовать базу шрифтов:
const { ResvgWithFonts, ResvgFontManager } = require('@aborrol/resvg-js-tolty')
const fontManager = new ResvgFontManager({
loadSystemFonts: false,
fontBuffers: [
{ fontName: 'Roboto-400', buffer: fs.readFileSync('Roboto-Regular.ttf') },
],
defaultFontFamily: 'Roboto-400',
})
const resvg = ResvgWithFonts.withFontManager(svgString, {
background: '#fff',
// любые другие опции
}, fontManager)
const png = resvg.render().asPng()⚡️ This is a fork of [email protected] with custom text layout features (see below).
resvg-js
resvg-js is a high-performance SVG renderer and toolkit, powered by Rust based resvg, with Node.js backend using napi-rs, also a pure WebAssembly backend.
Please use all lowercase resvg-js when referencing project names.
Playground
https://resvg-js.vercel.app
Features
- Fast, safe and zero dependencies, with correct output.
- Convert SVG to PNG, includes cropping, scaling and setting the background color.
- Support system fonts and custom fonts in SVG text.
v2: Gets the width and height of the SVG and the generated PNG.v2: Support for outputting simplified SVG strings, such as converting shapes(rect, circle, etc) to<path>.v2: Support WebAssembly.v2: Support to get SVG bounding box and crop according to bounding box.v2: Support for loading images of external links in<image>.- No need for node-gyp and postinstall, the
.nodefile has been compiled for you. - Cross-platform support, including Apple M Chips.
- Support for running as native addons in Deno.
Custom Features (Fork by Aborrol)
- Поддержка кастомного layout для
<text>: автоматический перенос строк, параметрыwidth,lineHeight,maxlines,textAlign,opacity,letterSpacingи др. через опциюtextLayoutв JS. - Возможность задавать шрифты из буфера с явным именем family (
fontBuffers). - Приоритет параметров: опции JS → SVG-атрибуты → дефолт.
- Все параметры применяются по id
<text>. Если id не найден — опции не применяются. - Условное логирование: контроль уровня детализации логов через опцию
logLevel('off','error','warn','info','debug','trace').
Пример: кастомный layout и шрифты из буфера
const { promises } = require('fs')
const { join } = require('path')
const { Resvg } = require('@resvg/resvg-js')
async function main() {
const svg = await promises.readFile(join(__dirname, 'input.svg'), 'utf8')
const fontFiles = [
{ name: 'Lobster', file: 'Lobster-Regular.ttf' },
{ name: 'Jost-700', file: 'Jost-700.ttf' },
]
// Загружаем шрифты как буферы
const fontBuffers = await Promise.all(
fontFiles.map(async ({ name, file }) => {
const buffer = await promises.readFile(join(__dirname, 'fonts', file))
return { fontName: name, buffer: Array.from(buffer) }
}),
)
const resvg = new Resvg(svg, {
background: '#fff',
font: {
loadSystemFonts: false,
fontBuffers, // <-- ваши шрифты
defaultFontFamily: 'Lobster',
},
textLayout: {
'main-title': {
width: 300,
lineHeight: 32,
maxlines: 3,
textAlign: 'center',
opacity: 0.5,
letterSpacing: 2.5,
x: 50,
y: 100,
fontFamily: 'Lobster',
fontSize: 48,
fill: '#ff0000',
},
'subtitle': {
width: 200,
lineHeight: 24,
maxlines: 2,
textAlign: 'left',
}
},
logLevel: 'debug', // Контроль уровня логирования: 'off', 'error', 'warn', 'info', 'debug', 'trace'
})
const pngData = resvg.render()
const pngBuffer = pngData.asPng()
await promises.writeFile(join(__dirname, 'output.png'), Buffer.from(pngBuffer))
console.log('💾 output.png создан')
}
main().catch(console.error)Этот пример показывает, как подключить свои TTF-шрифты из буфера и задать расширенный layout для текста через textLayout.
Уровни логирования (logLevel)
Опция logLevel позволяет контролировать детализацию отладочной информации:
'off'- никаких логов'error'- только ошибки'warn'- предупреждения и ошибки'info'- информационные сообщения, предупреждения и ошибки'debug'- все сообщения включая отладочные (по умолчанию)'trace'- максимальная детализация
Примеры использования:
// Минимальное логирование - только ошибки и предупреждения
const resvg = new Resvg(svg, { logLevel: 'warn' })
// Полная отладочная информация
const resvg = new Resvg(svg, { logLevel: 'debug' })
// Без логов
const resvg = new Resvg(svg, { logLevel: 'off' })TypeScript Поддержка
Проект включает полную TypeScript типизацию для всех функций, включая кастомный textLayout:
import { Resvg, ResvgRenderOptions, TextLayoutOptions } from '@aborrol/resvg-js-tolty';
const textLayout: TextLayoutOptions = {
'main-title': {
width: 300,
lineHeight: 32,
maxlines: 3,
textAlign: 'center', // 'left' | 'center' | 'right' | 'middle'
opacity: 0.5,
letterSpacing: 2.5,
x: 50,
y: 100,
fontFamily: 'Lobster',
fontSize: 48,
fill: '#ff0000',
fontWeight: 'bold',
fontStyle: 'normal',
}
};
const options: ResvgRenderOptions = {
font: {
loadSystemFonts: false,
fontBuffers: [
{ fontName: 'Lobster', buffer: [1, 2, 3, 4] }
],
},
textLayout,
logLevel: 'debug',
};
const resvg = new Resvg(svg, options);Доступные типы:
TextLayoutBlockOptions- опции для одного текстового блокаTextLayoutOptions- карта id → опции для всех текстовых блоковResvgRenderOptions- полные опции рендерингаFontBuffer- структура для передачи шрифтов из буфера
Cross-Compilation
resvg-js поддерживает кросскомпиляцию для всех основных платформ.
Быстрый старт
Локальная кросскомпиляция
# Установка зависимостей и Rust целей
make install
# Кросскомпиляция для всех платформ
make build
# Проверка артефактов
make verifyDocker кросскомпиляция
# Кросскомпиляция через Docker
make build-docker
# Или через npm
npm run cross-compile:docker:rebuildГибридная кросскомпиляция (рекомендуется)
# macOS локально + остальные через Docker
make build-hybrid
# Или через npm
npm run cross-compile:hybridДокументация
- CROSS_COMPILATION.md - Локальная кросскомпиляция
- DOCKER_CROSS_COMPILATION.md - Docker кросскомпиляция
- HYBRID_CROSS_COMPILATION.md - Гибридная кросскомпиляция (рекомендуется)
Поддерживаемые платформы
- macOS: ARM64 (Apple Silicon), x64 (Intel)
- Linux: ARM32/ARM64/x64 (glibc и musl)
- Windows: ARM64/x86/x64
- Android: ARM32/ARM64
CI/CD
Проект включает автоматический GitHub Actions workflow для кросскомпиляции на всех платформах.
Installation
Node.js
npm i @resvg/resvg-jsBrowser(Wasm)
<script src="https://unpkg.com/@resvg/resvg-wasm"></script>Docs
- Node.js see index.d.ts
- Wasm see wasm/index.d.ts
Example
Node.js Example
This example will load Source Han Serif, and then render the SVG to PNG.
node example/index.js
Loaded 1 font faces in 0ms.
Font './example/SourceHanSerifCN-Light-subset.ttf':0 found in 0.006ms.
✨ Done in 55.65491008758545 msDeno Example
deno run --unstable --allow-read --allow-write --allow-ffi example/index-deno.js
[2022-11-16T15:03:29Z DEBUG resvg_js::fonts] Loaded 1 font faces in 0.067ms.
[2022-11-16T15:03:29Z DEBUG resvg_js::fonts] Font './example/SourceHanSerifCN-Light-subset.ttf':0 found in 0.001ms.
Original SVG Size: 1324 x 687
Output PNG Size : 1200 x 623
✨ Done in 66 ms| SVG | PNG | | ---------------------------------------- | -------------------------------------------- | | | |
Usage
Node.js
const { promises } = require('fs')
const { join } = require('path')
const { Resvg } = require('@resvg/resvg-js')
async function main() {
const svg = await promises.readFile(join(__dirname, './text.svg'))
const opts = {
background: 'rgba(238, 235, 230, .9)',
fitTo: {
mode: 'width',
value: 1200,
},
font: {
fontFiles: ['./example/SourceHanSerifCN-Light-subset.ttf'], // Load custom fonts.
loadSystemFonts: false, // It will be faster to disable loading system fonts.
// defaultFontFamily: 'Source Han Serif CN Light', // You can omit this.
},
}
const resvg = new Resvg(svg, opts)
const pngData = resvg.render()
const pngBuffer = pngData.asPng()
console.info('Original SVG Size:', `${resvg.width} x ${resvg.height}`)
console.info('Output PNG Size :', `${pngData.width} x ${pngData.height}`)
await promises.writeFile(join(__dirname, './text-out.png'), pngBuffer)
}
main()Bun
Starting with Bun 0.8.1, resvg-js can be run directly in Bun without any modification to the JS files, and is fully compatible with the syntax in Node.js.
bun example/index.jsDeno
Starting with Deno 1.26.1, there is support for running Native Addons directly from Node.js. This allows for performance that is close to that found in Node.js.
deno run --unstable --allow-read --allow-write --allow-ffi example/index-deno.jsimport * as path from 'https://deno.land/[email protected]/path/mod.ts'
import { Resvg } from 'npm:@resvg/resvg-js'
const __dirname = path.dirname(path.fromFileUrl(import.meta.url))
const svg = await Deno.readFile(path.join(__dirname, './text.svg'))
const opts = {
fitTo: {
mode: 'width',
value: 1200,
},
}
const t = performance.now()
const resvg = new Resvg(svg, opts)
const pngData = resvg.render()
const pngBuffer = pngData.asPng()
console.info('Original SVG Size:', `${resvg.width} x ${resvg.height}`)
console.info('Output PNG Size :', `${pngData.width} x ${pngData.height}`)
console.info('✨ Done in', performance.now() - t, 'ms')
await Deno.writeFile(path.join(__dirname, './text-out-deno.png'), pngBuffer)WebAssembly
This package also ships a pure WebAssembly artifact built with wasm-bindgen to run in browsers.
Browser
<script src="https://unpkg.com/@resvg/resvg-wasm"></script>
<script>
;(async function () {
// The Wasm must be initialized first
await resvg.initWasm(fetch('https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm'))
const font = await fetch('./fonts/Pacifico-Regular.woff2')
if (!font.ok) return
const fontData = await font.arrayBuffer()
const buffer = new Uint8Array(fontData)
const opts = {
fitTo: {
mode: 'width', // If you need to change the size
value: 800,
},
font: {
fontBuffers: [buffer], // New in 2.5.0, loading custom fonts
},
}
const svg = '<svg> ... </svg>' // Input SVG, String or Uint8Array
const resvgJS = new resvg.Resvg(svg, opts)
const pngData = resvgJS.render(svg, opts) // Output PNG data, Uint8Array
const pngBuffer = pngData.asPng()
const svgURL = URL.createObjectURL(new Blob([pngData], { type: 'image/png' }))
document.getElementById('output').src = svgURL
})()
</script>See playground, it is also possible to call Wasm in Node.js, but it is slower.
Sample Benchmark
npm i [email protected] [email protected] @types/sharp [email protected]
npm run benchRunning "resize width" suite...
resvg-js(Rust):
12 ops/s
sharp:
9 ops/s
skr-canvas(Rust):
7 ops/s
svg2img(canvg and node-canvas):
6 ops/sSupport matrix
| | Node.js 12 | Node.js 14 | Node.js 16 | Node.js 18 | Node.js 20 | Node.js 22 | npm |
| ---------------- | ---------- | ---------- | ---------- | ---------- | ---------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Windows x64 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Windows x32 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Windows arm64 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| macOS x64 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| macOS arm64(M Chips) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Linux x64 gnu | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Linux x64 musl | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Linux arm gnu | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Linux arm64 gnu | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Linux arm64 musl | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Android arm64 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Android armv7 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
Test or Contributing
Install latest
RustInstall
Node.js@10+which fully supportedNode-APIInstall
wasm-packcurl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | shNormally
wasm-packwill installwasm-bindgenautomatically, but if the installation fails due to network reasons, please try to install it manually.cargo install wasm-bindgen-cliOn computers with Apple M chips, the following error message may appear:
Error: failed to download from https://github.com/WebAssembly/binaryen/releases/download/version_90/binaryen-version_90-x86_64-apple-darwin.tar.gz
Please install binaryen manually:
brew install binaryen
Build Node.js bindings
npm i
npm run build
npm testBuild WebAssembly bindings
npm i
npm run build:wasm
npm run test:wasmRoadmap
I will consider implementing the following features, if you happen to be interested, please feel free to discuss with me or submit a PR.
- [x] Support async API
- [x] Upgrade to napi-rs v2
- [x] Support WebAssembly
- [x] Output usvg-simplified SVG string
- [x] Support for getting SVG Bounding box
- [ ] Support for generating more lossless bitmap formats, e.g. avif, webp, JPEG XL
Release package
We use GitHub actions to automatically publish npm packages.
# 1.0.0 => 1.0.1
npm version patch
# or 1.0.0 => 1.1.0
npm version minorLicense
Please use all lowercase resvg-js when referencing project names.
Copyright (c) 2021-present, yisibl(一丝)
