Author: tilman
Date: Mon Sep 14 19:50:50 2026
New Revision: 1938211

Log:
PDFBOX-6258: clamp colors for shading in the colorspace class, cache ranges, 
add test

Modified:
   
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java
   
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java
   
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java
   
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/color/PDLabTest.java

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java
        Mon Sep 14 19:50:39 2026        (r1938210)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java
        Mon Sep 14 19:50:50 2026        (r1938211)
@@ -382,6 +382,26 @@ public abstract class PDColorSpace imple
         return dest;
     }
 
+    /**
+     * Clamp color values to allowed ranges, usually 0..1.
+     *
+     * @param values 
+     */
+    public void clamp(float[] values)
+    {
+        for (int i = 0; i < values.length; ++i)
+        {
+            if (values[i] < 0)
+            {
+                values[i] = 0;
+            }
+            else if (values[i] > 1)
+            {
+                values[i] = 1;
+            }
+        }
+    }
+
     @Override
     public COSBase getCOSObject()
     {

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java
       Mon Sep 14 19:50:39 2026        (r1938210)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java
       Mon Sep 14 19:50:50 2026        (r1938211)
@@ -35,12 +35,18 @@ public final class PDLab extends PDCIEDi
 {
     private PDColor initialColor;
     
+    private float minA = -100;
+    private float maxA = 100;
+    private float minB = -100;
+    private float maxB = 100;
+    
     /**
      * Creates a new Lab color space.
      */
     public PDLab()
     {
         super(COSName.LAB);
+        cacheRanges();
     }
 
     /**
@@ -50,6 +56,7 @@ public final class PDLab extends PDCIEDi
     public PDLab(COSArray lab)
     {
         super(lab);
+        cacheRanges();
     }
     
     @Override
@@ -70,12 +77,6 @@ public final class PDLab extends PDCIEDi
         BufferedImage rgbImage = new BufferedImage(width, height, 
BufferedImage.TYPE_INT_RGB);
         WritableRaster rgbRaster = rgbImage.getRaster();
 
-        PDRange aRange = getARange();
-        PDRange bRange = getBRange();
-        float minA = aRange.getMin();
-        float maxA = aRange.getMax();
-        float minB = bRange.getMin();
-        float maxB = bRange.getMax();
         float deltaA = maxA - minA;
         float deltaB = maxB - minB;
 
@@ -158,9 +159,7 @@ public final class PDLab extends PDCIEDi
     @Override
     public float[] getDefaultDecode(int bitsPerComponent)
     {
-        PDRange a = getARange();
-        PDRange b = getBRange();
-        return new float[] { 0, 100, a.getMin(), a.getMax(), b.getMin(), 
b.getMax() };
+        return new float[] { 0, 100, minA, maxA, minB, maxB };
     }
 
     @Override
@@ -170,8 +169,8 @@ public final class PDLab extends PDCIEDi
         {
             initialColor = new PDColor(new float[] {
                     0,
-                    Math.max(0, getARange().getMin()),
-                    Math.max(0, getBRange().getMin()) },
+                    Math.max(0, minA),
+                    Math.max(0, minB) },
                     this);
         }
         return initialColor;
@@ -263,6 +262,50 @@ public final class PDLab extends PDCIEDi
         }
         dictionary.setItem(COSName.RANGE, rangeArray);
         initialColor = null;
+        cacheRanges();
+    }
+
+    // called at the beginning and when it's changed
+    private void cacheRanges()
+    {
+        PDRange aRange = getARange();
+        PDRange bRange = getBRange();
+        minA = aRange.getMin();
+        maxA = aRange.getMax();
+        minB = bRange.getMin();
+        maxB = bRange.getMax();
     }
 
+    @Override
+    public void clamp(float[] values)
+    {
+        // assumption: 3 elements: L a b
+        // "The range of the first (L*) component shall be 0 to 100; 
+        //  the ranges of the second and third (a* and b*) components shall be 
defined by 
+        //  the Range entry in the colour space dictionary"
+        if (values[0] < 0)
+        {
+            values[0] = 0;
+        }
+        else if (values[0] > 100)
+        {
+            values[0] = 100;
+        }
+        if (values[1] < minA)
+        {
+            values[1] = minA;
+        }
+        else if (values[1] > maxA)
+        {
+            values[1] = maxA;
+        }
+        if (values[2] < minB)
+        {
+            values[2] = minB;
+        }
+        else if (values[2] > maxB)
+        {
+            values[2] = maxB;
+        }
+    }
 }

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java
 Mon Sep 14 19:50:39 2026        (r1938210)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java
 Mon Sep 14 19:50:50 2026        (r1938211)
@@ -421,17 +421,7 @@ public abstract class PDShading implemen
         // From the PDF spec:
         // "If the value returned by the function for a given colour component 
         // is out of range, it shall be adjusted to the nearest valid value."
-        for (int i = 0; i < returnValues.length; ++i)
-        {
-            if (returnValues[i] < 0)
-            {
-                returnValues[i] = 0;
-            }
-            else if (returnValues[i] > 1)
-            {
-                returnValues[i] = 1;
-            }
-        }
+        colorSpace.clamp(returnValues);
         return returnValues;
     }
 

Modified: 
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/color/PDLabTest.java
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/color/PDLabTest.java
   Mon Sep 14 19:50:39 2026        (r1938210)
+++ 
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/color/PDLabTest.java
   Mon Sep 14 19:50:50 2026        (r1938211)
@@ -93,4 +93,32 @@ class PDLabTest
         assertTrue(Arrays.equals(new float[]{0,0,3}, 
pdLab.getInitialColor().getComponents()));
     }
 
+    @Test
+    void testClamp()
+    {
+        PDLab lab = new PDLab();
+        PDRange aRange = new PDRange();
+        aRange.setMin(-160);
+        aRange.setMax(160);
+        lab.setARange(aRange);
+        PDRange bRange = new PDRange();
+        bRange.setMin(-160);
+        bRange.setMax(160);
+        lab.setBRange(bRange);
+        float[] lab1 = new float[]{-101, -161, -161};
+        float[] lab2 = new float[]{-100, -160, -160};
+        float[] lab3 = new float[]{0, 0, 0};
+        float[] lab4 = new float[]{100, 160, 160};
+        float[] lab5 = new float[]{101, 161, 161};
+        lab.clamp(lab1);
+        lab.clamp(lab2);
+        lab.clamp(lab3);
+        lab.clamp(lab4);
+        lab.clamp(lab5);
+        assertEquals("[0.0, -160.0, -160.0]", Arrays.toString(lab1));
+        assertEquals("[0.0, -160.0, -160.0]", Arrays.toString(lab2));
+        assertEquals("[0.0, 0.0, 0.0]", Arrays.toString(lab3));
+        assertEquals("[100.0, 160.0, 160.0]", Arrays.toString(lab4));
+        assertEquals("[100.0, 160.0, 160.0]", Arrays.toString(lab5));
+    }
 }

Reply via email to