Open Bug 1769884 Opened 3 years ago Updated 4 months ago

Noticeable aliasing in PDF

Categories

(Firefox :: PDF Viewer, defect, P3)

x86_64
Windows 10
defect

Tracking

()

People

(Reporter: mt, Unassigned, NeedInfo)

References

()

Details

(Whiteboard: [pdfjs-font-windows])

Attachments

(6 files)

Attached image edge.png

Attach (recommended) or Link to PDF file here:

Steps to reproduce the problem:

  1. View the linked document
  2. 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!?)

Attached image firefox.png

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.

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 ?

Flags: needinfo?(jfkthame)

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?

Flags: needinfo?(jfkthame)

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.

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.)

I just tried gfx.font_rendering.cleartype_params.rendering_mode set to 5 and the rendering is a way better on my Dell screens.

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.

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.

For reference, the following GitHub issues seem to demonstrate the same (or at least very similar) problems:

Attached image rendering_mode_-1.png

With gfx.font_rendering.cleartype_params.rendering_mode == -1 on the Dell screen.

Attached image rendering_mode_5.png

With gfx.font_rendering.cleartype_params.rendering_mode == 5 on the Dell screen.

:jfkthame, is there something we can do on the pdf.js side to improve the rendering ?

Severity: -- → S3
Flags: needinfo?(jfkthame)
Priority: -- → P3
Whiteboard: [pdfjs-font-windows]

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.

Flags: needinfo?(jfkthame) → needinfo?(lsalzman)

(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

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

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.

Hacking a gasp table onto the fonts sounds less contentious than adding in a Firefox-specific canvas2d extension...

Flags: needinfo?(lsalzman)

(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.

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.

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.

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.

(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?

Flags: needinfo?(lsalzman)
Flags: needinfo?(jfkthame)

(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.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: