The most reliable fix is to stop rasterizing text. If your PDF is made with doc.text(), jsPDF can store the characters as vector text that stays sharp and selectable at any zoom. If you first render HTML into a canvas, call addSvgAsImage(), or insert a canvas data URL, the PDF contains pixels; its maximum clarity is limited by the source canvas resolution.
Use this sequence: identify whether the page is vector or raster, use native jsPDF text where possible, enable px_scaling when your coordinates are CSS pixels, increase the html2canvas scale when an image is unavoidable, embed a font with the required glyphs, and inspect the result at 100% and at its intended print size.
First, determine why the text is blurry
Open the PDF in a viewer and try to select a word. If you can select individual characters, the text is probably native PDF text. Zoom in: vector glyph edges remain clean. If clicking selects one large rectangle, or if zooming reveals square pixels, the page is an image. A PDF wrapper does not turn a low-resolution screenshot into vector text.
| Pipeline | What the PDF contains | Typical symptom | Best fix |
|---|---|---|---|
doc.text() and jsPDF font APIs |
Vector text operators | Usually sharp and searchable | Correct font, size, units, and coordinates |
html2canvas followed by addImage() |
One raster image (or several) | Pixels appear when zoomed or printed | Increase source canvas resolution, or keep text native |
addSvgAsImage() or canvas data URL |
Image content in the resulting page | Sharpness depends on generated image dimensions | Raise raster resolution; do not expect vector text |
Use native jsPDF text whenever the layout allows
Recreate headings, labels, body copy, and simple tables with jsPDF drawing commands instead of taking a screenshot of the entire DOM. This preserves search, copy, accessibility features supported by the viewer, and sharp output at arbitrary zoom.
Recommended Free Tools
#1 Best Overall
- EDIT text, images & designs in PDF documents. ORGANIZE PDFs. Convert PDFs to Word, Excel & ePub.
- READ and Comment PDFs – Intuitive reading modes & document commenting and mark up.
- CREATE, COMBINE, SCAN and COMPRESS PDFs
- FILL forms & Digitally Sign PDFs. PROTECT and Encrypt PDFs
- LIFETIME License for 1 Windows PC or Laptop. 5GB MobiDrive Cloud Storage Included.
import { jsPDF } from 'jspdf';
const doc = new jsPDF({
unit: 'pt',
format: 'a4',
putOnlyUsedFonts: true,
floatPrecision: 16
});
doc.setFont('helvetica', 'normal');
doc.setFontSize(12);
doc.text('Sharp, selectable PDF text', 72, 72);
doc.save('sharp-text.pdf');
Use setFont(), setFontSize(), text(), and explicit coordinates for the portions that must remain crisp. You can still place photos, charts, or decorative artwork as images; mixing vector text and raster graphics is often the best compromise when CSS layout is too complex to reproduce manually.
Correct CSS-pixel units with the px_scaling hotfix
Many browser layouts are measured in CSS pixels, so developers construct jsPDF with unit: 'px'. Older or mismatched scaling calculations can make drawn components larger than intended and can make text appear to have the wrong size. The jsPDF hotfix documentation describes the problem as an incorrectly calculated internal scale when px is supplied as the unit; enabling px_scaling corrects that calculation.
import { jsPDF } from 'jspdf';
const doc = new jsPDF({
unit: 'px',
hotfixes: ['px_scaling']
});
doc.setFont('helvetica', 'normal');
doc.setFontSize(16);
doc.text('CSS-pixel coordinates with corrected scaling', 24, 40);
doc.save('px-scaled.pdf');
Do not combine arbitrary conversion factors with the hotfix. Pick one coordinate system, convert measurements once at the boundary of your layout code, and use the same system for text, lines, images, and page breaks.
Make an html2canvas export sharper when rasterization is required
Some pages depend on CSS features, positioned elements, or third-party widgets that you cannot conveniently rebuild with jsPDF primitives. In that case, increase the number of physical pixels in the source canvas before adding it to the PDF.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →import html2canvas from 'html2canvas';
import { jsPDF } from 'jspdf';
const element = document.querySelector('#invoice');
const canvas = await html2canvas(element, {
scale: Math.max(2, window.devicePixelRatio || 1),
useCORS: true
});
const image = canvas.toDataURL('image/png');
const pdf = new jsPDF({ unit: 'pt', format: 'a4' });
pdf.addImage(image, 'PNG', 0, 0, 595.28, 841.89);
pdf.save('rasterized-page.pdf');
The scale value is a starting point, not a universal guarantee. A larger scale creates more pixels and usually improves small type, but it also increases memory use, rendering time, and PDF size. Choose it from the target page dimensions, expected print size, amount of text, and the browser’s available memory. Raising scale cannot make the result selectable text and cannot recover detail that was absent from the original DOM or font render.
Keep the displayed image size honest
Do not stretch a small canvas to fill a large PDF area. A canvas has pixel dimensions (canvas.width and canvas.height) and a CSS display size; those are not interchangeable. Decide the physical size in points or millimetres, then ensure the canvas has enough pixels for that size. For text-heavy captures, PNG avoids JPEG compression around glyph edges and preserves transparency. JPEG can be smaller for photographic pages but may add ringing and blur to fine text.
Watch for browser and cross-origin limits
Images without appropriate cross-origin permissions may be omitted or may taint the canvas, preventing toDataURL(). The useCORS option helps only when the remote server supplies compatible CORS headers. Ensure fonts and images have finished loading before capture, and wait for lazy content to appear; otherwise you may be increasing the resolution of an incomplete page.
Embed a font that contains every glyph you use
The jsPDF README notes that its 14 standard PDF fonts are limited to the ASCII code page. Accented characters, non-Latin scripts, symbols, and many emoji require an integrated font with those glyphs. A missing glyph can look like a blank box, substitution, or inconsistent rendering rather than ordinary blur.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsRank #2
- Edit PDFs with Ease. Modify text, images, and layouts directly within your PDF documents.
- Convert & Organize. Export PDFs to Word, Excel, or ePub, and organize files with ease.
- Read & Annotate. Enjoy intuitive reading modes and powerful tools to comment, highlight, and mark up PDFs.
- Create & Manage PDFs. Create new PDFs, combine multiple files, scan documents, and compress for easy sharing.
- Fill & Sign Forms. Complete forms and digitally sign documents with secure e-signature tools.
- Choose a TTF (or a converted font) that covers every character in your document.
- Use jsPDF’s font converter, or load the TTF binary and register it with
addFileToVFS()andaddFont(). - Call
setFont()with the registered family and style before writing text. - Test real production strings, including accents, CJK characters, right-to-left text where applicable, and symbols.
// Outline only: the TTF data must be loaded by your application.
doc.addFileToVFS('MyFont.ttf', fontBinary);
doc.addFont('MyFont.ttf', 'MyFont', 'normal');
doc.setFont('MyFont', 'normal');
doc.setFontSize(12);
doc.text('Text with the required glyphs: café — 示例', 72, 100);
Embedding increases the document size, but it is preferable to replacing unsupported characters or rasterizing an entire page to hide font problems.
Use precision settings deliberately
jsPDF exposes precision, userUnit, and floatPrecision. Keep their defaults unless you have measured a specific problem. Repeatedly rounding coordinates in application code can accumulate visible alignment errors and uneven baselines; retain full-precision layout values and round only where a format or design requirement demands it. floatPrecision can affect coordinate serialization and file size, but it does not turn raster text into vector text.
Do not rely on non-uniform text transforms as the first fix
Scaling text horizontally with a transform is tempting when a line does not fit. The project documents text-scaling options, and an issue reports a matrix intended to scale text horizontally having no visible effect. Remove the transform while diagnosing the problem. Choose a suitable font size, adjust margins or line breaks, or redesign the layout first. A transform that appears to work in one viewer may render differently in another.
Compare the fixes by the result you need
| Approach | Selectable/searchable | Zoom and print sharpness | Memory and file-size trade-off | When to choose it |
|---|---|---|---|---|
Native doc.text() |
Yes | Vector sharpness | Usually efficient; embedded fonts add size | Headings, labels, paragraphs, and structured data |
| html2canvas at higher scale | No | Better, but limited by pixels | More RAM, CPU, and image data | Complex CSS that cannot be rebuilt natively |
| Low-resolution canvas enlarged in PDF | No | Blurry or pixelated | Small source, poor output | Avoid except for intentionally small previews |
| Native text plus raster graphics | Text only | Text stays vector; graphics depend on source | Balanced | Most mixed-content reports and invoices |
A repeatable debugging workflow
- Inspect selection: determine whether the PDF contains characters or one page image.
- Check units: if using CSS pixels, add
hotfixes: ['px_scaling']and remove duplicate conversion math. - Separate text from artwork: render text with jsPDF APIs and keep only genuinely complex regions as images.
- Check dimensions: compare canvas pixel width and height with the PDF display size; do not upscale a small canvas.
- Raise scale gradually: try a larger html2canvas scale while monitoring memory and generation time.
- Check fonts: verify that the selected embedded font contains every character and that it is selected before
text(). - Inspect transforms and rounding: remove horizontal scaling matrices and avoid repeated coordinate rounding.
- View correctly: inspect at 100% and at intended print size, then print a representative page if physical output matters.
Troubleshooting common symptoms
Text is blurry only after HTML capture
The page is rasterized. Replace important text with native jsPDF text, or increase html2canvas’s scale and ensure the resulting canvas is not enlarged beyond its intended physical size.
Everything is the wrong size when using unit: 'px'
Enable hotfixes: ['px_scaling']. Then check that your code is not applying an additional CSS-pixel-to-point multiplier.
Letters are missing or replaced by boxes
The selected standard font lacks the glyphs. Embed a suitable TTF with addFileToVFS() and addFont(), select it with setFont(), and test the exact production text.
Increasing scale causes crashes or very slow exports
The larger canvas may exceed browser memory. Reduce the capture region, process pages separately, lower the scale until it fits, or use native text for the high-volume portions. Do not assume a higher value is always better.
Text looks different in different PDF viewers
Remove non-uniform transforms, embed the font, use stable units, and avoid relying on viewer-specific fallback glyphs. Compare the same file at 100% and in print preview.
Rank #3
- EVERY PDF TOOL UNLOCKED - 30+ tools in one app: edit text and images, convert, merge, split, compress, sign, OCR, redact, watermark, batch process, and more. No feature gates, no upsells, nothing held back.
- PAY ONCE, OWN FOREVER — A one-time purchase, not a subscription. Other apps runs $240/year — Scrivar is yours for life, with free updates included.
- UNLIMITED eSIGN, BUILT IN — Send contracts and forms for signature and track every step. Recipients sign in their browser with no account or app needed. Replace DocuSign and save hundreds a year.
- PC, MAC, AND WEB — Install on any Win 10/11 PC or macOS 11+ Mac (Intel or Apple Silicon), or work in your browser at scrivar.com. Same tools, same account, everywhere you work.
- OCR + FULL OFFICE CONVERSION — Turn scanned documents into searchable, selectable text, and convert PDFs to and from Word, Excel, and PowerPoint with formatting kept intact.
The PDF is sharp but text cannot be searched
That is expected for an image-only PDF. A high-resolution PNG improves appearance but does not add a text layer; rebuild the text with jsPDF APIs or add a separate accessible text workflow.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
For a website screenshot or rendered page where you do not want to maintain browser-capture code, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one request. It accepts cookie and consent banners as a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and each response identifies the result with X-Page-Verdict and X-Billed headers.
See the complete parameter list in the ScreenshotNeo documentation. A cURL request is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
The same call in Python:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
And in Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const bytes = new Uint8Array(await res.arrayBuffer());
// Save bytes with your application’s file API.
ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Every feature is available on every plan: 1,000 screenshots per month are free with no card, and paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →FAQ
Frequently Asked Questions
Does increasing jsPDF’s PDF resolution make native text sharper?
Native text is already vector-based; increasing raster resolution does not improve it. Resolution changes matter when the page or text was rendered into an image first.
Should I use SVG instead of a canvas to avoid blur?
Only if your SVG remains vector content in the final PDF path. In the documented jsPDF workflow, treat addSvgAsImage() as image content and verify the resulting PDF by selecting text and zooming.
What is the best unit for a print-oriented PDF?
Points are a straightforward choice because PDF page formats are defined physically. CSS-pixel layouts can work when you enable px_scaling and keep conversions consistent.
Can a PDF viewer itself cause blurry text?
Viewer zoom and display interpolation can affect what you see on screen. Check at 100% and in print preview, and use text selection to distinguish viewer display from an image-only PDF.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

