mirror of
https://github.com/apache/poi.git
synced 2026-02-27 12:30:08 +08:00
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.
This commit is contained in:
parent
e3e04a641f
commit
372388b7ed
@ -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
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,4 +228,8 @@ public class HSLFPictureShape extends HSLFSimpleShape implements PictureShape<HS
|
||||
int fixedPoint = prop.getPropertyValue();
|
||||
return Units.fixedPointToDouble(fixedPoint);
|
||||
}
|
||||
}
|
||||
|
||||
public int getAlpha() {
|
||||
return (int)(super.getAlpha(EscherPropertyTypes.FILL__FILLOPACITY)*100000.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
BIN
test-data/slideshow/picture-transparency.pptx
Normal file
BIN
test-data/slideshow/picture-transparency.pptx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user