Open Bug 1800097 Opened 2 years ago Updated 1 year ago

Disable Subpixel Snapping When Rendering to PDFs

Categories

(Core :: Printing: Output, defect)

Firefox 105
defect

Tracking

()

People

(Reporter: ossman, Unassigned)

Details

Attachments

(5 files)

User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0

Steps to reproduce:

  1. Create a page with borders
  2. Print to PDF

Actual results:

Borders in PDF are thinner than specified by CSS.

Expected results:

Borders should match width specified in CSS.

Attached file Test case

Test case that demonstrates the bug. It seems to be some explicit nudging of border widths as only widths that are integer pixel sizes are tweaked, and always by a fixed amount (rather than a linear scale).

Also embedded a SVG image for reference, where dimensions are left alone.

Attached file Test output

Output as generated on my copy of Firefox, in case you get some other result.

We are trying to use Firefox as a way to generate vector-based screenshots, and this bug screws up the layout as the CSS isn't properly respected.

The Bugbug bot thinks this bug should belong to the 'Firefox::PDF Viewer' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → PDF Viewer
Component: PDF Viewer → Printing: Output
Product: Firefox → Core

Quoting comment 0 here:

Expected results:
Borders should match width specified in CSS.

So: we don't precisely match the width specified in CSS, since (as you inferred in comment 1) we in fact round borders (specifically borders, as distinguished from other CSS sizes) to whole display-pixel values -- which may or may not be the same as whole CSS pixels, depending on the resolution of the display/output device.

WebKit does this rounding as well, and Chrome is changing to match -- see https://bugs.chromium.org/p/chromium/issues/detail?id=1201762 and https://github.com/w3c/csswg-drafts/issues/5210

emilio blogged about this in https://crisal.io/words/2020/06/13/rounding-borders.html as well if you want more nitty-gritty details and background about the reasons/tradeoffs.

If you're setting up content that depends on border-width:1.5px reliably occupying 1.5 css pixels of layout space (being visually distinct from a 1px border, and offsetting the content that follows by an extra half-pixel), then that's likely to not reliably work in any browser pretty soon (though it may work in some cases if your display device's pixel ratio is such that 1.5 css pixels is a whole number of device pixels).

Does that make sense? Am I missing something about the description/testcase here?

Flags: needinfo?(ossman)

Also: to the extent that you're seeing different border-thickness-behavior in print-to-PDF output vs. regular browser rendering of your testcase, that's likely because of DPI differences between the PDF-printing backend vs. your screen. The PDF virtual-printer probably has a higher display-pixel density than your screen, so it ends up with different pixel-rounding behavior as a result.

Hmm... So if I understand you correctly only borders get this nudging, nothing else? This is problematic when you want to match it with other things...

I would have expected the PDF output to have massive DPI? Or just plainly disable the nudging since it isn't relevant. Right now I seem to be seeing that a PDF pixel is 0.6667 CSS pixels, which is a very annoying number as fairly sane on-screen widths such as 1px get distorted in print.

Is there some way we can influence this grid? I tried changing the print scale, but it did not fix it. It seems the pixel grid scales as well, keeping that odd ratio to CSS pixels.

Flags: needinfo?(ossman)

(In reply to Pierre Ossman from comment #7)

Hmm... So if I understand you correctly only borders get this nudging, nothing else? This is problematic when you want to match it with other things...

Correct. See bug 477157 which I filed 14 years back, for one case where it's problematic (borders not exactly covering a red background area that's nominally the same size).

It's a tradeoff, and Emilio's above-linked blog post goes into the reasons for this.
It at least should be standardized and reasonably-interoperable soon, per the above-linked Chrome bug.

I would have expected the PDF output to have massive DPI? Or just plainly disable the nudging since it isn't relevant.

That seems like a reasonable intuition, if you think of a PDF as having an infinite resolution. On the other hand, PDFs obviously aren't viewed on devices with infinite resolution, so we might be picking some assumed resolution based on assumptions about the eventual display device; I'm not sure.

Anyway -- I don't recall what resolution we use for generating PDFs, but I or someone can check... [I'll try to circle back with an answer on that, please nag me if I forget]

Is there some way we can influence this grid? I tried changing the print scale, but it did not fix it. It seems the pixel grid scales as well, keeping that odd ratio to CSS pixels.

I'm not sure offhand; I think really you would need to control the device-pixel-to-css-pixel ratio. I don't think that's configurable for our built-in save-to-PDF backend. It might be possible to do using a custom print driver, though I'm not entirely sure.

Yay! I found a setting amongst the dragons that fixes this! Specifically printer.default_dpi. It's set to 144 by default, i.e. 1.5×96, which fully explains why a PDF “device pixel” is .667 CSS pixels. If I change that value to 96, then I get much saner output.

Why is that value not 96 by default, though? Historical reasons? I tried to compare both PDFs and real prints with different settings, and I could not find any difference except border width rounding. Images and vector graphics are all rendered using the same size and density no matter the setting.

Side note: Background position seems to be rounded to device pixels for screen output, but not for print output. Perhaps something that also should be harmonised?

Higher DPI is very useful for images / rasterized web content, see bug 1664258. It was historically 144 already on Windows.

Do you have a more clear example? I could not see any rasterisation differences when changing that value.

If it truly needs to be higher than the standard 96, then I think it should at the very least be an integer multiple of 96 to avoid issues like the one described in the bug here.

Flags: needinfo?(emilio)

There were a variety of reports like bug 1658333 where images were wrongly scaled. IIRC the "regular" DPI before that bug was 72.0. Jonathans, do you have context on why the default dpi for printing used to be 72 rather than 96?

Flags: needinfo?(jwatt)
Flags: needinfo?(jfkthame)
Flags: needinfo?(emilio)

I don't know the specific history of our printing code, but 72dpi was the typical resolution of old dot-matrix printers, and of the original Mac's "WYSIWYG" bitmapped display. (It also relates to PostScript and PDF's native "point" unit.)

Flags: needinfo?(jfkthame)

I do wonder if we should disable the pixel-snapping of borders altogether when rendering to PDF, at least, and maybe for all printing unless we know it's a raster printer with a specific DPI. We have absolutely no way of knowing what resolution will be used when the PDF eventually gets viewed or printed, so the chances that our snapping will be "right" for that context, and improve the final quality, must be quite low.

For convenience, here's a testcase with each of the 0.1px values between 0.1px and 3px, to help visualize what the threshold is where the snapping behavior changes.

Changing title as per discussion - I wonder if bug 1803373 relates?

Status: UNCONFIRMED → NEW
Ever confirmed: true
Summary: Incorrect border width in prints → Disable Subpixel Snapping When Rendering to PDFs
Severity: -- → S3

(In reply to Emilio Cobos Álvarez (:emilio) from comment #12)

Jonathans, do you have context on why the default dpi for printing used to be 72 rather than 96?

I'd just add to jfkthame's comment that subsequent dot matrix printers were 144 DPI, I think, so it probably still made some sense to use 72 DPI in the Netscape era.

Flags: needinfo?(jwatt)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: