11 min read

How We Turn a PDF Into Handwriting in the Browser

How our PDF to handwriting engine works: glyph metrics, seeded variation, keeping the original layout, and learning letters from a photo, all client-side.

Quick answer

The engine turns each character into a stored glyph image with its own width, height and baseline offset, then places the glyphs with seeded random variation in rotation, baseline, size and pen pressure. To keep a PDF's layout, it renders each page with pdf.js, covers every text run with the paper colour sampled around it, and writes the handwriting into exactly the space the typed text occupied.

PDF to Handwriting is the second most visited tool on ihatepdf. You give it a PDF or some typed text and it gives back pages that look written by hand, either on notebook paper or in place on the original document with every image, table and margin where it was. It runs entirely in the browser: no model on a server, no upload, no account.

This post explains how it works. None of it is machine learning. It is glyph metrics, a seeded random number generator, a lot of canvas work, and one small use of OCR.

The pipeline at a glance

  1. Get the text. Typed text comes straight from the text box. For a PDF, pdf.js extracts every text run with its position, size and transform.
  2. Get a glyph for every character. Each character resolves to a stored image with a width, a height and a baseline offset: drawn by the user, learned from a photo of their handwriting, or rasterised from a handwriting font as a fallback.
  3. Lay the glyphs out. Notebook mode flows the text onto ruled paper. Keep-the-layout mode writes each run into the exact box the typed run occupied.
  4. Add variation. Every glyph gets a small, seeded change in rotation, baseline, scale and ink opacity, and repeated letters can use different variants.
  5. Write the PDF. Each page canvas is encoded as an image and placed on a page of the same size with pdf-lib.

A glyph is an image plus three numbers

The first version stored each letter as a bitmap and scaled every bitmap to the line height. It looked wrong immediately: a lowercase x came out as tall as a capital H, and descenders on g, p and y sat on the line instead of below it. Handwriting is legible because letters keep their proportions to an invisible baseline.

So every glyph is captured on a fixed 560-pixel square with two guide lines: the ascender line at 20% of the height and the baseline at 72%. The distance between them is the reference cap height, and every glyph is stored as {canvas, w, h, baseline}, where baseline is how far the baseline sits from the top of that glyph's own bounding box. At render time a single scale factor, font size divided by the reference cap height, is applied to everything, and each glyph is drawn at y = lineY - baseline * scale. Descenders fall below the line because their baseline offset is smaller than their height. That one change fixed every proportion problem at once.

Never fail a character: font fallback

Nobody draws 81 characters before trying a tool. If a character had no glyph, the first version left a gap. Now every missing character is rasterised from a handwriting font, Caveat, Patrick Hand or Dancing Script depending on the chosen style, into the same 560-pixel capture frame. The font is calibrated once so that its cap height lands exactly on the reference cap height, which means a font-generated "e" and a hand-drawn "R" share the same baseline and scale. Any character you do draw replaces the font's version for that character only.

One lesson from this part: we first used system font stacks, and on macOS all three styles silently resolved to the same installed font, so switching style changed nothing. The fonts are now loaded explicitly and the glyph cache is rebuilt once they are ready.

Variation that is random but repeatable

Handwriting is recognisable by its inconsistency. The renderer uses a small linear congruential generator seeded from the text and a user-controlled seed, and for each glyph draws a few numbers from it: a rotation around the slant angle, a baseline wobble of up to a few percent of the font size, a scale change of a few percent, and an ink opacity drop that reads as pen pressure. A slower "line wander" drifts the baseline across a line the way a real line of writing drifts. All of it is scaled by one "messiness" setting.

Seeding matters for two reasons. The live preview and the downloaded PDF must match exactly, and they do because they consume the same sequence. And a person who dislikes how a page came out can press Shuffle, which changes the seed and re-rolls every variation without changing anything else.

Each character can also hold up to three variants. When a page is laid out, a variant is chosen per occurrence before the width is measured, so the measurement and the drawing use the same glyph. Three different "e"s across a paragraph do more for realism than any amount of jitter on one.

Keeping the original layout

Most text-to-handwriting tools reflow everything onto lined paper. That is fine for notes and useless for a worksheet, a form or a slide. Keep-the-layout mode leaves the page alone and replaces only the typed text.

Each page is rendered with pdf.js at twice its size, capped at 4,000 pixels on the long side to stay inside mobile canvas limits. For every text run from getTextContent the renderer computes the run's box in canvas space, samples the paper colour just around it, and paints over the typed text with that colour. A run on a white page gets white, a heading on a coloured banner gets the banner's colour.

Then it decides the ink colour. Rather than writing everything in blue, it averages the pixels inside the run that differ clearly from the sampled background (a colour distance of more than 40), which gives the colour the typed text was printed in. White text on a dark banner stays white and grey captions stay grey.

Finally the handwriting has to fit. Each run is measured at its natural handwritten width and then compressed or stretched horizontally to the typed run's width, within limits of 0.32 to 1.18 times, so a line never spills into the next column or leaves a gap where a word was. The transform from pdf.js is applied first, so rotated and scaled text is written at the same angle and size.

Learning someone's handwriting from a photo

Drawing letters with a mouse is tedious, so the tool can also learn letters from a photo of a handwritten note. That part does use OCR, but only to find where letters are, not to generate anything.

The photo is cleaned first: a flat-field correction divides out uneven lighting and shadows, and Otsu's method picks the threshold between ink and paper. That gives two canvases, a transparent ink layer to cut glyphs from and a black-on-white copy for recognition. Tesseract.js reads the clean copy and returns a bounding box and confidence for each recognised symbol.

Cutting a letter out of a box is the easy part. Sizing it is the hard part. The first version normalised each line by its own cap height, which mis-sized any line written mostly in lowercase. The current version classifies every character typographically: x-height letters extend 0.54 of the reference height above the baseline, ascenders and capitals 1.0, descenders 0.54 above and 0.36 below, and punctuation has its own rules. Each glyph is scaled from its own ink bounds according to its class, so a photographed "n" and a photographed "B" come out in the right proportion. A connected-component pass removes strokes from neighbouring letters that strayed into a box, while keeping the dots on i and j.

The results go through a review step where the user can relabel or skip any letter before it is saved. Several photographed copies of the same letter become its variants.

What it does not do

Everything above runs in the page you are reading it from, which is why there is no upload step and no queue. The whole tool is at ihatepdf.cv/pdf-to-handwriting, and the typed-text version at ihatepdf.cv/text-to-handwriting.

Frequently asked questions

Does the PDF to handwriting tool use AI?

No generative model is involved. Letters come from your own drawings, from a photo of your handwriting, or from handwriting fonts, and realism comes from measured glyph proportions and seeded variation. OCR is used only to locate letters in a photo.

Why does the handwritten text keep the same layout as my PDF?

In keep-the-layout mode each typed run is painted over with the surrounding paper colour and the handwriting is fitted to that run's exact width, so images, tables and margins do not move.

Is the document uploaded anywhere?

No. Text extraction, rendering and PDF creation all happen in your browser, and the file never leaves your device.

→ Use these tools

PDF to Handwriting → Text to Handwriting → Handwriting to PDF →

Try all tools free — no sign-up, no watermark

40+ free PDF tools. Files never leave your device.

Open ihatepdf →

Related guides

How to Convert a PDF to Handwriting

The tool, from the user's side.

How to Make a Handwritten Assignment

Format, scan and submit.

Text to Handwriting Converter

Make typed text look handwritten.