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)


Reply via email to