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:
parent
1a32b63fd3
commit
e8d108ff22
@ -61,7 +61,7 @@ implements XSLFShapeContainer, GroupShape<XSLFShape,XSLFTextParagraph> {
|
|||||||
|
|
||||||
protected XSLFGroupShape(CTGroupShape shape, XSLFSheet sheet){
|
protected XSLFGroupShape(CTGroupShape shape, XSLFSheet sheet){
|
||||||
super(shape,sheet);
|
super(shape,sheet);
|
||||||
_shapes = sheet.buildShapes(shape);
|
_shapes = XSLFSheet.buildShapes(shape, sheet);
|
||||||
_grpSpPr = shape.getGrpSpPr();
|
_grpSpPr = shape.getGrpSpPr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -90,20 +90,20 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
|
|||||||
throw new IllegalStateException("SlideShow was not found");
|
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>();
|
List<XSLFShape> shapes = new ArrayList<XSLFShape>();
|
||||||
for(XmlObject ch : spTree.selectPath("*")){
|
for(XmlObject ch : spTree.selectPath("*")){
|
||||||
if(ch instanceof CTShape){ // simple shape
|
if(ch instanceof CTShape){ // simple shape
|
||||||
XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, this);
|
XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, sheet);
|
||||||
shapes.add(shape);
|
shapes.add(shape);
|
||||||
} else if (ch instanceof CTGroupShape){
|
} else if (ch instanceof CTGroupShape){
|
||||||
shapes.add(new XSLFGroupShape((CTGroupShape)ch, this));
|
shapes.add(new XSLFGroupShape((CTGroupShape)ch, sheet));
|
||||||
} else if (ch instanceof CTConnector){
|
} else if (ch instanceof CTConnector){
|
||||||
shapes.add(new XSLFConnectorShape((CTConnector)ch, this));
|
shapes.add(new XSLFConnectorShape((CTConnector)ch, sheet));
|
||||||
} else if (ch instanceof CTPicture){
|
} else if (ch instanceof CTPicture){
|
||||||
shapes.add(new XSLFPictureShape((CTPicture)ch, this));
|
shapes.add(new XSLFPictureShape((CTPicture)ch, sheet));
|
||||||
} else if (ch instanceof CTGraphicalObjectFrame){
|
} else if (ch instanceof CTGraphicalObjectFrame){
|
||||||
XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, this);
|
XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, sheet);
|
||||||
shapes.add(shape);
|
shapes.add(shape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
|
|||||||
_drawing = new XSLFDrawing(this, cgs);
|
_drawing = new XSLFDrawing(this, cgs);
|
||||||
}
|
}
|
||||||
if (_shapes == null) {
|
if (_shapes == null) {
|
||||||
_shapes = buildShapes(cgs);
|
_shapes = buildShapes(cgs, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,10 +25,15 @@ import static org.junit.Assert.assertSame;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
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.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.TextParagraph.TextAlign;
|
||||||
import org.apache.poi.sl.usermodel.VerticalAlignment;
|
import org.apache.poi.sl.usermodel.VerticalAlignment;
|
||||||
import org.apache.poi.xslf.XSLFTestDataSamples;
|
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.CTPlaceholder;
|
||||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
|
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Yegor Kozlov
|
|
||||||
*/
|
|
||||||
public class TestXSLFTextShape {
|
public class TestXSLFTextShape {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -913,4 +915,16 @@ public class TestXSLFTextShape {
|
|||||||
|
|
||||||
ppt.close();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -499,4 +499,9 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
|
|||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getFollowMasterGraphics() {
|
||||||
|
return getFollowMasterObjects();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,12 @@
|
|||||||
|
|
||||||
package org.apache.poi.hslf.usermodel;
|
package org.apache.poi.hslf.usermodel;
|
||||||
|
|
||||||
import org.apache.poi.ddf.*;
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
import org.apache.poi.sl.usermodel.*;
|
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.
|
* Represents a TextFrame shape in PowerPoint.
|
||||||
@ -88,5 +92,4 @@ public class HSLFTextBox extends HSLFTextShape implements TextBox<HSLFShape,HSLF
|
|||||||
setVerticalAlignment(VerticalAlignment.TOP);
|
setVerticalAlignment(VerticalAlignment.TOP);
|
||||||
setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002);
|
setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -994,6 +994,15 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
return sb.toString();
|
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
|
* Returns a new string with line breaks converted into internal ppt
|
||||||
* representation
|
* representation
|
||||||
|
@ -34,6 +34,7 @@ import org.apache.poi.ddf.EscherProperties;
|
|||||||
import org.apache.poi.ddf.EscherSimpleProperty;
|
import org.apache.poi.ddf.EscherSimpleProperty;
|
||||||
import org.apache.poi.ddf.EscherTextboxRecord;
|
import org.apache.poi.ddf.EscherTextboxRecord;
|
||||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
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.EscherTextboxWrapper;
|
||||||
import org.apache.poi.hslf.record.InteractiveInfo;
|
import org.apache.poi.hslf.record.InteractiveInfo;
|
||||||
import org.apache.poi.hslf.record.InteractiveInfoAtom;
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
BIN
test-data/slideshow/bug52297.ppt
Normal file
BIN
test-data/slideshow/bug52297.ppt
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user