PDFBox
  1. PDFBox
  2. PDFBOX-1445

/ImageMask true does not work. Patch included.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.8.0
    • Component/s: None
    • Labels:
      None

      Description

      I have the following pdf...

      10 0 obj
      <<
      /Type /Page
      /MediaBox [ 0 0 612.0 792.0 ]
      /Parent 3 0 R
      /Resources << /XObject << /Obj4 4 0 R /Obj5 5 0 R /Obj6 6 0 R /Obj7 7 0 R >> /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >>
      /Contents [ 8 0 R 9 0 R ]
      >>
      endobj

      Which then draws 4 images. The first one is a "base" and then rest are image masks

      9 0 obj
      << /Filter /FlateDecode /Length 121 >>
      stream
      q
      612.00 0 0 792.00 0.00 0.00 cm
      /Obj4 Do
      Q
      q
      0.129 g
      524.16 0 0 556.80 48.00 127.68 cm
      /Obj5 Do
      Q
      q
      0.302 g
      220.80 0 0 398.40 48.00 286.08 cm
      /Obj6 Do
      Q
      q
      0.204 g
      524.16 0 0 469.44 48.00 185.28 cm
      /Obj7 Do
      Q
      endstream
      endobj

      4 0 obj
      << /Type /XObject /Subtype /Image /Width 1275 /Height 1650 /BitsPerComponent 8
      /ColorSpace /DeviceGray /Filter [ /FlateDecode /DCTDecode ] /Length 50485 >>
      stream
      endstream
      endobj

      5 0 obj
      << /Type /XObject /Subtype /Image /Width 2184 /Height 2320 /BitsPerComponent 1
      /ImageMask true /Filter /CCITTFaxDecode /DecodeParms << /K -1 /Columns 2184 >>
      /Length 15580 >>
      stream

      etc ...

      The current code simply treats the imagemask as an image. Since this is just a 1 bit image it has no Alpha channel it overwrites the existing image and we simply get the last image drawn.

      In

      org.apache.pdfbox.util.operator.pagedrawer.Invoke.java

      method

      public void process(PDFOperator operator, List<COSBase> arguments) throws IOException

      after

      if (awtImage == null)

      { LOG.warn("getRGBImage returned NULL"); return;//TODO PKOCH }

      If you add the following code it fixes the problem. I can not provide the sample doc due to privacy reasons.

      /**

      • Spec 8.9.6.2
      • If ImageMask is true then the image is one bit. Black means draw the current colour and white means use the colour on the current image (ie Mask).
      • Convert the map to an image with an Alpha channel so we can lay it on top
        */
        if(image.getImageMask())
        {
        Color currentColour = drawer.getGraphicsState().getStrokingColor().getJavaColor();
        final int onColour = 0xff000000 | currentColour.getRGB();
        BufferedImage bia = new BufferedImage(awtImage.getWidth(),awtImage.getHeight(),BufferedImage.TYPE_INT_ARGB);
        for(int y=0;y<awtImage.getHeight();y++)
        Unknown macro: { for(int x=0;x<awtImage.getWidth();x++) { bia.setRGB(x, y, (awtImage.getRGB(x, y) & 0x00ffffff) == 0xffffff ? 0x00ffffff : onColour); } }

        awtImage = bia;
        }

      1. PDCcitt.java.patch
        2 kB
        Dave Smith
      2. PDJpeg.java.patch
        1 kB
        Dave Smith
      3. PDPixelMap.java.patch
        3 kB
        Dave Smith
      4. PDXObjectImage.java.patch
        4 kB
        Dave Smith

        Activity

        Dave Smith created issue -
        Hide
        Andreas Lehmkühler added a comment -

        Can't we just use the code which already exists in PDPixelMap (starting at line 369)? It should be faster.

        P.S.: Please attach patches as diff to make it easier for us the apply them

        Show
        Andreas Lehmkühler added a comment - Can't we just use the code which already exists in PDPixelMap (starting at line 369)? It should be faster. P.S.: Please attach patches as diff to make it easier for us the apply them
        Hide
        Dave Smith added a comment -

        Nope. We only have one ImageMask and the current state of the drawn images. PDPixelMap assumes you have an image and a image mask. What I am doing is converting an ImageMask to an image that we can write on top to the current image

        I will figure out how eclipse generates patches and go from there. Unfortunately there is other debug code I have in there so it is not so easy .....

        Show
        Dave Smith added a comment - Nope. We only have one ImageMask and the current state of the drawn images. PDPixelMap assumes you have an image and a image mask. What I am doing is converting an ImageMask to an image that we can write on top to the current image I will figure out how eclipse generates patches and go from there. Unfortunately there is other debug code I have in there so it is not so easy .....
        Hide
        Andreas Lehmkühler added a comment -

        PDPixelMap combines 2 images if it contains a soft mask (SMask == true). If it is an image mask it will be used to create a mask using the nonstroking color and the 1-pixel map.

        Show
        Andreas Lehmkühler added a comment - PDPixelMap combines 2 images if it contains a soft mask (SMask == true). If it is an image mask it will be used to create a mask using the nonstroking color and the 1-pixel map.
        Hide
        Dave Smith added a comment -

        I see it now. BUT .. In my case I have an /ImageMask that is type PDCcitt and a /Mask that is a JBIG2 and they do not go through the PDPixelMap code...

        Show
        Dave Smith added a comment - I see it now. BUT .. In my case I have an /ImageMask that is type PDCcitt and a /Mask that is a JBIG2 and they do not go through the PDPixelMap code...
        Hide
        Andreas Lehmkühler added a comment -

        The idea is to replace your code with the code from PDPixelMap and remove the code from PDPIxelMap. So that the ImageMask stuff will be used with all kind of PDXObjectImages (PixelMap, Ccitt and Jpeg). WDYT

        Show
        Andreas Lehmkühler added a comment - The idea is to replace your code with the code from PDPixelMap and remove the code from PDPIxelMap. So that the ImageMask stuff will be used with all kind of PDXObjectImages (PixelMap, Ccitt and Jpeg). WDYT
        Hide
        Dave Smith added a comment -

        These move the /ImageMask and /Mask code to the base PDXObjectImage class

        Each class that extends the PDXObjectImage simply call applyMask at the end.

        Show
        Dave Smith added a comment - These move the /ImageMask and /Mask code to the base PDXObjectImage class Each class that extends the PDXObjectImage simply call applyMask at the end.
        Dave Smith made changes -
        Field Original Value New Value
        Attachment PDPixelMap.java.patch [ 12553391 ]
        Attachment PDXObjectImage.java.patch [ 12553392 ]
        Attachment PDJpeg.java.patch [ 12553393 ]
        Attachment PDCcitt.java.patch [ 12553394 ]
        Hide
        Dave Smith added a comment -

        I have included fixed for both /ImageMask and /Mask . The latter was not being handled at all. I have samples for both but I need the ttps://issues.apache.org/jira/browse/PDFBOX-1067 applied to test the /Mask case...

        Show
        Dave Smith added a comment - I have included fixed for both /ImageMask and /Mask . The latter was not being handled at all. I have samples for both but I need the ttps://issues.apache.org/jira/browse/PDFBOX-1067 applied to test the /Mask case...
        Hide
        Andreas Lehmkühler added a comment -

        I applied the patch in revision 1410890 as proposed.

        Thanks for the contribution

        Show
        Andreas Lehmkühler added a comment - I applied the patch in revision 1410890 as proposed. Thanks for the contribution
        Andreas Lehmkühler made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Assignee Andreas Lehmkühler [ lehmi ]
        Fix Version/s 1.8.0 [ 12321650 ]
        Resolution Fixed [ 1 ]
        Hide
        Andreas Lehmkühler added a comment -

        Revision 1410890 introduced a regression. PDJpeg#write2OutputStream no longer writes the image due to a null reference.

        I fixed that in revision 1419000.

        Show
        Andreas Lehmkühler added a comment - Revision 1410890 introduced a regression. PDJpeg#write2OutputStream no longer writes the image due to a null reference. I fixed that in revision 1419000.
        Andreas Lehmkühler made changes -
        Status Resolved [ 5 ] Closed [ 6 ]

          People

          • Assignee:
            Andreas Lehmkühler
            Reporter:
            Dave Smith
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development