Colours in PDFDocument

OK, I’m trying to create a PDF that is responsive to changes in Dark / Light mode. The first problem is the white background. How do I define the background colour, or lack of it. Is it possible to have a transparent background.

You need to use the PDFDocuments Graphics context. Here’s a sample for a PDF with two pages, each of them has a different “background” color:

Var pdf As New PDFDocument
Var g As Graphics = pdf.Graphics

' first page with yellow background
g.DrawingColor = Color.Yellow
g.FillRectangle(0, 0, g.Width, g.Height)

' add new page
g.NextPage

' second page with red background
g.DrawingColor = Color.Red
g.FillRectangle(0, 0, g.Width, g.Height)

' save the PDF
pdf.Save(SpecialFolder.Desktop.Child("Test.pdf"))

Yes, but I want a transparent background. Not a colour. Drawing a transparent rectangle would just show through the white background, that is seemingly built into the document.

PDFDocument doesn’t “hardcode” a background color for its pages… but most (if not all) PDF viewer apps do set a white page background colour when the PDF document is opened / previewed.

This is how a PDF document generated with Xojo does look like “as-is” when opened in Pixelmator = transparent background.

@Javier_Menendez Thanks for that. I’m creating a PDF graphing module (from my SVG one) and so far I’ve got a white background, I’ll try it in the HTMLViewer when I get far enough along.

Unfortunately the background is always white in HTML viewer. Even in dark mode, which in it’s self is very odd. Here’s an example of the output:

Not only is it showing a white background there is a grey border around it and it is scalable / scrollable, which is undesirable.

I’m also assuming that drawing isn’t dark mode friendly either. In other works lines are drawn in a fixed colour, rather than one that can take account of dark mode. I can create a CSS stylesheet for HTML that automatically switches colours when dark or light mode is enabled, without using any javascript. I’m kind of coming to the conclusion that PDF cannot cope with that either.

PDF isn’t a parameterized drawing system like SVG is - it is specifically designed to be self-contained, with consistent rendering across all platforms and contexts. So it’s not going to do what you want here.

The best you could do would be to create two versions of the PDF, one for Light and one for Dark mode, and swap them out via CSS in the HTML (make only one visible at a time, in other words).

Then I can’t see how it could ever be used as part of a user interface in a modern OS. All of which have a version of light and dark mode. Having to have two copies around or regenerate on mode change is a major drawback.

That’s one reason why all icons are now in bw instead of using color. For toolbar icons I only need to set isTemplate and macOS inverts everything in DarkMode:

if item.label = PrefsToolbarLocalization.kProxy then
  dim theImage as new NSImageMBS(proxy_outline)
  theImage.isTemplate = true
  item.image = theImage

and so on.

Yes, I’m using template images. It is the only way to get the correct colour for toolbar icons, especially when desktop wallpaper tinting is turned on. I don’t see how that is going to work with pdf though.

It depends on what you’re looking to accomplish. Black and white PDFs can be rasterized on the fly and then the resulting pixels processed to present a different color, even inverted for a Dark Mode effect. But your average PDF of a textual document - or a graph - isn’t intended for this.

I want a scalable method of drawing a graph that can be displayed on screen other information, preferably with HTML something similar as it offers rich formatting with ease. I want to be able to copy things simply into other applications and remain the scalability of the output.

HTML + SVG offers that for display purposes, but fails on the pasting into other applications.

HTML + PDF offers the copy and paste, but fails not the disaplay-ability.

If I could generate a scalable PDF of my graphics and then render that as a PNG for display purposes, I would be quite happy to offer a method of copy and pasting a PDF scalable version of the graphs for insertion into other applications. What I don’t want to do is generate two versions of the output by walking through my dataset. If I throw 183,000 datapoints at my graphics it can take 7-8 seconds to draw, I don’t want that doubled. I’ve just optimised it to be this fast.

Hmm… this seems to point towards a solution for PDF to PNG:

dim DPI as Double
if MimeOptions.PreviewSize = 1024 then
  DPI = 144.0
Else
  DPI = 72.0
end if
  
  #pragma BreakOnExceptions false
  try
    dim PreviewPic as Picture
    dim c as new CGImageSourceMBS(MimeData)
    dim img as CGImageMBS
    dim d as new Dictionary
    d.Value(c.kCGImageSourceThumbnailMaxPixelSize)=2048
    d.Value(c.kCGImageSourceCreateThumbnailFromImageAlways)=True
    d.Value(c.kCGImageSourceShouldAllowFloat)=True
    d.Value(c.kCGImageSourceCreateThumbnailWithTransform)=True
    img = c.CreateThumbnailAtIndex(0, d)
    PreviewPic = img.Picture
    Return PreviewPic
  catch err as OutOfBoundsException
    'no image
  end try
  #pragma BreakOnExceptions True

I don’t have MBS sorry. But thanks for that. I’ll keep looking your code may well point me to a solution.

MacOSLib does have a CGImageSource class…

Actually, you can simply Picture.Open a PDF to get a rasterized version of it. Xojo and the underlying CoreGraphics framework handles it all.

Interesting. I’ll give it a try.

Also: it’s a separate issue for a different thread, but perhaps we could help you further optimize your graph drawing algorithm. :slight_smile:

Indeed. It does work but it actually won’t work fully anyway as the PNG is no more capable of being light / dark mode friendly. I suppose I could regenerate them resave them and reload the HTML. Or actually have a Light and Dark version of them and use HTML to automatically switch them when the mode changes.