/SVG-to-PDFKit

Insert SVG into a PDF document created with PDFKit

Primary LanguageJavaScript

SVG-to-PDFKit

Notes: Added by forker (jacobbubu)

  • Using peerDependencies for pdfkit
  • adding callback for element drawing.
  • support color from color books
  • support customized getComputedStyle
    • Add getComputedStyleCallback

Example for parseColorCallback

import SVGtoPDF from "svg-to-pdfkit";
import { load } from "color-books";

const getColor = (bookName, colorName: string) {
  const book = load(bookName);
  if (book.records[colorName]) {
    return {
      name: colorName,
      colorSpace: book.colorSpace,
      components: book.records[colorName].components,
      isSpot: book.isSpot
    };
  }
};

// <path d="..." fill="COLOR_BOOK(PANTONE+ CMYK Coated/PANTONE P 24-8 C)"></path>
const parseColorCallback = (color) => {
  const temp = color.match(/^COLOR_BOOK\((.+)\/(.+)\)$/);
  if (temp) {
    const [bookName, colorName] = temp.slice(1);
    return getColor(bookName, colorName);
  }
};

const draw = (doc, svg, { left, top, width, height }) => {
  doc.save();
  try {
    SVGtoPDF(doc, svg, left, top, {
      width,
      height,
      parseColorCallback
    });
  } finally {
    doc.restore();
  }
};

Example for getComputedStyleCallback

fs = require 'fs'
PDFDocument = require 'pdfkit'
SVGtoPDF = require 'svg-to-pdfkit'
open = require 'opn'
cheerio = require 'cheerio'
css = require 'css'

doc = new PDFDocument autoFirstPage: false

###
<svg>
    <defs>
        <style>
            .cls-1 {
                fill: red;
            }
            .cls-2 {
                stroke: yellow;
            }
        </style>
    </defs>
    <rect class="cls-1 cls-2" x="0" y="0" width="100" height="100" />
</svg>
###
svgContent = fs.readFileSync 'has-css.svg', 'utf8'

$ = cheerio.load svgContent, xmlMode: true

styles = reduce.call $('svg defs style').contents(), (sum, curr) ->
    if curr.type is 'text'
        sum += curr.data + '\n'
    sum
, ''

parsed = css.parse(styles)

cssProps = parsed.stylesheet.rules.reduce (propsBySelector, rule) ->
    if rule.type is 'rule'
        props = rule.declarations.reduce (sum, decor) ->
            sum[decor.property] = decor.value
            sum
        , {}

        for s in rule.selectors
            propsBySelector[s] = props
    propsBySelector
, {}

doc.pipe fs.createWriteStream 'output.pdf'

doc.addPage { size: [512, 512], margin: 0 }

getComputedStyleCallback = (node) ->
    if node.getAttribute('class')
        classNames = node.getAttribute('class').split(/\s/)
        styles = classNames.reduce((sum, name) ->
            name = '.' + name
            if cssProps[name]
                sum = { sum..., cssProps[name]... }
            sum
        , {})
        styles

SVGtoPDF doc, svgContent, 0, 0, { width: 200, height: 200, getComputedStyleCallback }
doc.end();

Insert SVG into a PDF document created with PDFKit.

Use:

SVGtoPDF(doc, svg, x, y, options);

    If you prefer, you can add the function to the PDFDocument prototype:

PDFDocument.prototype.addSVG = function(svg, x, y, options) {
  return SVGtoPDF(this, svg, x, y, options), this;
};

    And then simply call:

doc.addSVG(svg, x, y, options);

Parameters:

doc [PDFDocument] = the PDF document created with PDFKit
svg [SVGElement or string] = the SVG object or XML code
x, y [number] = the position where the SVG will be added
options [Object] = >
  - width, height [number] = initial viewport, by default it's the page dimensions
  - preserveAspectRatio [string] = override alignment of the SVG content inside its viewport
  - useCSS [boolean] = use the CSS styles computed by the browser (for SVGElement only)
  - fontCallback [function] = function called to get the fonts, see source code
  - imageCallback [function] = same as above for the images (for Node.js)
  - warningCallback [function] = function called when there is a warning
  - assumePt [boolean] = assume that units are PDF points instead of SVG pixels
  - precision [number] = precision factor for approximative calculations (default = 3)

Demos:

    https://alafr.github.io/SVG-to-PDFKit/examples/demo.htm

    https://alafr.github.io/SVG-to-PDFKit/examples/options.htm

Supported:

  • shapes: rect, circle, path, ellipse, line, polyline, polygon
  • special elements: use, nested svg
  • text elements: text, tspan, textPath
  • text attributes: x, y, dx, dy, rotate, text-anchor, textLength, word-spacing, letter-spacing, font-size
  • styling: with attributes only
  • colors: fill, stroke & color (rgb, rgba, hex, string), fill-opacity, stroke-opacity & opacity
  • units: all standard units
  • transformations: transform, viewBox & preserveAspectRatio attributes
  • clip paths & masks
  • images
  • fonts
  • gradients
  • patterns

Unsupported:

  • links (#18)
  • filters
  • text attributes: text-decoration, font-variant, writing-mode, unicode-bidi
  • foreignObject (#37)
  • other things I don't even know they exist

Warning:

  • Use an updated PDFKit version (≥0.8.1): see here how to build it, or use the prebuilt file in the examples folder.
  • There are bugs, please send issues and/or pull requests.

License:

    MIT

Other useful projects:

  • PDFKit, the JavaScript PDF generation library for Node and the browser.
  • For inserting SVG graphics into a PDFKit document there is also svgkit.
  • For the opposite conversion, from PDF to SVG, you can use Mozilla's PDF.js.