tinypdf

repository·main·Indexed 23 days ago

https://github.com/lulzx/tinypdf

A minimal, zero-dependency PDF creation library (v0.3.1) designed for high performance and small bundle size. It provides a PDFBuilder for placing text, JPEG images, and vector shapes (rectangles, lines) on pages. Features include a markdown-to-PDF converter supporting headers, lists, and horizontal rules, as well as a buildStream method for streaming large documents as a ReadableStream<Uint8Array> to save memory.

Tokens
2.4K
Snippets
10
Records
19
Agent score
34%

What's inside tinypdf

  1. Quick start with tinypdf

    main

    To create a basic PDF, import pdf from tinypdf, initialize a document, and use doc.page() to define a drawing context. Within the callback, you can use methods like ctx.rect, ctx.text, and ctx.line to draw elements. Finally, call doc.build() to get a Uint8Array of the PDF content.

    import { pdf } from 'tinypdf'
    import { writeFileSync } from 'fs'
    
    const doc = pdf()
    
    doc.page((ctx) => {
      ctx.rect(50, 700, 200, 40, '#2563eb')           // blue rectangle
      ctx.text('Hello PDF!', 60, 712, 24, { color: '#ffffff' })
      ctx.line(50, 680, 250, 680, '#000000', 1)       // black line
    })
    
    writeFileSync('output.pdf', doc.build())
  2. Stream large PDFs to save memory

    main

    For documents that are too large to fit in memory, use doc.buildStream() instead of doc.build(). This returns a ReadableStream<Uint8Array> that emits the PDF data one object at a time, making it suitable for writing to disk or serving via HTTP.

    import { pdf } from 'tinypdf'
    
    const doc = pdf()
    for (let i = 0; i < 10_000; i++) {
      doc.page((ctx) => ctx.text(`Page ${i + 1}`, 50, 750, 12))
    }
    
    // Write to disk (Bun)
    await Bun.write('huge.pdf', doc.buildStream())
    
    // Or serve as an HTTP response
    return new Response(doc.buildStream(), {
      headers: { 'Content-Type': 'application/pdf' },
    })
  3. Add clickable links to a PDF

    main

    To add a clickable URL, use ctx.link(url, x, y, w, h, options?). A common pattern is to use measureText to determine the width of the text being linked to ensure the clickable area matches the text size.

    import { pdf, measureText } from 'tinypdf'
    
    doc.page((ctx) => {
      const text = 'Visit Example.com'
      const y = 700
      ctx.text(text, 50, y, 14, { color: '#0066cc' })
      ctx.link('https://example.com', 50, y - 4, measureText(text, 14), 18, { underline: '#0066cc' })
    })
  4. Add JPEG images to a PDF

    main

    You can add JPEG images to a page using ctx.image(). This method requires a Uint8Array of the JPEG bytes.

    import { readFileSync } from 'fs'
    
    doc.page((ctx) => {
      const logo = new Uint8Array(readFileSync('logo.jpg'))
      ctx.image(logo, 50, 700, 100, 50)
    })
  5. Measure text width in points

    main

    Use measureText(str, size) to calculate the width of a string in points for a given font size. This is useful for alignment and calculating link bounding boxes.

    import { measureText } from 'tinypdf'
    
    measureText('Hello', 12) // => 27.34 (points)
  6. Convert Markdown to PDF

    main

    The markdown(str, options?) function allows you to generate a PDF directly from a markdown string. It supports headers (h1, h2, h3), bullet lists, numbered lists, and horizontal rules. It includes automatic word wrapping and pagination.

    Options include width, height, and margin.

    import { markdown } from 'tinypdf'
    import { writeFileSync } from 'fs'
    
    const pdf = markdown(`
    # Hello World
    
    A minimal PDF from markdown.
    
    ## Features
    - Headers (h1, h2, h3)
    - Bullet lists
    - Numbered lists
    - Horizontal rules
    
    ---
    
    Automatic word wrapping and pagination included.
    `)
    
    writeFileSync('output.pdf', pdf)
  7. Reference: Drawing Context (ctx) API

    main

    Methods available within the doc.page callback to draw elements on the page.

    ctx.text(str, x, y, size, options?)        // options: { color, align, width }
    ctx.rect(x, y, w, h, fill)                 // filled rectangle
    ctx.line(x1, y1, x2, y2, stroke, width?)   // line
    ctx.image(jpegBytes, x, y, w, h)           // JPEG image
    ctx.link(url, x, y, w, h, options?)        // options: { underline }
  8. Reference: Document and Page API

    main

    Methods for managing the PDF document and its pages.

    pdf()                                      // create document
    doc.page(callback)                         // add page (612×792 default)
    doc.page(width, height, callback)          // add page with custom size
    doc.build()                                // returns Uint8Array
    doc.buildStream()                          // returns ReadableStream<Uint8Array>
  9. Convert Markdown to PDF with markdown()

    main

    A high-level utility to convert a Markdown string directly into a Uint8Array PDF document.

    Parameters:

    • md: The Markdown string.
    • opts?: { width?: number; height?: number; margin?: number }: Document dimensions and margins. Defaults are width: 612, height: 792, and margin: 72.

    Supported Markdown Features:

    • Headers (# to ######)
    • Lists (-, *, or 1. )
    • Horizontal rules (---, ***, or ___)
    • Paragraphs
    • Blank lines