IsaacSchemm/pdf.js-seamonkey

How to change the background color of the document page in pdf.js

Opened this issue · 4 comments

Configuration

  • Web browser and its version:
    Pale Moon 32.4.0.1
  • Operating system and its version:
    Linux, 5.4.196-gentoo
  • PDF.js version: 2.3.240
  • Is a browser extension:
    Yes

Steps to reproduce the problem

  1. Open any PDF with white page background.
  2. Try to change the background color of the page

What is the expected behavior?

I would like to change the background color of the page (the PDF page, where the text of the PDF appears) from the usual white to something more eye-friendly.

What went wrong?

No matter what I try it seems impossible to change the page background color.
I use the Stylem extension to set my own CSS for PDFs. This is a Pale Moon specific extension, but it works like the Stylish extension for Firefox and uses the same CSSs. While all the following works and changes the colors of the toolbar, sidebar, links etc.

@-moz-document regexp(".*.pdf")
{
/* Viewer body area: dark side margins */
#viewer.pdfViewer {
	background-color: #EACCAF !important;
}

/* Viewer toolbar and elements */
#toolbarContainer > #toolbarViewer, 
#toolbarContainer > #toolbarViewer input,
#toolbarContainer > #toolbarViewer select,
#toolbarContainer > #toolbarViewer option,
#toolbarContainer > #toolbarViewer span,
#secondaryToolbar,
#secondaryToolbar > #secondaryToolbarButtonContainer button {
	color: #eee !important;
	background-color: #4992A7 !important;
}
  

#toolbarContainer > #toolbarViewer button::before,
#toolbarContainer > #toolbarViewer a::before,
#toolbarContainer > #toolbarViewer span::after,
#secondaryToolbar > #secondaryToolbarButtonContainer button::before {
	filter: invert(1) !important;
}
  

#toolbarContainer > #toolbarViewer button:hover,
#toolbarContainer > #toolbarViewer a:hover,
#sidebarContainer a:hover
{
	background-color: #EDA870 !important;
}

  
#sidebarContent {
    background-color: #4992A7 !important;
  }

} 

, none of the following has any effect:

.page, .canvasWrapper, .textLayer {
    background-color: #EACCAF !important;
  }
html body div#outerContainer.sidebarOpen div#mainContainer div#viewerContainer div#viewer.pdfViewer div.page div.textLayer {
   background-color: #EACCAF !important;
}

#viewerContainer > #viewer > .page > .canvasWrapper > canvas {
    background-color: #EACCAF !important;
}

It seems that pdf.js will use white, no matter what one sets for canvas, textLayer, or whatever CSS selector...

pdfjs-page-background-color

As you can see in the screenshot above, page background remains white.

Solution

Finally, after lot of experimentation, I found some settings that would do the trick:

Add the following to the above:

div.textLayer, div.canvasWrapper, div.page,
.page > .canvasWrapper > canvas
  {
    background-color: #EACCAF !important;
    /*
    filter: sepia(0.3);
    filter: opacity(85%);
    */
    mix-blend-mode: darken;
  }

The result is now nice:

pdfjs-page-background-color-2

Notes

  • I have left a few other possibilities that also work in some sense commented in the code:
  1. filter: sepia(1.0); would make the page too yellow, filter: sepia(0.3); was "OK, somehow".
  2. filter: opacity(85%); was also able to change the page background color, in a way that left the color of parent element "shine through". However, text looked less sharp and more like "through milky glass".

Background

How did I arrive at this solution? Well, looking at the way the page was painted on the screen while having only

div.textLayer, div.canvasWrapper, div.page,
.page > .canvasWrapper > canvas
  {
    background-color: #EACCAF !important;
  }

, one could see that the background was set for one (or maybe all) parent elements of div.textLayer (div.canvasWrapper is a parent of div.textLayer, and div.page a parent of div.canvasWrapper) - but then the page would be "painted" over that background somehow and would get the white background. This made me think "I need a mechanism to change colors after the whole painting has taken place". This mechanism is exactly filter:, so I experimented with it.

Indeed , as said, adding filter: sepia(0.3);, or filter: opacity(85%); worked, so I did some reading on filter: and the article CSS Image Filter [Usage + 10 Examples] pointed me to the right direction:

Not exactly a CSS image filter but definitely another cool CSS effect that you should know about.

This CSS property uses the mix-blend-mode keyword to allow you to set how the elements should blend together with the background. This is used mainly with text and cool backgrounds like in our example.

Conclusion

Is this a bug? Yes and no. At start I felt that the usual CSS selectors, e.g. having only

div.textLayer, div.canvasWrapper, div.page,
.page > .canvasWrapper > canvas
  {
    background-color: #EACCAF !important;
  }

should suffice to set background colors. Now, looking at the way a page is "painted" on a "canvas", this may not be technically possible and the only way to get a grasp of the background color may be with the mix-blend-mode: mechanism.

So you may close this as resolved, after all - or put it in the Wiki. Here is the final CSS code that styles PDFs in my Stylem CSS file:

/* Styling of PDFs inside the pdf.js extension */
@-moz-document regexp(".*.pdf")
{
/* Viewer body area: dark side margins */
#viewer.pdfViewer {
	background-color: #EACCAF !important;
}
  
/* Viewer toolbar and elements */
#toolbarContainer > #toolbarViewer, 
#toolbarContainer > #toolbarViewer input,
#toolbarContainer > #toolbarViewer select,
#toolbarContainer > #toolbarViewer option,
#toolbarContainer > #toolbarViewer span,
#secondaryToolbar,
#secondaryToolbar > #secondaryToolbarButtonContainer button {
	color: #eee !important;
	background-color: #4992A7 !important;
}
  

#toolbarContainer > #toolbarViewer button::before,
#toolbarContainer > #toolbarViewer a::before,
#toolbarContainer > #toolbarViewer span::after,
#secondaryToolbar > #secondaryToolbarButtonContainer button::before {
	filter: invert(1) !important;
}
  

#toolbarContainer > #toolbarViewer button:hover,
#toolbarContainer > #toolbarViewer a:hover,
#sidebarContainer a:hover
{
	background-color: #EDA870 !important;
}

  
#sidebarContent {
    background-color: #4992A7 !important;
  }
  
  
div.textLayer, div.canvasWrapper, div.page,
.page > .canvasWrapper > canvas
  {
    background-color: #EACCAF !important;
    /*
    filter: sepia(0.3);
    filter: opacity(85%);
    */
    mix-blend-mode: darken;
  }

}

Some improvements and quirks to the above:

Improved CSS

In the above CSS, replace

div.textLayer, div.canvasWrapper, div.page,
.page > .canvasWrapper > canvas
  {
    background-color: #EACCAF !important;
    /*
    filter: sepia(0.3);
    filter: opacity(85%);
    */
    mix-blend-mode: darken;
  }

with the more accurate

div#viewer.pdfViewer {
    background-color: #C6B2A8 !important;
}
  
div.page {
    background-color: #eee !important;
}

div.textLayer
  {
    background-color: #EACCAF !important;
    /*
    filter: sepia(0.3);
    filter: opacity(85%);
    */
    mix-blend-mode: darken;
  }

As you can see, we assign three different background colors to the three areas - pdfViewer, which encloses page, which encloses textLayer. You can play with them and see which is which. The #C6B2A8 color for pdfViewer harmonizes very nicely with both #4992A7 of the left sidebar menu and the toolbar. It is also the standard color of the Pale Moon toolbars. The #eee color for page is somehow not visible. The styling now looks like this:

pdfjs-page-background-color-3

Quirks

Pressing PgUp, PgDown, or the arrow keys, or even just clicking somewhere in the page changes page background to the "hover" color of buttons and links in the toolbar and sidebar (#EDA870):

pdfjs-page-background-color-4

The only explanation I have for this is that the area assigned to textLayer (and even more so the area assigned to page) overlaps the area of toolbarViewer, so that a simple click inside textLayer is interpreted as a "hover" event for toolbarViewer, changing its background to #EDA870, which in turn leads to the same background for textLayer due to the mix-blend-mode: darken; rule.

The workaround (which confirms the above explanation) is to simply click somewhere in the toolbar of the PDF viewer (the toolbarViewer area). This obviously ends the "hover" event and all goes back to normal.

I don't think there is a real solution for this, unless the areas of textLayer and page are made to have no common pixels with that of toolbarViewer.

To style the color of the thumbnail selection ring consistently with the hover style of buttons and outline links, add .thumbnail.selected div.thumbnailSelectionRingto the block with the #EDA870 background color:

#toolbarContainer > #toolbarViewer button:hover,
#toolbarContainer > #toolbarViewer a:hover,
#sidebarContainer a:hover,
#toolbarSidebar button:hover,
.thumbnail.selected div.thumbnailSelectionRing
{
	background-color: #EDA870 !important;
}

pdfjs-page-background-color-5

The presence of #sidebarContainer a:hover in the above changes the hover background color of the buttons inside the toolbar of the sidebar (#toolbarSidebar):
pdfjs-page-background-color-6

Unfortunately, trying to also change the background of the sidebar toolbar (the dark (almost black, #474645) background where the buttons for "thumbnails", "outlines" and "attachments" are positioned) to something more harmonious with

#toolbarSidebar {
  background-color: #EACCAF !important;
}

does NOT seem to work. This may be a bug...

Final version

...well, final for the moment! :-)

Here is the (hopefully) final CSS for the Stylem extension to completely style a PDF for pdf.js:

@-moz-document regexp(".*.pdf")
{
  
#outerContainer, #viewerContainer {
  background-color: #C6B2A8 !important;
}
  
/* Viewer toolbar and elements */
#toolbarContainer > #toolbarViewer, 
#toolbarContainer > #toolbarViewer input,
#toolbarContainer > #toolbarViewer select,
#toolbarContainer > #toolbarViewer option,
#toolbarContainer > #toolbarViewer span {
  color: black !important;
  /* background-color: #C6B2A8 !important; */
  background-color: #C6AC9E !important;
}

#toolbarSidebar {
  background-color: #EACCAF !important;
}

/* Uncomment to invert the color of buttons etc. on the toolbar from (currently) white to black.
/*
#toolbarContainer > #toolbarViewer button::before,
#toolbarContainer > #toolbarViewer a::before,
#toolbarContainer > #toolbarViewer span::after {
	filter: invert(1) !important;
}
*/
  

#toolbarContainer > #toolbarViewer button:hover,
#toolbarContainer > #toolbarViewer a:hover,
#sidebarContainer a:hover,
#toolbarSidebar button:hover,
.thumbnail.selected div.thumbnailSelectionRing
{
	background-color: #EDA870 !important;
}

  
#sidebarContent {
  background-color: #4992A7 !important;
  color: white;
}
  
  
/* Viewer body area */

div#viewer.pdfViewer {
  background-color: #C6B2A8 !important;
}

div.page {
    background-color: #EACCAF !important;
  
}

.page > .canvasWrapper > canvas
  {
    background-color: #EACCAF !important;
    /*
    filter: sepia(0.3);
    filter: opacity(85%);
    */
    mix-blend-mode: darken;
  }


} 

You can probably use the above in any CSS that is going to be used in conjunction with pdf.js and Pale Moon to completely style a PDF - not just the background color of the PDF pages, but the whole appearance. I have thrown away selectors that did nothing and added only those that are absolutely necessary.

Some notes

  • The problem of getting the "hover" color on the whole page upon using PgUp, PgDown or the arrow keys is now gone. You can click at your will wherever and as often you please now - except for a very minor detail:
  • If you do not style the background color for #viewerContainer, clicking somewhere on the PDF page will trigger the "hover" color (#EDA870). You may or may not notice, as currently very small parts of #viewerContainer may "shine through" the various other layers. Background color for #viewerContainer is set for this reason explicitly.
  • I have changed the background color of the top toolbar from #4992A7, which is still the background color of the sidebar content, to a shade of the background color of #outerContainer: #C6AC9E differs from #C6B2A8 only in a few units of saturation (saturation 20, instead of 15). I think this gives a much better color combination - one that is pleasant to the eye, but not too wild.
  • I don't invert the color of the icons on the top toolbar - they remain white, instead of black. I've commented the code that inverts them to black. I find white better for the new background color of the top toolbar, as well as for the "hover" color.
  • The background-color rule for canvas does not have any effect. What sets the background color for canvas is the mix-blend-mode: rule: it takes the background of page (#EACCAF) and darkens it a bit (actually, for me, it doesn't darken it at all, it just takes it as-is). This was the original problem of this issue.
  • If you don't style canvas as shown, you will not manage to set the background color of the PDF pages.
  • I use this CSS for locally stored PDFs, i.e for URLs like file:///full/path/to/some-file.pdf. For this to work, file:// should NOT be among the @-moz-document URLs for your main CSS.

The last one above is a bit cryptic, so let me try to explain it a bit: In a Stylem CSS, you usually have:

@-moz-document url("about:blank"), url-prefix("http://"), url-prefix("https://"), url-prefix("ftp://")
{
...CSS rules for "about:blank", "http://", "https://" and "ftp://" URLs..
}

@-moz-document regexp(".*.pdf")
{
...here comes the CSS for PDFs as posted above
}

This will work fine. But if you try to add a file:// regexp like this

@-moz-document url("about:blank"), url-prefix("http://"), url-prefix("https://"), url-prefix("ftp://"), regexp('file:.*(?!\.pdf)')
{
...
}
@-moz-document regexp(".*.pdf")
{
...
}

in an attempt to say: "here are CSS rules for URLs like about:blank, http://, https://, ftp:// and file:// - but NOT file://...pdf - and here are CSS rules for .*.pdf" - this is NOT going to work! In other words, I have not yet found a way to exclude PDFs from file:// URLs in @-moz-document rules, so I completely avoid file:// in all @-moz-document directives. I hope it's clear now.

Result

And here's how it looks like:
pdfjs-page-background-color-7

Conclusion

So here we are: with a few colors and lot of know-how we get a complete styling of PDFs - one that hopefully will please your eyes at least as much as mine. Enjoy! :-)