diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/BitmapPainter.java b/src/scratchpad/src/org/apache/poi/hslf/blip/BitmapPainter.java
index ecc368c2b..aae83bf6e 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/blip/BitmapPainter.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/blip/BitmapPainter.java
@@ -22,6 +22,9 @@ import org.apache.poi.hslf.model.Picture;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
+
+
+
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -39,7 +42,9 @@ import org.apache.poi.util.POILogFactory;
limitations under the License.
==================================================================== */
import javax.imageio.ImageIO;
+
import java.awt.*;
+import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
@@ -54,15 +59,36 @@ public final class BitmapPainter implements ImagePainter {
public void paint(Graphics2D graphics, PictureData pict, Picture parent) {
BufferedImage img;
try {
- img = ImageIO.read(new ByteArrayInputStream(pict.getData()));
- }
- catch (Exception e){
+ img = ImageIO.read(new ByteArrayInputStream(pict.getData()));
+ } catch (Exception e) {
logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + pict.getType());
return;
}
+ boolean isClipped = true;
+ Insets clip = parent.getBlipClip();
+ if (clip == null) {
+ isClipped = false;
+ clip = new Insets(0,0,0,0);
+ }
+
+ int iw = img.getWidth();
+ int ih = img.getHeight();
+
Rectangle anchor = parent.getLogicalAnchor2D().getBounds();
- graphics.drawImage(img, anchor.x, anchor.y, anchor.width, anchor.height, null);
+
+ double cw = (100000-clip.left-clip.right) / 100000.0;
+ double ch = (100000-clip.top-clip.bottom) / 100000.0;
+ double sx = anchor.getWidth()/(iw*cw);
+ double sy = anchor.getHeight()/(ih*ch);
+ double tx = anchor.getX()-(iw*sx*clip.left/100000.0);
+ double ty = anchor.getY()-(ih*sy*clip.top/100000.0);
+ AffineTransform at = new AffineTransform(sx, 0, 0, sy, tx, ty) ;
+
+ Shape clipOld = graphics.getClip();
+ if (isClipped) graphics.clip(anchor.getBounds2D());
+ graphics.drawRenderedImage(img, at);
+ graphics.setClip(clipOld);
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
index eac973ef6..ea6777dee 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
@@ -18,6 +18,7 @@
package org.apache.poi.hslf.model;
import java.awt.Graphics2D;
+import java.awt.Insets;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
@@ -264,4 +265,40 @@ public class Picture extends SimpleShape {
graphics.setTransform(at);
}
-}
+
+ /**
+ * Returns the clipping values as percent ratio relatively to the image size.
+ * The anchor specified by {@link #getLogicalAnchor2D()} is the displayed size,
+ * i.e. the size of the already clipped image
+ *
+ * @return the clipping as insets converted/scaled to 100000 (=100%)
+ */
+ public Insets getBlipClip() {
+ EscherOptRecord opt = getEscherOptRecord();
+
+ double top = getFractProp(opt, EscherProperties.BLIP__CROPFROMTOP);
+ double bottom = getFractProp(opt, EscherProperties.BLIP__CROPFROMBOTTOM);
+ double left = getFractProp(opt, EscherProperties.BLIP__CROPFROMLEFT);
+ double right = getFractProp(opt, EscherProperties.BLIP__CROPFROMRIGHT);
+
+ // if all crop values are zero (the default) then no crop rectangle is set, return null
+ return (top==0 && bottom==0 && left==0 && right==0)
+ ? null
+ : new Insets((int)(top*100000), (int)(left*100000), (int)(bottom*100000), (int)(right*100000));
+ }
+
+ /**
+ * @return the fractional property or 0 if not defined
+ *
+ * @see 2.2.1.6 FixedPoint
+ */
+ private static double getFractProp(EscherOptRecord opt, short propertyId) {
+ EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propertyId);
+ if (prop == null) return 0;
+ int fixedPoint = prop.getPropertyValue();
+ int i = (fixedPoint >> 16);
+ int f = (fixedPoint >> 0) & 0xFFFF;
+ double fp = i + f/65536.0;
+ return fp;
+ }
+}
\ No newline at end of file
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java
index aac72a28e..71cd5f570 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java
@@ -17,39 +17,35 @@
package org.apache.poi.hslf.model;
-import junit.framework.Test;
-import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
/**
* Collects all tests from the package org.apache.poi.hslf.model.
- *
- * @author Josh Micich
*/
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ TestBackground.class,
+ TestFreeform.class,
+ TestHeadersFooters.class,
+ TestHyperlink.class,
+ TestImagePainter.class,
+ TestLine.class,
+ TestMovieShape.class,
+ TestOleEmbedding.class,
+ TestPPFont.class,
+ TestPPGraphics2D.class,
+ TestPicture.class,
+ TestSetBoldItalic.class,
+ TestShapes.class,
+ TestSheet.class,
+ TestSlideChangeNotes.class,
+ TestSlideMaster.class,
+ TestSlides.class,
+ TestTable.class,
+ TestTextRun.class,
+ TestTextRunReWrite.class,
+ TestTextShape.class
+})
public class AllHSLFModelTests {
-
- public static Test suite() {
- TestSuite result = new TestSuite(AllHSLFModelTests.class.getName());
- result.addTestSuite(TestBackground.class);
- result.addTestSuite(TestFreeform.class);
- result.addTestSuite(TestHeadersFooters.class);
- result.addTestSuite(TestHyperlink.class);
- result.addTestSuite(TestImagePainter.class);
- result.addTestSuite(TestLine.class);
- result.addTestSuite(TestMovieShape.class);
- result.addTestSuite(TestOleEmbedding.class);
- result.addTestSuite(TestPPFont.class);
- result.addTestSuite(TestPPGraphics2D.class);
- result.addTestSuite(TestPicture.class);
- result.addTestSuite(TestSetBoldItalic.class);
- result.addTestSuite(TestShapes.class);
- result.addTestSuite(TestSheet.class);
- result.addTestSuite(TestSlideChangeNotes.class);
- result.addTestSuite(TestSlideMaster.class);
- result.addTestSuite(TestSlides.class);
- result.addTestSuite(TestTable.class);
- result.addTestSuite(TestTextRun.class);
- result.addTestSuite(TestTextRunReWrite.class);
- result.addTestSuite(TestTextShape.class);
- return result;
- }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java
index 3444ae5fe..fabf63bee 100644
--- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java
+++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java
@@ -17,26 +17,38 @@
package org.apache.poi.hslf.model;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
import javax.imageio.ImageIO;
-import junit.framework.TestCase;
-
+import org.apache.poi.POIDataSamples;
import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow;
-import org.apache.poi.POIDataSamples;
+import org.apache.poi.util.JvmBugs;
+import org.junit.Ignore;
+import org.junit.Test;
/**
* Test Picture shape.
*
* @author Yegor Kozlov
*/
-public final class TestPicture extends TestCase {
+public final class TestPicture {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
/**
@@ -44,7 +56,8 @@ public final class TestPicture extends TestCase {
* This is important when the same image appears multiple times in a slide show.
*
*/
- public void testMultiplePictures() throws Exception {
+ @Test
+ public void multiplePictures() throws Exception {
SlideShow ppt = new SlideShow();
Slide s = ppt.createSlide();
@@ -78,7 +91,8 @@ public final class TestPicture extends TestCase {
* Picture#getEscherBSERecord threw NullPointerException if EscherContainerRecord.BSTORE_CONTAINER
* was not found. The correct behaviour is to return null.
*/
- public void test46122() {
+ @Test
+ public void bug46122() {
SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide();
@@ -92,7 +106,8 @@ public final class TestPicture extends TestCase {
pict.draw(graphics);
}
- public void testMacImages() throws Exception {
+ @Test
+ public void macImages() throws Exception {
HSLFSlideShow hss = new HSLFSlideShow(_slTests.openResourceAsStream("53446.ppt"));
PictureData[] pictures = hss.getPictures();
@@ -128,4 +143,47 @@ public final class TestPicture extends TestCase {
}
}
}
+
+ @Test
+ @Ignore("Just for visual validation - antialiasing is different on various systems")
+ public void bug54541() throws Exception {
+// InputStream xis = _slTests.openResourceAsStream("54542_cropped_bitmap.pptx");
+// XMLSlideShow xss = new XMLSlideShow(xis);
+// xis.close();
+//
+// Dimension xpg = xss.getPageSize();
+// for(XSLFSlide slide : xss.getSlides()) {
+// BufferedImage img = new BufferedImage(xpg.width, xpg.height, BufferedImage.TYPE_INT_RGB);
+// Graphics2D graphics = img.createGraphics();
+// fixFonts(graphics);
+// slide.draw(graphics);
+// ImageIO.write(img, "PNG", new File("testx.png"));
+// }
+//
+// System.out.println("########################");
+
+ InputStream is = _slTests.openResourceAsStream("54541_cropped_bitmap.ppt");
+ SlideShow ss = new SlideShow(is);
+ is.close();
+
+ Dimension pg = ss.getPageSize();
+ int i=1;
+ for(Slide slide : ss.getSlides()) {
+ BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_RGB);
+ Graphics2D graphics = img.createGraphics();
+ fixFonts(graphics);
+ slide.draw(graphics);
+ ImageIO.write(img, "PNG", new File("test"+(i++)+".png"));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void fixFonts(Graphics2D graphics) {
+ if (!JvmBugs.hasLineBreakMeasurerBug()) return;
+ Map fontMap = (Map)graphics.getRenderingHint(TextPainter.KEY_FONTMAP);
+ if (fontMap == null) fontMap = new HashMap();
+ fontMap.put("Calibri", "Lucida Sans");
+ fontMap.put("Cambria", "Lucida Bright");
+ graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap);
+ }
}
diff --git a/test-data/slideshow/54541_cropped_bitmap.ppt b/test-data/slideshow/54541_cropped_bitmap.ppt
new file mode 100644
index 000000000..3c631a16f
Binary files /dev/null and b/test-data/slideshow/54541_cropped_bitmap.ppt differ