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:
parent
bfffe6cb4f
commit
8e3eee35cd
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
test-data/slideshow/54541_cropped_bitmap.ppt
Normal file
BIN
test-data/slideshow/54541_cropped_bitmap.ppt
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user