New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

masax-drawpdf

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

masax-drawpdf

PDF Template Builder - CKEditor to PDF with Vietnamese support, template engine with variables, loops, conditionals

latest
Source
npmnpm
Version
2.2.4
Version published
Maintainers
1
Created
Source

DrawPDF

📄 PDF Template Builder - Convert HTML templates to PDF with Vietnamese support, variables, loops, and conditionals.

npm version npm downloads jsdelivr hits License: MIT

✨ Features

  • HTML to PDF - Parse CKEditor/HTML content to structured JSON, then render to PDF
  • Template Engine - Variables {{name}}, loops {{#each}}, conditionals {{#if}}
  • Vietnamese Support - Full Unicode support with Roboto/Tahoma fonts
  • Rich Text - Bold, italic, underline, colors, font sizes
  • Tables - With colspan, rowspan, borders, colors
  • Code Eval - Execute JavaScript in templates for dynamic content

📦 Installation

# npm
npm i masax-drawpdf

# or from git
npm install github:masax/DrawPDF#main

Peer Dependencies:

  • jspdf ^2.5.1
  • jspdf-autotable ^3.8.1

🔤 Font Configuration

Default Behavior

By default, DrawPDF uses Roboto font (Vietnamese support built-in) with helvetica as fallback.

Custom Font Configuration

import DrawPDF from "drawpdf";

const pdf = await DrawPDF.create("#editor", {
  fonts: {
    defaultFont: "MyCustomFont", // Primary font name
    fallback: "helvetica", // Fallback if font not found
    register: [
      // Pre-converted font files (.js)
      "/fonts/MyCustomFont-Regular.js",
      "/fonts/MyCustomFont-Bold.js",
    ],
  },
});

Dynamic Font Registration

// Register font at runtime
await pdf.registerFont("/fonts/AnotherFont.js");

Creating Custom Font Files

🌐 Browser Usage (UMD)

For direct usage in the browser without a bundler, use the standalone build which includes all dependencies (jspdf, jspdf-autotable).

<!-- Load the standalone script -->
<script src="./dist/drawpdf.standalone.umd.cjs"></script>

<script>
  // Access via global variable 'DrawPDF'
  const { DrawPDF } = window.DrawPDF;

  // Initialize
  DrawPDF.create("#editor").then((pdf) => {
    console.log("Ready!");
  });
</script>

🚀 Quick Start

Design Mode (Thiết kế template với CKEditor)

import DrawPDF from "drawpdf";

// 1. Khởi tạo CKEditor
const pdf = await DrawPDF.create("#editor");

// 2. User soạn thảo trong editor...

// 3. Lấy JSON Blueprint từ editor
const blueprint = pdf.getData();

// 4. Save blueprint để dùng sau
localStorage.setItem("myTemplate", JSON.stringify(blueprint));

// 5. Preview PDF
pdf.preview({ name: "Test", salary: 25000000 });

Print Mode (In PDF từ blueprint có sẵn) ⭐

Đây là use case phổ biến nhất: Bạn đã có file blueprint.json và chỉ cần in ra PDF!

import DrawPDF from "drawpdf";

// 📂 Cách 1: Load blueprint từ file/localStorage
const blueprint = JSON.parse(localStorage.getItem("myTemplate"));
// hoặc: const blueprint = await fetch('/templates/invoice.json').then(r => r.json());

// 🖨️ In ngay! Không cần CKEditor
new DrawPDF().setData(blueprint).download("document.pdf", {
  name: "Nguyễn Văn An",
  salary: 25000000,
  items: [
    { name: "Sản phẩm A", price: 100000 },
    { name: "Sản phẩm B", price: 200000 },
  ],
});

Hoặc dùng Static Method (1 dòng):

DrawPDF.downloadBlueprint(blueprint, "output.pdf", { name: "Test" });

Các cách xuất khác:

const pdf = new DrawPDF().setData(blueprint);

// Render và lấy data URL (để preview trong iframe)
const dataUrl = pdf.render(data);
document.getElementById("preview").src = dataUrl;

// Lấy Blob (để upload lên server)
const blob = pdf.getBlob(data);
await fetch("/api/upload", { method: "POST", body: blob });

// Mở preview trong tab mới
pdf.preview(data);

📚 API Reference - DrawPDF Class

Instance Methods (Main API)

MethodDescriptionReturns
init(element, options)Khởi tạo CKEditor vào elementPromise<DrawPDF>
getData()Parse HTML từ editor → JSON BlueprintObject (Blueprint)
setData(blueprint)Load blueprint có sẵn để renderDrawPDF (chainable)
render(data)Render PDF từ blueprintstring (data URL)
download(filename, data)Tải PDF xuốngDrawPDF (chainable)
preview(data)Mở PDF trong tab mớivoid
getBlob(data)Lấy Blob để uploadBlob
getBlueprint()Lấy blueprint hiện tại (không parse lại)Object or null
exportJson()Xuất blueprint dạng JSON stringstring
importJson(jsonString)Import blueprint từ JSON stringDrawPDF (chainable)
registerFont(url)Đăng ký font tùy chỉnhPromise<DrawPDF>
destroy()Hủy editor instancevoid

Static Methods (Headless - Không cần CKEditor)

MethodDescription
DrawPDF.create(element, options)Factory method: new DrawPDF().init()
DrawPDF.parseHtml(html)Parse HTML → Blueprint
DrawPDF.renderBlueprint(blueprint, data)Render blueprint → data URL
DrawPDF.downloadBlueprint(blueprint, filename, data)Download PDF ngay từ blueprint

Workflow Comparison

┌─────────────────────────────────────────────────────────────────┐
│  🎨 DESIGN MODE (Có CKEditor)                                   │
│  ───────────────────────────────                                │
│  DrawPDF.create('#editor')                                      │
│    → User soạn thảo trong editor                                │
│    → pdf.getData() → Lấy blueprint                              │
│    → Lưu blueprint.json                                         │
└─────────────────────────────────────────────────────────────────┘
                              ↓ blueprint.json
┌─────────────────────────────────────────────────────────────────┐
│  🖨️ PRINT MODE (Không cần CKEditor)                             │
│  ─────────────────────────────────                              │
│  new DrawPDF()                                                  │
│    .setData(blueprint)      ← Load blueprint có sẵn             │
│    .download('file.pdf', {  ← Truyền data vào                   │
│        name: 'Nguyễn Văn An',                                   │
│        salary: 25000000                                         │
│    });                                                          │
└─────────────────────────────────────────────────────────────────┘

📖 Advanced API

CKEditorParser

import { CKEditorParser, PDFRenderer } from "drawpdf";

const parser = new CKEditorParser();
const renderer = new PDFRenderer();

const blueprint = parser.parse("<h1>Hello</h1>");
renderer.render(blueprint, { name: "World" });
renderer.download("output.pdf");

CKEditorParser

import { CKEditorParser, PAGE, FONTS } from "drawpdf";

const parser = new CKEditorParser();
const blueprint = parser.parse(htmlString);

// Constants
console.log(PAGE.WIDTH); // 210 (A4 mm)
console.log(FONTS.DEFAULT_SIZE); // 12

PDFRenderer

import { PDFRenderer } from "drawpdf";

const renderer = new PDFRenderer();

// Render blueprint with data
renderer.render(blueprint, data);

// Output methods
renderer.download("file.pdf"); // Download file
renderer.getDataUrl(); // Get data URL for preview
renderer.getBlob(); // Get Blob for upload
renderer.preview(); // Open in new tab

JsPdfService

Low-level wrapper with 88+ methods for direct PDF manipulation.

import { JsPdfService } from "drawpdf";

const pdf = new JsPdfService();

pdf.addTitle("Document Title");
pdf.addText("Hello World", null, null, { fontSize: 14 });
pdf.addTable(
  ["Col1", "Col2"],
  [
    ["A", "B"],
    ["C", "D"],
  ],
);
pdf.addSpace(10);
pdf.addHorizontalLine();
pdf.addNewPage();
pdf.savePDF("output.pdf");

TemplateEngine

Process template syntax independently.

import { TemplateEngine } from "drawpdf";

const result = TemplateEngine.process("Hello {{name}}!", { name: "World" });
// "Hello World!"

📝 Template Syntax

Variables

{{name}}
<!-- Simple -->
{{employee.department.name}}
<!-- Nested -->

Loops

{{#each items}} - {{name}}: {{formatCurrency price}}{{br}} {{/each}}

Loop variables: {{@index}}, {{@first}}, {{@last}}

Conditionals

{{#if isActive}}Active{{else}}Inactive{{/if}} {{#if salary > 10000000}}High
salary{{/if}}

Format Helpers

HelperExample
{{formatNumber num}}10000001.000.000
{{formatCurrency num}}10000001.000.000đ
{{formatDate date}}2026-01-2929/01/2026
{{uppercase text}}helloHELLO
{{capitalize text}}hello worldHello World

Date Helpers

HelperOutput
{{today}}29/01/2026
{{now}}29/01/2026, 13:45
{{year}}2026

Layout Tags

TagEffect
{{br}}Line break
{{tab}}Tab (4 spaces)
{{hr}}Horizontal line
{{pageBreak}}New page

� Blueprint JSON Structure

Blueprint là định dạng trung gian giữa HTML và PDF. Đây là output của getData() và input của setData().

Cấu trúc cơ bản

{
  "version": "1.0",
  "pageSize": { "width": 210, "height": 297, "unit": "mm" },
  "margins": { "top": 20, "bottom": 20, "left": 15, "right": 15 },
  "pages": [
    {
      "pageNumber": 1,
      "elements": [
        { "type": "richtext", "x": 15, "y": 20, "segments": [...] },
        { "type": "table", "x": 15, "y": 50, "rows": [...] }
      ]
    }
  ],
  "sourceHtml": "<p>Original HTML...</p>",
  "createdAt": "2026-01-30T07:00:00Z"
}

Element Types

TypeDescriptionKey Properties
richtextĐoạn văn bản có định dạngsegments[] (text, style), content, style
tableBảng với cellsrows[][], style, rowHeight
headingTiêu đề H1-H6level, content, style
listDanh sách ul/olitems[], listType
imageHình ảnhsrc, width, height
codeCode blockcode, language

Ví dụ RichText Element

{
  "type": "richtext",
  "x": 15,
  "y": 20,
  "width": 180,
  "segments": [
    { "text": "Xin chào ", "style": { "bold": false } },
    { "text": "{{name}}", "style": { "bold": true, "color": "#0000ff" } },
    { "text": "!", "style": { "bold": false } }
  ],
  "style": {
    "fontSize": 12,
    "align": "left",
    "lineHeight": 6.35
  }
}

---

## �🔥 Code Block Eval

Execute JavaScript directly in templates with `// eval`:

```javascript
// eval
const total = sum(data.items, 'price');
pdf.addText('Total: ' + formatCurrency(total));

pdf.addTable(
  ['Item', 'Price'],
  data.items.map(i => [i.name, formatCurrency(i.price)])
);

Available in eval:

  • pdf - JsPdfService instance
  • data - Template data
  • formatNumber(), formatCurrency(), sum(), count()

🛠 Development

# Clone
# git clone https://github.com/masax/DrawPDF.git
# cd DrawPDF/pdf-builder

# Install
npm install

# Dev server
npm run dev

# Build library
npm run build

📁 Project Structure

draw-pdf/
├── src/
│   ├── index.js              # Library entry point
│   ├── DrawPDF.js            # Main Class Wrapper
│   ├── parser/
│   │   ├── CKEditorParser.js # HTML → JSON Blueprint
│   │   └── RichTextTokenizer.js
│   ├── renderer/
│   │   └── PDFRenderer.js    # Blueprint → PDF
│   ├── service/
│   │   └── jspdf-service/main.js  # jsPDF wrapper (3000+ lines)
│   └── utils/
│       └── TemplateEngine.js # Template processing
├── docs/                     # Documentation & Examples
│   └── index.html            # Main demo
├── dist/                     # Build output
│   ├── drawpdf.js           # ES Module
│   └── drawpdf.umd.cjs      # CommonJS
└── public/fonts/             # Vietnamese fonts

📄 License

MIT License

Keywords

pdf

FAQs

Package last updated on 09 Feb 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts