Author: tilman Date: Wed Oct 9 11:05:09 2024 New Revision: 1921203 URL: http://svn.apache.org/viewvc?rev=1921203&view=rev Log: PDFBOX-5884: support OCG visibility expressions
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java?rev=1921203&r1=1921202&r2=1921203&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Wed Oct 9 11:05:09 2024 @@ -2099,10 +2099,10 @@ public class PageDrawer extends PDFGraph private boolean isHiddenOCMD(PDOptionalContentMembershipDictionary ocmd) { - if (ocmd.getCOSObject().getCOSArray(COSName.VE) != null) + COSArray veArray = ocmd.getCOSObject().getCOSArray(COSName.VE); + if (veArray != null && !veArray.isEmpty()) { - // support seems to be optional, and is approximated by /P and /OCGS - LOG.info("/VE entry ignored in Optional Content Membership Dictionary"); + return isHiddenVisibilityExpression(veArray); } List<PDPropertyList> oCGs = ocmd.getOCGs(); if (oCGs.isEmpty()) @@ -2136,6 +2136,109 @@ public class PageDrawer extends PDFGraph return visibles.stream().noneMatch(v -> v); } + private boolean isHiddenVisibilityExpression(COSArray veArray) + { + if (veArray.isEmpty()) + { + return false; + } + String op = veArray.getName(0); + if (op == null) + { + return false; + } + switch (op) + { + case "And": + return isHiddenAndVisibilityExpression(veArray); + case "Or": + return isHiddenOrVisibilityExpression(veArray); + case "Not": + return isHiddenNotVisibilityExpression(veArray); + default: + return false; + } + } + + private boolean isHiddenAndVisibilityExpression(COSArray veArray) + { + // hidden if at least one isn't visible + for (int i = 1; i < veArray.size(); ++i) + { + COSBase base = veArray.getObject(i); + if (base instanceof COSArray) + { + // Another VE + boolean isHidden = isHiddenVisibilityExpression((COSArray) base); + if (isHidden) + { + return true; + } + } + else if (base instanceof COSDictionary) + { + // Another OCG + PDPropertyList prop = PDOptionalContentGroup.create((COSDictionary) base); + boolean isHidden = isHiddenOCG(prop); + if (isHidden) + { + return true; + } + } + } + return false; + } + + private boolean isHiddenOrVisibilityExpression(COSArray veArray) + { + // hidden only if all are hidden + for (int i = 1; i < veArray.size(); ++i) + { + COSBase base = veArray.getObject(i); + if (base instanceof COSArray) + { + // Another VE + boolean isHidden = isHiddenVisibilityExpression((COSArray) base); + if (!isHidden) + { + return false; + } + } + else if (base instanceof COSDictionary) + { + // Another OCG + PDPropertyList prop = PDOptionalContentGroup.create((COSDictionary) base); + boolean isHidden = isHiddenOCG(prop); + if (!isHidden) + { + return false; + } + } + } + return true; + } + + private boolean isHiddenNotVisibilityExpression(COSArray veArray) + { + if (veArray.size() != 2) + { + return false; + } + COSBase base = veArray.getObject(1); + if (base instanceof COSArray) + { + // Another VE + return !isHiddenVisibilityExpression((COSArray) base); + } + else if (base instanceof COSDictionary) + { + // Another OCG + PDPropertyList prop = PDOptionalContentGroup.create((COSDictionary) base); + return !isHiddenOCG(prop); + } + return false; + } + private LookupTable getInvLookupTable() { if (invTable == null)