Search code examples
pdfpdf-generationpdfbox

How to use a color Mask on a bitonal image in a PDF file?


I'm trying to create a PDF file containing a monochrome 1-bit image, but configure the image to be transparent where it contains white pixels (so that content under the image is visible). The image uses the DeviceGray color space, and BitsPerComponent is 1.

I'm using the Mask entry with an array specifying the color range which should be masked. My copy of the PDF spec calls this "Colour Key Masking". Since the image is bitonal, this color range is just [1 1] (white).

However, I simply can't get this to work. The content under the image never displays. I've tried tweaking the range values, changing the image filter, tweaking the surrounding graphics state -- all to no avail.

The only thing that has worked has been to change the image color space from DeviceGray to DeviceRGB and tweak the Mask ranges accordingly, but that would increase the size of these images in the PDF file, which I cannot do.

What is the correct way to use color key masking on bitonal DeviceGray images?

Here's the image that I think should work, but does not:

6 0 obj
<<
/Length 8800
/Type /XObject
/Subtype /Image
/Filter /ASCIIHexDecode
/BitsPerComponent 1
/Width 350
/Height 100
/ColorSpace /DeviceGray
/Mask [1 1]
>>
stream
FFFF<snip>FFFC
endstream
endobj

EDIT: Adding full sample PDF file for full context. The file contains an image with the text "XYZ", and a line that runs under the XYZ image, which is hidden by the image but should be visible under the text:

%PDF-1.4
%צה
1 0 obj
<<
/Type /Catalog
/Version /1.4
/Pages 2 0 R
>>
endobj
2 0 obj
<<
/Type /Pages
/Kids [3 0 R]
/Count 1
>>
endobj
3 0 obj
<<
/Type /Page
/MediaBox [0.0 0.0 612.0 792.0]
/Parent 2 0 R
/Contents 4 0 R
/Resources 5 0 R
>>
endobj
4 0 obj
<<
/Length 53
>>
stream
0 396 m
612 396 l
S
q
90 0 0 80 261 356 cm
/Im1 Do
Q

endstream
endobj
5 0 obj
<<
/XObject <<
/Im1 6 0 R
>>
>>
endobj
6 0 obj
<<
/Length 1920
/Type /XObject
/Subtype /Image
/Filter /ASCIIHexDecode
/BitsPerComponent 1
/Width 90
/Height 80
/ColorSpace /DeviceGray
/Mask [1 1]
>>
stream
FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FE0FFF8307FFF8380000FFC0FF07FF0783FFF0780000FFC0FF87FE0FC3FFF0F80000FFC0FF83FE0FC1FFE0F80000FFC0FFC1FC1FE0FFC1FFFFE0FFC0FFE0F83FF0FFC3FFFFC1FFC0FFF0F87FF07F83FFFF83FFC0FFF0707FF83F07FFFF07FFC0FFF820FFFC3F0FFFFF07FFC0FFFC21FFFC1E0FFFFE0FFFC0FFFC01FFFE1C1FFFFC1FFFC0FFFE03FFFF0C3FFFF83FFFC0FFFF07FFFF003FFFF07FFFC0FFFF07FFFF807FFFF07FFFC0FFFE03FFFFC0FFFFE0FFFFC0FFFC01FFFFC0FFFFC1FFFFC0FFFC21FFFFE1FFFF83FFFFC0FFF820FFFFE1FFFF83FFFFC0FFF0707FFFE1FFFF07FFFFC0FFF0F87FFFE1FFFE0FFFFFC0FFE0F83FFFE1FFFC1FFFFFC0FFC1FC1FFFE1FFFC1FFFFFC0FFC3FE1FFFE1FFF83FFFFFC0FF83FE0FFFE1FFF07FFFFFC0FF07FF07FFE1FFE0FFFFFFC0FE0FFF83FFE1FFE000007FC0FE1FFFC3FFE1FFE000007FC0FC1FFFC1FFE1FFE000007FC0F83FFFE0FFE1FFE000007FC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0FFFFFFFFFFFFFFFFFFFFFFC0
endstream
endobj
xref
0 7
0000000000 65535 f
0000000015 00000 n
0000000078 00000 n
0000000135 00000 n
0000000247 00000 n
0000000352 00000 n
0000000399 00000 n
trailer
<<
/Root 1 0 R
/ID [<DF10D2517650DA8AC34FF5D6B9B046EA> <DF10D2517650DA8AC34FF5D6B9B046EA>]
/Size 7
>>
startxref
2505
%%EOF

EDIT 2: Thanks to iPDFdev's confirmation that this should indeed work, I dug deeper into the reader side of things. It turns out that there is a bug in SumatraPDF, and there was also a bug in the older version of Acrobat Reader that I was using.

After updating Acrobat Reader, the simplified example is working, but a more complex example involving Forms is still not working -- it seems that this is perhaps an area of the PDF spec that is not widely used or as battle-tested as others, even in Acrobat Reader. I'll probably stay away from the DeviceGray + bitonal + Mask combination for the time being, due to compatibility concerns, and use the less efficient SMask option instead.

All examples (both simple and complex) are working correctly in the iOS, Chrome and Firefox viewers, so I just happened to choose the two worst reader options to test this.


Solution

  • Without seeing the entire file I cannot say why the mask is not applied.

    But the file below shows that the /Mask is applied to /DeviceGray bitonal images:

    4 0 obj
    <<
      /Type /Page
      /Resources <</XObject <</XO0 6 0 R>>>>
      /Contents [5 0 R ]
      /MediaBox [0  0  612  792  ]
      /Parent 3 0 R
    >>
    endobj
    5 0 obj
    <<
      /Length 103 
    >>
    stream
      /DeviceRGB cs
      0 1 0 sc
      50 650 m 250 650 l 250 750 l 50 750 l h f
      q 200 0 0 100 50 650 cm /XO0 Do Q
    endstream
    endobj
    6 0 obj
    <<
      /Subtype /Image
      /Width 16 
      /Height 8 
      /BitsPerComponent 1 
      /ColorSpace /DeviceGray
      /Mask [1  1]
      /Length 16 
    >>
    stream
    UUUUUUUUUUUUUUUU
    endstream
    endobj
    

    This is the result (image drawn on top of green rectangle, U=01010101, white color (1) is transparent): enter image description here