IsaacSchemm / pdf.js-seamonkey

SeaMonkey fork of pdf.js
Apache License 2.0
25 stars 4 forks source link

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

Open sedimentation-fault opened 1 year ago

sedimentation-fault commented 1 year ago

Configuration

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.

sedimentation-fault commented 1 year ago

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

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

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;
  }

}
sedimentation-fault commented 1 year ago

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.

sedimentation-fault commented 1 year ago

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

sedimentation-fault commented 1 year ago

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 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-documentrules, 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! :-)