Noticeable aliasing in PDF
Categories
(Firefox :: PDF Viewer, defect, P3)
Tracking
()
People
(Reporter: mt, Unassigned, NeedInfo)
References
()
Details
(Whiteboard: [pdfjs-font-windows])
Attachments
(6 files)
Attach (recommended) or Link to PDF file here:
Steps to reproduce the problem:
- View the linked document
- Witness aliasing
What is the expected behavior? (add screenshot)
Edge (chromium) has different treatment of this font. Edge produces a somewhat heavier rendering, but also a smooth one.
What went wrong? (add screenshot)
Firefox produces highly aliased, thinner text. (Why can't I attach multiple files when opening an issue!?)
Reporter | ||
Comment 1•3 years ago
|
||
Note that this is at the same zoom as Edge (125%) which is approximately where the aliasing is most prominent. Things look somewhat better closer to 100% or as the text gets much larger.
Comment 2•3 years ago
|
||
I can reproduce on windows 11 but it depends on the screen used to render the pdf.
Everything is perfect on the LG Ultrafine (3840x2160) but it isn't on the two Dell U2415 (1920x1200).
:jfkthame, do you have any ideas ?
Comment 3•3 years ago
|
||
The doc is using "Google Sans 18pt", with the font resources (or subsets) embedded in the PDF.
A couple of possible factors:
My guess (but it's really only a guess for now) is that the embedded fonts lack any hinting, and in Firefox we see DirectWrite's (rough) rendering of the unhinted font, while in Blink-based browsers they render it via a bundled copy of FreeType and it's applying an auto-hinting algorithm.
Another possible issue, if the Edge rendering is rasterized via DW (not FreeType) is the choice of DirectWrite rendering mode. It looks like the Edge screenshot is using something like one of the NATURAL_SYMMETRIC rendering modes, with antialiasing applied in both horizontal and vertical axes, while the Firefox image lacks y-axis antialiasing, at least at the smaller text size.
The rendering mode we use might be affected by any 'gasp' table in the font; I was going to take a look, but I tried a few tools to extract the embedded font files from the PDF, and they consistently failed on this file. Is it possible to save a local copy of the font resources that pdf.js extracts for further examination?
Comment 4•3 years ago
|
||
You can enable pdfBug
, in about:config > pdfjs.pdfBugEnabled
and then open:
https://assets.publishing.service.gov.uk/media/62835bfee90e071f6af1457e/Privacy_Sandbox_Progress_Report_to_the_CMA_2022_Q1.pdf#pdfBug=all
(eventually reload the page), you should have an inspector on the right and you should be able to download the font: it's the font we use in the canvas.
Few changes have been made in the font thanks to:
https://github.com/mozilla/pdf.js/blob/master/src/core/fonts.js
so maybe we're doing something wrong.
Anyway I managed to get the font from the pdf itself:
qpdf --show-object=270 --raw-stream-data --stream-data=uncompress privacy.pdf > foo.ttf
zlib-flate -uncompress < foo.ttf > bar.ttf
I thought that qpdf
was uncompressing the data but it seems that it doesn't.
Comment 5•3 years ago
|
||
Thanks. OK, I confirmed that this is a TrueType font that has been subsetted (during PDF generation, no doubt) and is without any hints (quite likely hints were also stripped when the font was embedded in the PDF).
There's no 'gasp' table in the font resource, so that's not a factor in choosing the rendering mode.
Does it make any difference if you set gfx.font_rendering.cleartype_params.rendering_mode
to 5? (May require restarting Firefox.)
Comment 6•3 years ago
|
||
I just tried gfx.font_rendering.cleartype_params.rendering_mode
set to 5 and the rendering is a way better on my Dell screens.
Comment 7•3 years ago
|
||
Interesting; I just tried it on my windows machine and didn't think it made much difference (if any). Maybe it also depends on various other system settings.
Reporter | ||
Comment 8•3 years ago
|
||
FWIW, gfx.font_rendering.cleartype_params.rendering_mode
of 5 makes the file look much better for me also (also a Dell monitor). Also, no restart needed, just a reload.
Comment 9•3 years ago
|
||
For reference, the following GitHub issues seem to demonstrate the same (or at least very similar) problems:
Comment 10•3 years ago
|
||
With gfx.font_rendering.cleartype_params.rendering_mode == -1
on the Dell screen.
Comment 11•3 years ago
|
||
With gfx.font_rendering.cleartype_params.rendering_mode == 5
on the Dell screen.
Comment 12•3 years ago
|
||
:jfkthame, is there something we can do on the pdf.js side to improve the rendering ?
Comment 13•3 years ago
|
||
I don't know of anything offhand, but perhaps we need a way for pdf.js to explicitly ask for NATURAL_SYMMETRIC font rendering, overriding whatever the system default may be, as it's fairly common to have embedded fonts where all hints have been stripped and any kind of aliased rendering is likely to look quite bad. Those rendering modes are primarily targeted at carefully-hinted fonts on low-res screens, while rendering a PDF is more like trying to emulate arbitrary-resolution printed output.
Lee, WDYT - would that be a reasonable thing to try? I guess it'd mean having some kind of internal API that pdf.js can use to override the rendering mode.
Comment 14•3 years ago
|
||
(In reply to Jonathan Kew (:jfkthame) from comment #3)
The rendering mode we use might be affected by any 'gasp' table in the font;
Sorry about the potentially stupid question, but:
Looking at https://docs.microsoft.com/en-us/typography/opentype/spec/gasp, could we (in PDF.js) maybe generate a gasp
table that forces a suitable text rendering mode to be chosen by the browser?
As part of the font parsing in the PDF.js library, we'll generate a new and (mostly) sanitized OpenType font from the font-data embedded in the PDF document; see e.g. https://github.com/mozilla/pdf.js/blob/master/src/core/opentype_file_builder.js
Comment 15•3 years ago
•
|
||
Having very quickly hacked together a patch which adds a rudimentary gasp
table in PDF.js, using the GASP_SYMMETRIC_SMOOTHING
-flag, it actually seems to sort of work. However, as mentioned above, I don't know if it's a good idea or even correct in general.
https://github.com/mozilla/pdf.js/compare/master...Snuffleupagus:gasp-table
Comment 16•3 years ago
|
||
Comment 17•3 years ago
|
||
That actually sounds like it could be a good solution here. I'd be curious to see whether GASP behavior 0x08 (SYMMETRIC_SMOOTHING only) or 0x0C (SYMMETRIC_SMOOTHING + SYMMETRIC_GRIDFIT) tends to look better; did you compare these, or just pick one for an initial test?
It'd also be worth testing on Windows with ClearType disabled (i.e. only grayscale smoothing enabled at the OS level). We might need to ensure the DO_GRAY flag is turned on for this case.
Comment 18•3 years ago
|
||
Hacking a gasp table onto the fonts sounds less contentious than adding in a Firefox-specific canvas2d extension...
Comment 19•3 years ago
|
||
(In reply to Jonathan Kew [:jfkthame] from comment #17)
I'd be curious to see whether GASP behavior 0x08 (SYMMETRIC_SMOOTHING only) or 0x0C (SYMMETRIC_SMOOTHING + SYMMETRIC_GRIDFIT) tends to look better; did you compare these, or just pick one for an initial test?
I mostly just picked a value at random, to have something to test with.
However, having just tested, for the PDF document in this bug there doesn't seem to be any visual difference between SYMMETRIC_SMOOTHING
and SYMMETRIC_SMOOTHING + SYMMETRIC_GRIDFIT
.
While the patch in https://github.com/mozilla/pdf.js/pull/15009 does fix this bug, it unfortunately causes regressions in existing test-cases; please see https://github.com/mozilla/pdf.js/pull/15009#issuecomment-1150885796
To summarize what the latest version of that patch does:
- Keeps any existing
gasp
table found in the font, since previously we'd just ignore that table. - Only creates a fallback
gasp
table when the PDF.js font parsing code decides that the hinting-data is invalid or when some of the relevant tables are missing.
Given the regression mentioned above, it seems to me that not all fonts with broken/missing hinting-data actually benefit from a fallback gasp
table. Unfortunately I just don't know enough about fonts to be able to tell, more specifically, when adding a gasp
table is actually necessary.
Reporter | ||
Comment 20•3 years ago
|
||
What are the consequences that come from using gfx.font_rendering.cleartype_params.rendering_mode
set to 5 in general browsing? I'm still getting this issue and it is pretty annoying.
Reporter | ||
Comment 21•2 years ago
|
||
I traced this to https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_rendering_mode and - if I understand correctly - this value of 5 seems like a fine default. I'll now defer to others on how (and whether) to address this.
Reporter | ||
Comment 22•1 year ago
|
||
I have a new one that I think might be related from https://arxiv.org/pdf/2408.07892
Notice the aliasing on the capital "A" here. That's not something that I see in Chromium. The aliasing is present for any setting of gfx.font_rendering.cleartype_params.rendering_mode, so it might be different. It's also likely the case that the font has bad or non-existent hinting. But it's pretty noticeable how much worse our rendering of this document is than our competitor.
Comment 23•7 months ago
|
||
(In reply to Martin Thomson [:mt:] from comment #21)
I traced this to https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_rendering_mode and - if I understand correctly - this value of 5 seems like a fine default. I'll now defer to others on how (and whether) to address this.
Should we switch to 5 by default?
![]() |
||
Comment 24•4 months ago
|
||
(In reply to Marco Castelluccio [:marco] from comment #23)
I traced this to https://learn.microsoft.com/en-us/windows/win32/api/dwrite/ne-dwrite-dwrite_rendering_mode and - if I understand correctly >
Should we switch to 5 by default?
That's DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
, which will be more computationally expensive.
Blink uses that value in SkScalerContext_win_dw.cpp under certain circumstances it seems (rotated glyphs, real size above 20px, etc.) but we don't seem to have the same information where we make decisions in cairo-dwrite-font.cpp about which DWRITE_RENDERING_MODE_*
value to use. Plumbing that information through, and getting those patches upstreamed, is probably a fair bit of work and may require API changes.
Perhaps we could use DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC
blindly, but it's not clear to me what the perf impact would be, or whether we would have adaquate testing to quantify the impact.
Right now the Layout team is pretty overloaded with work that is higher priority, so I’m not sure this is going to get developer time any time soon.
Description
•