You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@pdfbox.apache.org by GitBox <gi...@apache.org> on 2021/06/24 23:20:42 UTC

[GitHub] [pdfbox] gunnar-ifp edited a comment on pull request #121: optimize applyMask in PdImageXObject

gunnar-ifp edited a comment on pull request #121:
URL: https://github.com/apache/pdfbox/pull/121#issuecomment-868018899


   Yes, I would like to keep the interpolation block. 
   
   The PDF 8.9.6.2 spec says that stencil masks can have an interpolate flag, and when enabled to interpolate the mask, not the colors, so low res stencil masks don't appear with jagged edges.
   
   Originally this happens when the image / mask are rendered onto the canvas, but we apply the mask before hand w/o knowing the target resolution. This is why we have to interpolate ourself and also work in maybe way too high of image size.
   
   But I noticed a few things while writing this text:
   
   We do extend the the 1 bit stencil mask to 8 bit, which might pose an interesting problem:
   Looking at the PDFBOX-4218, if instead the image was 48 pixel wide and the mask 6 pixel, and interpolate flag set for the mask, this would create alpha blending near the masked out areas. It would be interesting to create such a file and see how other pdf engines behave. But if this is wrong, one can simply clamp the alpha value to 0 and 255 with a threshold at 127 when writing the alpha value into the stencil mask image (I reckon this should not be done for soft masks). I do believe that the current behaviour is the better choice.
   
   As for interpolating the image, if we knew the target resolution it's going to be rendered in the end, we could scale everything bigger than that down to that and then proceed. But we don't and the PDF spec says that mask and image can have different resolutions, even aspect ratios, but get squeezed into the same target rectangle. We need to emulate that and that's why we scale up to the larger one.
   So if we were to not interpolate the image when scaling it up to the mask, we can introduce a crappy, jagged image, which might be actually written 1:1 to the canvas because maybe the mask is in the resolution of the final render. Usually rendering a non masked image to the canvas will do the proper interpolation, whatever is set in the canvas graphics, but we are circumventing that in applyMask() with large masks.
   
   PDFBOX-2750 doesn't use interpolation so scaleImage doesn't interpolate. And it's just a color soup background (you can't really see it in PDFDebugger because the mask is always applied, but if one disabled the alpha composition in applyMask() it shows the soup). So differences are probably almost invisible. With disabled alpha composition and forced interpolation jagged vs not so jagged diagonal lines are clearly visible in the soup, they are simply not visible with the stencil mask:
   ![PDF2750-bgsoup_jagged](https://user-images.githubusercontent.com/23260584/123341607-8a562980-d54e-11eb-8700-f356241c3615.jpg)
   ![PDF2750-bgsoup_soft](https://user-images.githubusercontent.com/23260584/123341616-8e824700-d54e-11eb-8750-6428b9bd258b.jpg)
   Still shows that image interpolation is good when it is requested by the image.
   
   Even worse, we are violating that overlay principle sometimes:
   If there is an image with 100 x 100 and the mask is 200 x 10, we will scale the mask to 100 x 100 when we actually must scale everything to 200 x 100 as to not deliberately reduce resolution of image or mask.
   
   Seeing that interpolation is not that slow once we switch to bilinear, I could live with it. For very large scaling operations even worse than 10*10 maybe one should switch to nearest neighbor. I was looking for faster image scaling in java and did find AffineTransformationOp, which is handled by java natively and I thought that the Graphics instances use that already. Turns out it is still faster except for nearest neighbor (results for Alfa Page 1):
   Graphics.drawImage():
   Bicubic / Quality: 5.83s
   Bicubic / Speed: 5.83s
   Bilinear / Speed: 1.74s
   Nearest Neighbor: 0.11
   AffineTransformOp.filter() (no difference in speeds between Raster and BufferedImage (even if src = RGB and dst = ARGB)
   Bicubic: 4.79
   Bilinear: 1.5s
   Nearest Neighbor: 0.47
   
   I added some code for both the Op and the Max(mask, image).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@pdfbox.apache.org
For additional commands, e-mail: dev-help@pdfbox.apache.org