Bug 54541 - Add support for cropped images in Slide.draw()

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1648335 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2014-12-29 13:35:57 +00:00
parent bfffe6cb4f
commit 8e3eee35cd
5 changed files with 159 additions and 42 deletions

View File

@ -22,6 +22,9 @@ import org.apache.poi.hslf.model.Picture;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
/* ==================================================================== /* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -39,7 +42,9 @@ import org.apache.poi.util.POILogFactory;
limitations under the License. limitations under the License.
==================================================================== */ ==================================================================== */
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -54,15 +59,36 @@ public final class BitmapPainter implements ImagePainter {
public void paint(Graphics2D graphics, PictureData pict, Picture parent) { public void paint(Graphics2D graphics, PictureData pict, Picture parent) {
BufferedImage img; BufferedImage img;
try { try {
img = ImageIO.read(new ByteArrayInputStream(pict.getData())); img = ImageIO.read(new ByteArrayInputStream(pict.getData()));
} } catch (Exception e) {
catch (Exception e){
logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + pict.getType()); logger.log(POILogger.WARN, "ImageIO failed to create image. image.type: " + pict.getType());
return; 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(); 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);
} }
} }

View File

@ -18,6 +18,7 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -264,4 +265,40 @@ public class Picture extends SimpleShape {
graphics.setTransform(at); 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 <a href="http://msdn.microsoft.com/en-us/library/dd910765(v=office.12).aspx">2.2.1.6 FixedPoint</a>
*/
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;
}
}

View File

@ -17,39 +17,35 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import junit.framework.Test; import org.junit.runner.RunWith;
import junit.framework.TestSuite; import org.junit.runners.Suite;
/** /**
* Collects all tests from the package <tt>org.apache.poi.hslf.model</tt>. * Collects all tests from the package <tt>org.apache.poi.hslf.model</tt>.
*
* @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 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;
}
} }

View File

@ -17,26 +17,38 @@
package org.apache.poi.hslf.model; 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.Graphics2D;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; 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 javax.imageio.ImageIO;
import junit.framework.TestCase; import org.apache.poi.POIDataSamples;
import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.hslf.HSLFSlideShow; import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.PictureData; import org.apache.poi.hslf.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow; 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. * Test Picture shape.
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public final class TestPicture extends TestCase { public final class TestPicture {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); 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. * 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(); SlideShow ppt = new SlideShow();
Slide s = ppt.createSlide(); Slide s = ppt.createSlide();
@ -78,7 +91,8 @@ public final class TestPicture extends TestCase {
* Picture#getEscherBSERecord threw NullPointerException if EscherContainerRecord.BSTORE_CONTAINER * Picture#getEscherBSERecord threw NullPointerException if EscherContainerRecord.BSTORE_CONTAINER
* was not found. The correct behaviour is to return null. * was not found. The correct behaviour is to return null.
*/ */
public void test46122() { @Test
public void bug46122() {
SlideShow ppt = new SlideShow(); SlideShow ppt = new SlideShow();
Slide slide = ppt.createSlide(); Slide slide = ppt.createSlide();
@ -92,7 +106,8 @@ public final class TestPicture extends TestCase {
pict.draw(graphics); pict.draw(graphics);
} }
public void testMacImages() throws Exception { @Test
public void macImages() throws Exception {
HSLFSlideShow hss = new HSLFSlideShow(_slTests.openResourceAsStream("53446.ppt")); HSLFSlideShow hss = new HSLFSlideShow(_slTests.openResourceAsStream("53446.ppt"));
PictureData[] pictures = hss.getPictures(); 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<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(TextPainter.KEY_FONTMAP);
if (fontMap == null) fontMap = new HashMap<String,String>();
fontMap.put("Calibri", "Lucida Sans");
fontMap.put("Cambria", "Lucida Bright");
graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap);
}
} }

Binary file not shown.