Search code examples
pdfghostscriptpostscript

Changing PDF opacity with Ghostscript


I'm trying to take a PDF file and set an opacity level to the entire document or page. The PDF's are always a single page and contain vectors but no raster images like this PDF file and can have RGB or CMYK colors. In this case, I'm trying to set an opacity level of 0.5 so everything is half-transparent.

I found a lot about watermarking PDFs which I think it's easier because the content is added to the PDF, in my case I want to modify the PDF content. I found these amazing transparency operators for Ghostscript but I can't make them work! I created a very simple postscript program and called it program.ps:

0 .pushpdf14devicefilter
0.5 .setopacityalpha 0.5 .setshapealpha

Then I run Ghostscript:

gswin64c.exe -dNOCACHE -dNOPAUSE -dBATCH -dNOSAFER -dALLOWPSTRANSPARENCY -sDEVICE=pdfwrite -o "opacity.pdf" program.ps circles.pdf

But the output is exactly the same, no transparency is applied. This results in a blank page:

<<
/EndPage {
    2 eq { pop false }
    {
        0 .pushpdf14devicefilter
        0.5 .setopacityalpha 0.5 .setshapealpha
        true
    } ifelse
} bind
>> setpagedevice

This makes no difference at all:

<<
/EndPage {
    2 eq { pop false }
    {
        0.5 .setopacityalpha 0.5 .setshapealpha
        true
    } ifelse
} bind
>> setpagedevice

Changing the operators to .setfillconstantalpha and .setstrokeconstantalpha makes no difference. I'm obviously blindly trying out stuff because I can't find much information about this and I'm not entirely sure this is even possible.

Does anyone have any experience with this or any articles/papers/books I can use as a guide?


Solution

  • Changing the opacity in EndPage won't do anything, because EndPage is called after the page is rendered (or in your case emitted as a new PDF). You would need to make those changes in a BeginPage procedure, not EndPage.

    In addition, you haven't created a transparency group, so all you've done is change the value of the current transparency in the graphics state. As soon as the PDF interpreter comes across any operator in the input PDF file which affects the opacity, it will set the graphics state to that new value, simply overwriting what you have already set. I'm reasonably certain that the initialisation of the graphics state at the start of interpretation will overwrite any values that you set in PostScript before you start interpreting a PDF file, which is why your first attempt doesn't work either.

    I'm afraid PDF transparency is a great deal more complicated than simply setting an alpha blending value. It is described in detail in the PDF Reference Manual, and the Ghostscript extensions are defined here.

    However, these extensions are really intended to be applied with PostScript marking operations, so that you can get transparency operations in PostScript. They are not intended as methods for modifying an existing PDF file, beyond possibly adding extra transparent objects, such as watermarks, and I don't think you can achieve your goal this way. You would need to start a transparency Group which enclosed the page content, and frankly I just don't think you can do that.

    Edit

    OK, so there's a .begintransparencygroup and .endtransparencygroup operator, so you could potentially create a group. However you should probably look at ghostpdl/examples/transparency_example.ps to see some of the other things you will need to get right for this to work. Note in particular the setting of PageUsesTransparency.