This is an automated email from the ASF dual-hosted git repository.

fanningpj pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 372388b7ed Support rendering transparent bitmaps in presentations. 
(#990)
372388b7ed is described below

commit 372388b7ede7df4eddb4a05c4a80d66723c4bb34
Author: Jacobo Aragunde PĂ©rez <[email protected]>
AuthorDate: Sat Jan 17 13:47:09 2026 +0100

    Support rendering transparent bitmaps in presentations. (#990)
    
    * Support rendering transparent bitmaps in presentations.
    
    Add PictureShape.getAlpha() method and implementations for HSLF and
    XSLF. Then make use of it in DrawPictureShape to apply the right alpha
    value to the picture being drawn.
    
    Fixed a bug in BitmapImageRenderer that considered alpha value 0 as
    "fully opaque", when it means "fully transparent" instead.
    
    Finally, added a test for this feature in TestDrawPictureShape for XSLF.
    A test for HSLF could not be created because it was not possible to
    generate a test file with today's tools; MS Office removes the
    bitmap transparency effect when saving as .ppt, and LibreOffice blends
    it into the bitmap.
    
    * Address reviewer comments.
    
    * Add comment about default alpha value.
    
    * Prevent NPE in XSLFPictureShape.getAlpha().
    
    * Change wording in comments to avoid the word "percentage".
    
    * Use static vars for extreme alpha values.
---
 .../poi/xslf/usermodel/XSLFPictureShape.java       |   8 ++++++
 .../poi/sl/tests/draw/TestDrawPictureShape.java    |  32 ++++++++++++++++++++-
 .../poi/hslf/usermodel/HSLFPictureShape.java       |   6 +++-
 .../apache/poi/sl/draw/BitmapImageRenderer.java    |   3 +-
 .../org/apache/poi/sl/draw/DrawPictureShape.java   |   7 +++++
 .../org/apache/poi/sl/usermodel/PictureShape.java  |  11 +++++++
 test-data/slideshow/picture-transparency.pptx      | Bin 0 -> 11793 bytes
 7 files changed, 64 insertions(+), 3 deletions(-)

diff --git 
a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java 
b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
index 80b5d4a6ce..aec5faccf6 100644
--- 
a/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
+++ 
b/poi-ooxml/src/main/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
@@ -225,6 +225,14 @@ public class XSLFPictureShape extends XSLFSimpleShape
             POIXMLUnits.parsePercent(r.xgetR()));
     }
 
+    public int getAlpha() {
+        CTBlip blip = getBlip();
+        if (blip == null) {
+            return FULLY_OPAQUE_ALPHA_VALUE;
+        }
+        return blip.sizeOfAlphaModFixArray() > 0 ? 
POIXMLUnits.parsePercent(blip.getAlphaModFixArray(0).xgetAmt()) : 
FULLY_OPAQUE_ALPHA_VALUE;
+    }
+
     /**
      * Add a SVG image reference
      * @param svgPic a previously imported svg image
diff --git 
a/poi-ooxml/src/test/java/org/apache/poi/sl/tests/draw/TestDrawPictureShape.java
 
b/poi-ooxml/src/test/java/org/apache/poi/sl/tests/draw/TestDrawPictureShape.java
index 9f5568c4c4..0bd9414d8b 100644
--- 
a/poi-ooxml/src/test/java/org/apache/poi/sl/tests/draw/TestDrawPictureShape.java
+++ 
b/poi-ooxml/src/test/java/org/apache/poi/sl/tests/draw/TestDrawPictureShape.java
@@ -22,8 +22,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assumptions.assumeFalse;
 
-import java.awt.Dimension;
+import java.awt.*;
 import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -117,4 +118,33 @@ class TestDrawPictureShape {
             return val;
         }
     }
+
+    @Test
+    void testAlphaXSLFPictureShape() throws IOException {
+        SlideShow<?,?> ss = openSampleDocument("picture-transparency.pptx");
+
+        // First slide contains a fully opaque bitmap
+        verifySlideFirstPixelColor(ss.getSlides().get(0), new Color(0, 0, 0, 
255));
+        // Second slide contains a 20% transparency bitmap (255*0.8=204)
+        verifySlideFirstPixelColor(ss.getSlides().get(1), new Color(0, 0, 0, 
204));
+        // Third slide contains a 60% transparency bitmap (255*0.4=102)
+        verifySlideFirstPixelColor(ss.getSlides().get(2), new Color(0, 0, 0, 
102));
+        // Fourth slide contains a fully transparent bitmap
+        verifySlideFirstPixelColor(ss.getSlides().get(3), new Color(0, 0, 0, 
0));
+    }
+
+    private void verifySlideFirstPixelColor(Slide<?,?> slide, Color color) {
+        PictureShape<?,?> picShape = null;
+        for (Shape<?,?> shape : slide.getShapes()) {
+            if (shape instanceof PictureShape) {
+                picShape = (PictureShape<?,?>)shape;
+                break;
+            }
+        }
+        assertNotNull(picShape);
+        BufferedImage img = new BufferedImage(100, 100, 
BufferedImage.TYPE_INT_ARGB);
+        new DrawPictureShape(picShape).draw(img.createGraphics());
+        assertEquals(Transparency.TRANSLUCENT, img.getTransparency());
+        assertEquals(color, new Color(img.getRGB(0, 0), true));
+    }
 }
diff --git 
a/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFPictureShape.java
 
b/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFPictureShape.java
index e10a54cb55..ac2f12bd2f 100644
--- 
a/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFPictureShape.java
+++ 
b/poi-scratchpad/src/main/java/org/apache/poi/hslf/usermodel/HSLFPictureShape.java
@@ -228,4 +228,8 @@ public class HSLFPictureShape extends HSLFSimpleShape 
implements PictureShape<HS
         int fixedPoint = prop.getPropertyValue();
         return Units.fixedPointToDouble(fixedPoint);
     }
-}
\ No newline at end of file
+
+    public int getAlpha() {
+        return 
(int)(super.getAlpha(EscherPropertyTypes.FILL__FILLOPACITY)*100000.0);
+    }
+}
diff --git a/poi/src/main/java/org/apache/poi/sl/draw/BitmapImageRenderer.java 
b/poi/src/main/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
index 0cf66780bd..cb3921eac6 100644
--- a/poi/src/main/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
+++ b/poi/src/main/java/org/apache/poi/sl/draw/BitmapImageRenderer.java
@@ -289,7 +289,8 @@ public class BitmapImageRenderer implements ImageRenderer {
             return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
         }
 
-        if (alpha == 0) {
+        if (alpha == 1) {
+            // Do not apply any rescale for a fully opaque alpha value
             return image;
         }
 
diff --git a/poi/src/main/java/org/apache/poi/sl/draw/DrawPictureShape.java 
b/poi/src/main/java/org/apache/poi/sl/draw/DrawPictureShape.java
index 0b9ae3cb13..2dbee57ea5 100644
--- a/poi/src/main/java/org/apache/poi/sl/draw/DrawPictureShape.java
+++ b/poi/src/main/java/org/apache/poi/sl/draw/DrawPictureShape.java
@@ -36,6 +36,9 @@ import org.apache.poi.sl.usermodel.PictureData;
 import org.apache.poi.sl.usermodel.PictureShape;
 import org.apache.poi.sl.usermodel.RectAlign;
 
+import static 
org.apache.poi.sl.usermodel.PictureShape.FULLY_OPAQUE_ALPHA_VALUE;
+import static 
org.apache.poi.sl.usermodel.PictureShape.FULLY_TRANSPARENT_ALPHA_VALUE;
+
 
 public class DrawPictureShape extends DrawSimpleShape {
     private static final Logger LOG = 
PoiLogManager.getLogger(DrawPictureShape.class);
@@ -50,6 +53,7 @@ public class DrawPictureShape extends DrawSimpleShape {
 
         Rectangle2D anchor = getAnchor(graphics, ps);
         Insets insets = ps.getClipping();
+        int alpha = ps.getAlpha();
 
         PictureData[] pics = { ps.getAlternativePictureData(), 
ps.getPictureData() };
         for (PictureData data : pics) {
@@ -66,6 +70,9 @@ public class DrawPictureShape extends DrawSimpleShape {
                 ImageRenderer renderer = getImageRenderer(graphics, ct);
                 if (renderer.canRender(ct)) {
                     renderer.loadImage(dataBytes, ct);
+                    if (FULLY_TRANSPARENT_ALPHA_VALUE <= alpha && alpha < 
FULLY_OPAQUE_ALPHA_VALUE) {
+                        renderer.setAlpha(alpha/(float) 
FULLY_OPAQUE_ALPHA_VALUE);
+                    }
                     renderer.drawImage(graphics, anchor, insets);
                     return;
                 }
diff --git a/poi/src/main/java/org/apache/poi/sl/usermodel/PictureShape.java 
b/poi/src/main/java/org/apache/poi/sl/usermodel/PictureShape.java
index 9f967207bb..bc3dff1e4b 100644
--- a/poi/src/main/java/org/apache/poi/sl/usermodel/PictureShape.java
+++ b/poi/src/main/java/org/apache/poi/sl/usermodel/PictureShape.java
@@ -23,6 +23,9 @@ public interface PictureShape<
     S extends Shape<S,P>,
     P extends TextParagraph<S,P,? extends TextRun>
 > extends SimpleShape<S,P> {
+    public static final int FULLY_TRANSPARENT_ALPHA_VALUE = 0;
+    public static final int FULLY_OPAQUE_ALPHA_VALUE = 100000;
+
     /**
      * Returns the picture data for this picture.
      *
@@ -47,4 +50,12 @@ public interface PictureShape<
      * @return the clipping rectangle, which is given in percent in relation 
to the image width/height
      */
     Insets getClipping();
+
+    /**
+     * Returns alpha value in a range between 0 and 100000.
+     * Value 0 represents complete transparency and 100000 represents complete 
opacity.
+     * @return alpha value in the range 0..100000.
+     * @since 6.0.0
+     */
+    int getAlpha();
 }
diff --git a/test-data/slideshow/picture-transparency.pptx 
b/test-data/slideshow/picture-transparency.pptx
new file mode 100644
index 0000000000..41121f7dde
Binary files /dev/null and b/test-data/slideshow/picture-transparency.pptx 
differ


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to