Add support for HSLF metro blobs

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1713318 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-11-08 23:13:28 +00:00
parent 1a32b63fd3
commit e8d108ff22
10 changed files with 235 additions and 50 deletions

View File

@ -61,7 +61,7 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
protected XSLFGroupShape(CTGroupShape shape, XSLFSheet sheet){
super(shape,sheet);
_shapes = sheet.buildShapes(shape);
_shapes = XSLFSheet.buildShapes(shape, sheet);
_grpSpPr = shape.getGrpSpPr();
}

View File

@ -0,0 +1,60 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.xslf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.util.Internal;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
/**
* Experimental class for metro blobs, i.e. an alternative escher property
* containing an ooxml representation of the shape.
* This is the helper class for HSLFMetroShape to dive into OOXML classes
*/
@Internal
public class XSLFMetroShape {
/*
* parses the metro bytes to a XSLF shape
*/
public static Shape<?,?> parseShape(byte metroBytes[])
throws InvalidFormatException, IOException, XmlException {
PackagePartName shapePN = PackagingURIHelper.createPartName("/drs/shapexml.xml");
OPCPackage pkg = null;
try {
pkg = OPCPackage.open(new ByteArrayInputStream(metroBytes));
PackagePart shapePart = pkg.getPart(shapePN);
CTGroupShape gs = CTGroupShape.Factory.parse(shapePart.getInputStream());
XSLFGroupShape xgs = new XSLFGroupShape(gs, null);
return xgs.getShapes().get(0);
} finally {
if (pkg != null) {
pkg.close();
}
}
}
}

View File

@ -90,20 +90,20 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
throw new IllegalStateException("SlideShow was not found");
}
protected List<XSLFShape> buildShapes(CTGroupShape spTree){
protected static List<XSLFShape> buildShapes(CTGroupShape spTree, XSLFSheet sheet){
List<XSLFShape> shapes = new ArrayList<XSLFShape>();
for(XmlObject ch : spTree.selectPath("*")){
if(ch instanceof CTShape){ // simple shape
XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, this);
XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, sheet);
shapes.add(shape);
} else if (ch instanceof CTGroupShape){
shapes.add(new XSLFGroupShape((CTGroupShape)ch, this));
shapes.add(new XSLFGroupShape((CTGroupShape)ch, sheet));
} else if (ch instanceof CTConnector){
shapes.add(new XSLFConnectorShape((CTConnector)ch, this));
shapes.add(new XSLFConnectorShape((CTConnector)ch, sheet));
} else if (ch instanceof CTPicture){
shapes.add(new XSLFPictureShape((CTPicture)ch, this));
shapes.add(new XSLFPictureShape((CTPicture)ch, sheet));
} else if (ch instanceof CTGraphicalObjectFrame){
XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, this);
XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, sheet);
shapes.add(shape);
}
}
@ -156,7 +156,7 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
_drawing = new XSLFDrawing(this, cgs);
}
if (_shapes == null) {
_shapes = buildShapes(cgs);
_shapes = buildShapes(cgs, this);
}
}

View File

@ -25,10 +25,15 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.usermodel.HSLFTextShape;
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.xslf.XSLFTestDataSamples;
@ -40,9 +45,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
/**
* @author Yegor Kozlov
*/
public class TestXSLFTextShape {
@Test
@ -913,4 +915,16 @@ public class TestXSLFTextShape {
ppt.close();
}
@Test
public void metroBlob() throws IOException {
File f = POIDataSamples.getSlideShowInstance().getFile("bug52297.ppt");
SlideShow<?,?> ppt = SlideShowFactory.create(f);
HSLFTextShape sh = (HSLFTextShape)ppt.getSlides().get(1).getShapes().get(3);
XSLFAutoShape xsh = (XSLFAutoShape)sh.getMetroShape();
String textExp = " ___ ___ ___ ________ __ _______ ___ ___________ __________ __ _____ ___ ___ ___ _______ ____ ______ ___________ _____________ ___ _______ ______ ____ ______ __ ___________ __________ ___ _________ _____ ________ __________ ___ _______ __________ ";
String textAct = xsh.getText();
ppt.close();
assertEquals(textExp, textAct);
}
}

View File

@ -0,0 +1,83 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hslf.model;
import java.lang.reflect.Method;
import org.apache.poi.ddf.AbstractEscherOptRecord;
import org.apache.poi.ddf.EscherComplexProperty;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherTertiaryOptRecord;
import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
* Experimental class for metro blobs, i.e. an alternative escher property
* containing an ooxml representation of the shape
*/
@Internal
public class HSLFMetroShape<T extends Shape<?,?>> {
private static final POILogger LOGGER = POILogFactory.getLogger(HSLFMetroShape.class);
private final HSLFShape shape;
public HSLFMetroShape(HSLFShape shape) {
this.shape = shape;
}
/**
* @return the bytes of the metro blob, which are bytes of an OPCPackage, i.e. a zip stream
*/
public byte[] getMetroBytes() {
AbstractEscherOptRecord opt = shape.getEscherChild(EscherTertiaryOptRecord.RECORD_ID);
if (opt != null) {
EscherComplexProperty ep = (EscherComplexProperty)opt.lookup(EscherProperties.GROUPSHAPE__METROBLOB);
if (ep != null) {
return ep.getComplexData();
}
}
return null;
}
/**
* @return the metro blob shape or null if either there's no metro blob or the ooxml classes
* aren't in the classpath
*/
@SuppressWarnings("unchecked")
public T getShape() {
byte metroBytes[] = getMetroBytes();
if (metroBytes == null) {
return null;
}
// org.apache.poi.xslf.usermodel.XSLFMetroShape
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
Class<?> ms = cl.loadClass("org.apache.poi.xslf.usermodel.XSLFMetroShape");
Method m = ms.getMethod("parseShape", byte[].class);
return (T)m.invoke(null, new Object[]{metroBytes});
} catch (Exception e) {
LOGGER.log(POILogger.ERROR, "can't process metro blob, check if all dependencies for POI OOXML are in the classpath.", e);
return null;
}
}
}

View File

@ -499,4 +499,9 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
// TODO Auto-generated method stub
}
@Override
public boolean getFollowMasterGraphics() {
return getFollowMasterObjects();
}
}

View File

@ -17,8 +17,12 @@
package org.apache.poi.hslf.usermodel;
import org.apache.poi.ddf.*;
import org.apache.poi.sl.usermodel.*;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.TextBox;
import org.apache.poi.sl.usermodel.VerticalAlignment;
/**
* Represents a TextFrame shape in PowerPoint.
@ -88,5 +92,4 @@ public class HSLFTextBox extends HSLFTextShape implements TextBox<HSLFShape,HSLF
setVerticalAlignment(VerticalAlignment.TOP);
setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002);
}
}

View File

@ -994,6 +994,15 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
return sb.toString();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (HSLFTextRun r : getTextRuns()) {
sb.append(r.getRawText());
}
return toExternalString(sb.toString(), getRunType());
}
/**
* Returns a new string with line breaks converted into internal ppt
* representation

View File

@ -34,6 +34,7 @@ import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.HSLFMetroShape;
import org.apache.poi.hslf.record.EscherTextboxWrapper;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.InteractiveInfoAtom;
@ -881,4 +882,14 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
}
/**
* Get alternative representation of text shape stored as metro blob escher property.
* The returned shape is the first shape in stored group shape of the metro blob
*
* @return null, if there's no alternative representation, otherwise the text shape
*/
public TextShape<?,?> getMetroShape() {
HSLFMetroShape<TextShape<?,?>> mbs = new HSLFMetroShape<TextShape<?,?>>(this);
return mbs.getShape();
}
}

Binary file not shown.