Recommended Free Tools
Blurry jsPDF text usually has one of two causes: the PDF contains a low-resolution image of the page, or CSS-pixel dimensions are being scaled incorrectly. First determine which output you made. Text added with doc.text() is vector text and should remain crisp and selectable. Output produced through html2canvas, canvas.toDataURL(), addImage(), or addSvgAsImage() is raster content, so its sharpness is limited by the source canvas pixels. Use native jsPDF text whenever the layout permits; if rasterization is required, increase the canvas resolution without enlarging the image beyond its effective print resolution.
1. Identify whether the PDF contains text or an image
Open the PDF in a viewer and try to select a word. If individual characters can be selected and searched, the page contains PDF text. Zooming should keep the letter edges clean. If the entire page selects as one object, or selection is impossible, you exported a bitmap. Zooming a bitmap eventually reveals pixels regardless of the PDF page size.
- Vector path:
doc.text(),setFont(),setFontSize(), and embedded fonts. - Raster path: html2canvas, a canvas data URL,
addImage(), or an SVG converted to an image.
This distinction determines the fix. No amount of PDF viewer zooming or metadata changes can restore detail that was never present in a raster source.
2. Prefer native jsPDF text
Rebuild headings, labels, table values, and body copy with jsPDF text APIs instead of taking a screenshot of the entire HTML page. Native text is selectable, searchable, generally smaller, and remains sharp at high zoom and print size.
#1 Best Overall
Minimal sharp-text example
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 points, millimetres, or another deliberate physical unit for the document and calculate positions consistently. Keep the documented defaults for precision, userUnit, and floatPrecision unless measurements show that a change is needed. Repeatedly rounding coordinates in application code can create visible alignment errors, but increasing numeric precision cannot turn an image into vector text.
When native text is not a drop-in replacement
Complex CSS layout, filters, gradients, web fonts, and browser-only line wrapping may not reproduce exactly with jsPDF primitives. In those cases, keep only the genuinely visual parts as images and draw important labels or captions as native text over them. This hybrid approach preserves searchable text while limiting raster content.
3. Correct CSS-pixel units with the px_scaling hotfix
If you construct jsPDF with unit: 'px', enable the documented px_scaling hotfix:
import { jsPDF } from 'jspdf';
const doc = new jsPDF({
unit: 'px',
hotfixes: ['px_scaling']
});
The jsPDF HOTFIX documentation explains that, without this option, the internal scaling factor for the px unit was miscalculated, making drawn components larger than intended. The hotfix corrects that calculation; it does not increase raster resolution or make text vector-based.
Check for unit mismatches
- Do not pass CSS pixel coordinates to a document configured in points or millimetres without converting them.
- Do not use a canvas pixel width as though it were a physical PDF width unless you have chosen the intended print size.
- Keep the same unit assumptions for margins, font sizes, image placement, and page breaks.
4. Increase html2canvas resolution when raster output is required
When the design must be captured as a browser-rendered image, raise html2canvas’s scale. The canvas then contains more physical pixels before it is converted to a data URL and inserted into the PDF.
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');
A scale of 2 is a practical starting point, not a universal guarantee. Choose it from the target page dimensions, expected print resolution, amount of text, browser memory, and the number of pages. A scale of 3 or 4 can improve small type but may cause large canvases, slow rendering, or memory failures. Test the actual longest page rather than assuming the first page represents the whole document.
Calculate an honest display size
A low-resolution canvas enlarged to fill an A4 page will look soft. Keep the displayed physical size proportional to the canvas pixel dimensions and intended output resolution. For text-heavy screenshots, PNG avoids JPEG compression halos and preserves transparent or high-contrast edges. JPEG can be smaller for photographic content but is usually a poor choice for fine black text on a light background.
SVG and canvas caveat
addSvgAsImage and canvas-to-data-URL workflows still create raster output in the PDF. Increasing the source scale can improve the result, as documented in the jsPDF issue discussing this approach, but it does not make the resulting text vector text. If selectable text matters, use native jsPDF text or a PDF workflow that preserves SVG/text objects.
5. Load a font with the glyphs you actually use
Sharp geometry is not enough if the font is substituted or characters are missing. jsPDF’s README notes that its 14 standard PDF fonts are limited to the ASCII code page. Unicode text requires an integrated font containing the required glyphs.
Embedding workflow
- Obtain a suitable TrueType (
.ttf) font with licensing that permits embedding. - Use the jsPDF font converter or load the TTF as binary data.
- Register it with
addFileToVFS()andaddFont(). - Select the registered family and style with
setFont()before drawing text. - Test every language, symbol, emoji, and combining mark your application emits.
// Outline; font data loading is application-specific.
doc.addFileToVFS('MyFont.ttf', fontBinary);
doc.addFont('MyFont.ttf', 'MyFont', 'normal');
doc.setFont('MyFont', 'normal');
doc.text('Unicode: café — 東京', 72, 110);
If glyphs appear as boxes, disappear, or trigger fallback, inspect font coverage before changing image scale. A fallback font can also alter line breaks and make text appear to have the wrong size.
6. Avoid relying on text transforms to repair softness
Non-uniform text transforms are a fragile first-line fix. The project documents text scaling options, and an issue reports a matrix intended to scale text horizontally having no visible effect. Remove the transform, choose an appropriate font size, adjust the layout, or use a font with the desired proportions. Do not assume a transform has been applied merely because the call succeeds.
7. Verify sharpness at useful viewing scales
- Inspect at 100% zoom to check normal reading quality.
- Inspect at the intended print size; a high-zoom view can exaggerate harmless anti-aliasing.
- Try selecting and copying a sentence.
- Search for a distinctive word.
- Zoom substantially. Vector edges should remain clean; a raster page will eventually show pixels.
- Check a page containing the smallest type, not just a cover page.
8. Troubleshooting by symptom
| Symptom | Likely cause | Fix |
|---|---|---|
| Entire page is one selectable image | html2canvas or canvas data URL | Draw text with doc.text(); otherwise increase html2canvas scale and keep the image size honest. |
Text is the wrong physical size with unit: 'px' |
Incorrect pixel scaling | Add hotfixes: ['px_scaling'] and audit unit conversions. |
| Small type looks soft after scaling | Insufficient source pixels | Increase canvas scale, reduce the placed image size, or switch that text to native PDF text. |
| Letters are missing or boxes appear | Standard font lacks Unicode glyphs | Embed a TTF with required coverage and select it with setFont(). |
| JPEG text has halos | Lossy compression | Use PNG for text-heavy or transparent content. |
| Changing a transform does nothing | Unsupported or ineffective text matrix | Remove the transform and change font size, font choice, or layout. |
| Browser tab crashes on export | Canvas is too large | Lower scale, split pages, reduce simultaneous canvases, and test memory limits. |
| Images or web fonts are absent | Cross-origin restrictions | Serve assets with appropriate CORS headers and use useCORS: true; otherwise raster capture may be incomplete. |
9. Performance, file size, and reliability trade-offs
- Native text: usually the best combination of clarity, searchability, and file size, but requires layout work.
- Higher raster scale: improves apparent sharpness while increasing canvas memory, encoding time, PDF size, and risk of browser limits.
- PNG: lossless edges and transparency, often larger for photographs.
- JPEG: smaller for photos, but compression artifacts are conspicuous around text.
- Embedded fonts: improve predictable rendering and Unicode coverage, while adding font data to the file.
Measure the generated PDF on representative devices and printers. A setting that looks excellent on a high-density display may still be unnecessarily expensive for a long, multi-page export.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Or skip the browser setup
For automated website captures, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one request. It accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before the capture. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.
Its 63 options include full-page lazy-image loading, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper and margin controls, custom CSS and JavaScript, clicks, selector waits, network-idle waits, ad/tracker/request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for parameters and response details. The same service also works from Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
And 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}`);
The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000, and every feature is available on every plan. Create a free ScreenshotNeo account to try it.
Rank #4
10. A practical decision checklist
- Need selectable, searchable text? Use native jsPDF text and embed a Unicode font when necessary.
- Must reproduce browser CSS exactly? Rasterize, but increase source scale and control the physical image size.
- Using CSS pixels? Enable
px_scaling. - Seeing missing characters? Verify font glyph coverage and embedding.
- Seeing memory failures? Reduce scale, split pages, or mix native text with smaller raster regions.
- Unsure what the PDF contains? Test selection, search, 100% viewing, and high zoom before changing settings.
Frequently Asked Questions
Does increasing jsPDF’s font size fix blurry text?
Only when the text is native PDF text. If the page is a bitmap, changing jsPDF font settings does not alter the pixels already rendered into that image.
Can a PDF viewer make a rasterized jsPDF page vector-sharp?
No. A viewer can resample an image, but it cannot recreate character outlines that were not present in the source canvas.
Should I always set html2canvas scale to 4?
No. Higher values increase memory use and export time. Select a scale from the target page size, smallest type, print requirement, and browser limits, then verify the actual output.
Why is text selectable but still visually poor?
Selectable text can still use an unsuitable or substituted font, incorrect font size, poor placement, or a viewer’s rendering at a non-100% zoom. Check font registration, glyph coverage, units, and the intended viewing scale.
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.




