{
  "slug": "sign",
  "title": "pdf editor",
  "description": "Open a PDF and mark it up — signature, text, pen, highlight, boxes, lines, images — plus rotate, reorder, delete, append and extract pages. All in the browser.",
  "origin": "Started as a way to sign a PDF on an iPad with the Apple Pencil without a desktop app or uploading the file to someone's server, then grew into a full markup + page editor. The file never leaves the browser.",
  "category": "document",
  "status": "live",
  "url": "https://aaronchartier.com/tools/sign",
  "keywords": [
    "pdf",
    "sign",
    "signature",
    "annotate",
    "markup",
    "edit",
    "highlight",
    "text",
    "merge",
    "split",
    "rotate",
    "ipad",
    "apple pencil",
    "stylus",
    "fill"
  ],
  "privacy": "all computation is client-side; no input is transmitted",
  "pageApi": "window.__tools[\"sign\"] — run(input), describe(); output in #tool-output",
  "params": {
    "pdf": "ArrayBuffer | Uint8Array | base64 string — the PDF to edit",
    "ops": "array of edit ops applied in order (see the op table in the guide)"
  },
  "returns": "{ bytes: Uint8Array } — the edited PDF; interactive use downloads it directly",
  "async": true,
  "guide": "A PDF markup + page editor. Load a PDF, apply an ordered list of `ops`, get the edited bytes back. Annotation ops stamp content onto a page; structural ops rotate/remove pages. Ops apply in array order.\n\n**Coordinates are resolution-independent.** Every position/size is a fraction of the page in `[0,1]` with the origin at the **top-left** (x → right, y → down). `page` is **1-based**. `color` is a hex string; text `size` and shape `width` are fractions of the page height. Text is drawn in Helvetica.\n\n**Op types**\n\n| type | shape | does |\n| --- | --- | --- |\n| `text` | `{page, x, y, text, size?=0.03, color?=\"#000000\"}` | stamp text at (x,y) |\n| `signature` / `image` | `{page, x, y, w, h, png}` | place a PNG (`png` = data URL) in the box |\n| `draw` | `{page, points:[{nx,ny},…], color?, width?=0.004}` | freehand polyline |\n| `highlight` | `{page, x, y, w, h, color?=\"#ffe14d\"}` | translucent marker box |\n| `rect` | `{page, x, y, w, h, color?, width?}` | outlined rectangle |\n| `line` | `{page, x1, y1, x2, y2, color?, width?}` | straight line |\n| `rotate` | `{page, degrees}` | add rotation (rotates the page + its stamps) |\n| `deletePage` | `{page}` | drop a page from the output |\n\nNote: annotation ops target the **original** pages only (pages appended via the UI's \"append PDF\" aren't annotatable). The UI uses the same engine — anything the toolbar does maps to one of these ops.",
  "examples": [
    {
      "run": {
        "pdf": "<base64 PDF>",
        "ops": [
          {
            "type": "text",
            "page": 1,
            "x": 0.1,
            "y": 0.1,
            "text": "APPROVED",
            "color": "#0b3d91",
            "size": 0.04
          }
        ]
      },
      "note": "stamp a label near the top-left"
    },
    {
      "run": {
        "pdf": "<base64 PDF>",
        "ops": [
          {
            "type": "highlight",
            "page": 1,
            "x": 0.12,
            "y": 0.46,
            "w": 0.5,
            "h": 0.03
          },
          {
            "type": "rotate",
            "page": 1,
            "degrees": 90
          }
        ]
      },
      "note": "highlight a line, then rotate the page"
    },
    {
      "run": {
        "pdf": "<base64 PDF>",
        "ops": [
          {
            "type": "deletePage",
            "page": 2
          }
        ]
      },
      "note": "drop page 2"
    }
  ]
}