aboutsummaryrefslogtreecommitdiffstats
path: root/src/ooxml/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/ooxml/java')
-rwxr-xr-xsrc/ooxml/java/org/apache/poi/util/Units.java3
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/model/CharacterPropertyFetcher.java45
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/model/ParagraphPropertyFetcher.java52
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/model/PropertyFetcher.java48
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/model/TextBodyPropertyFetcher.java52
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java81
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java70
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java54
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java36
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java46
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java84
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java79
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java47
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPresetGeometry.java637
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRenderingHint.java42
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java106
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java75
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java121
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java589
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java46
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java46
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java22
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java28
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java16
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java452
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java136
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java275
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java202
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java101
29 files changed, 3273 insertions, 318 deletions
diff --git a/src/ooxml/java/org/apache/poi/util/Units.java b/src/ooxml/java/org/apache/poi/util/Units.java
index 77652004e1..3a400399c7 100755
--- a/src/ooxml/java/org/apache/poi/util/Units.java
+++ b/src/ooxml/java/org/apache/poi/util/Units.java
@@ -13,7 +13,8 @@
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.util;
+==================================================================== */
+package org.apache.poi.util;
/**
* @author Yegor Kozlov
diff --git a/src/ooxml/java/org/apache/poi/xslf/model/CharacterPropertyFetcher.java b/src/ooxml/java/org/apache/poi/xslf/model/CharacterPropertyFetcher.java
new file mode 100644
index 0000000000..09674abfe8
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/model/CharacterPropertyFetcher.java
@@ -0,0 +1,45 @@
+/*
+ * ====================================================================
+ * 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.model;
+
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+
+/**
+ *
+ * @author Yegor Kozlov
+ */
+public abstract class CharacterPropertyFetcher<T> extends ParagraphPropertyFetcher<T> {
+
+ public CharacterPropertyFetcher(int level) {
+ super(level);
+ }
+
+ public boolean fetch(CTTextParagraphProperties props) {
+ if (props.isSetDefRPr()) {
+ return fetch(props.getDefRPr());
+ }
+
+ return false;
+ }
+
+ public abstract boolean fetch(CTTextCharacterProperties props);
+
+} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/model/ParagraphPropertyFetcher.java b/src/ooxml/java/org/apache/poi/xslf/model/ParagraphPropertyFetcher.java
new file mode 100644
index 0000000000..65c19e6d74
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/model/ParagraphPropertyFetcher.java
@@ -0,0 +1,52 @@
+/*
+ * ====================================================================
+ * 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.model;
+
+import org.apache.poi.xslf.usermodel.XSLFSimpleShape;
+import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+
+/**
+ *
+ * @author Yegor Kozlov
+ */
+public abstract class ParagraphPropertyFetcher<T> extends PropertyFetcher<T> {
+ int _level;
+
+ public ParagraphPropertyFetcher(int level) {
+ _level = level;
+ }
+
+ public boolean fetch(XSLFSimpleShape shape) {
+
+ XmlObject[] o = shape.getXmlObject().selectPath(
+ "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
+ "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
+ ".//p:txBody/a:lstStyle/a:lvl" + (_level + 1) + "pPr"
+ );
+ if (o.length == 1) {
+ CTTextParagraphProperties props = (CTTextParagraphProperties) o[0];
+ return fetch(props);
+ }
+ return false;
+ }
+
+ public abstract boolean fetch(CTTextParagraphProperties props);
+} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/model/PropertyFetcher.java b/src/ooxml/java/org/apache/poi/xslf/model/PropertyFetcher.java
new file mode 100644
index 0000000000..d446ccedde
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/model/PropertyFetcher.java
@@ -0,0 +1,48 @@
+/*
+ * ====================================================================
+ * 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.model;
+
+import org.apache.poi.xslf.usermodel.XSLFSimpleShape;
+import org.apache.poi.util.Internal;
+
+/**
+ * Used internally to navigate the PresentationML text style hierarchy and fetch properties
+ *
+ * @author Yegor Kozlov
+*/
+@Internal
+public abstract class PropertyFetcher<T> {
+ private T _value;
+
+ /**
+ *
+ * @param shape the shape being examined
+ * @return true if the desired property was fetched
+ */
+ public abstract boolean fetch(XSLFSimpleShape shape) ;
+
+ public T getValue(){
+ return _value;
+ }
+
+ public void setValue(T val){
+ _value = val;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/model/TextBodyPropertyFetcher.java b/src/ooxml/java/org/apache/poi/xslf/model/TextBodyPropertyFetcher.java
new file mode 100644
index 0000000000..b66a1e5f7a
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/model/TextBodyPropertyFetcher.java
@@ -0,0 +1,52 @@
+/*
+ * ====================================================================
+ * 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.model;
+
+import org.apache.poi.xslf.usermodel.XSLFSimpleShape;
+import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: yegor
+ * Date: Oct 21, 2011
+ * Time: 1:18:52 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public abstract class TextBodyPropertyFetcher<T> extends PropertyFetcher<T> {
+
+ public boolean fetch(XSLFSimpleShape shape) {
+
+ XmlObject[] o = shape.getXmlObject().selectPath(
+ "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
+ "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
+ ".//p:txBody/a:bodyPr"
+ );
+ if (o.length == 1) {
+ CTTextBodyProperties props = (CTTextBodyProperties) o[0];
+ return fetch(props);
+ }
+
+ return false;
+ }
+
+ public abstract boolean fetch(CTTextBodyProperties props);
+
+} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java
index feb77a4041..e37259459f 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java
@@ -21,6 +21,8 @@ package org.apache.poi.xslf.usermodel;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Units;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuideList;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
@@ -39,8 +41,12 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
/**
* Represents a preset geometric shape.
@@ -49,6 +55,7 @@ import java.util.List;
*/
@Beta
public class XSLFAutoShape extends XSLFTextShape {
+ private static final Pattern adjPtrn = Pattern.compile("val\\s+(\\d+)");
/*package*/ XSLFAutoShape(CTShape shape, XSLFSheet sheet) {
super(shape, sheet);
@@ -83,44 +90,6 @@ public class XSLFAutoShape extends XSLFTextShape {
return ct;
}
- /**
- * Specifies a solid color fill. The shape is filled entirely with the specified color.
- *
- * @param color the solid color fill.
- * The value of <code>null</code> unsets the solidFIll attribute from the underlying xml
- */
- public void setFillColor(Color color) {
- CTShapeProperties spPr = getSpPr();
- if (color == null) {
- if(spPr.isSetSolidFill()) spPr.unsetSolidFill();
- }
- else {
- CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill();
-
- CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
- rgb.setVal(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()});
-
- fill.setSrgbClr(rgb);
- }
- }
-
- /**
- *
- * @return solid fill color of null if not set
- */
- public Color getFillColor(){
- CTShapeProperties spPr = getSpPr();
- if(!spPr.isSetSolidFill() ) return null;
-
- CTSolidColorFillProperties fill = spPr.getSolidFill();
- if(!fill.isSetSrgbClr()) {
- // TODO for now return null for all colors except explicit RGB
- return null;
- }
- byte[] val = fill.getSrgbClr().getVal();
- return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
- }
-
protected CTTextBody getTextBody(boolean create){
CTShape shape = (CTShape) getXmlObject();
CTTextBody txBody = shape.getTxBody();
@@ -132,4 +101,38 @@ public class XSLFAutoShape extends XSLFTextShape {
return txBody;
}
-} \ No newline at end of file
+ int getAdjustValue(String name, int defaultValue){
+ /*
+ CTShape shape = (CTShape) getXmlObject();
+ CTGeomGuideList av = shape.getSpPr().getPrstGeom().getAvLst();
+ if(av != null){
+ for(CTGeomGuide gd : av.getGdList()){
+ if(gd.getName().equals(name)) {
+ String fmla = gd.getFmla();
+ Matcher m = adjPtrn.matcher(fmla);
+ if(m.matches()){
+ int val = Integer.parseInt(m.group(1));
+ return 21600*val/100000;
+ }
+ }
+ }
+ }
+ */
+ return defaultValue;
+ }
+
+ @Override
+ protected java.awt.Shape getOutline(){
+ java.awt.Shape outline = XSLFPresetGeometry.getOutline(this);
+ Rectangle2D anchor = getAnchor();
+
+ AffineTransform at = new AffineTransform();
+ at.translate(anchor.getX(), anchor.getY());
+ at.scale(
+ 1.0f/21600*anchor.getWidth(),
+ 1.0f/21600*anchor.getHeight()
+ );
+ return outline == null ? anchor : at.createTransformedShape(outline);
+ }
+
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java
new file mode 100644
index 0000000000..646c5a40af
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java
@@ -0,0 +1,70 @@
+/* ====================================================================
+ 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 org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+
+/**
+ * Background shape
+ *
+ * @author Yegor Kozlov
+ */
+public class XSLFBackground extends XSLFSimpleShape {
+
+ /* package */XSLFBackground(CTBackground shape, XSLFSheet sheet) {
+ super(shape, sheet);
+ }
+
+ public void draw(Graphics2D graphics) {
+ Dimension pg = getSheet().getSlideShow().getPageSize();
+ Rectangle anchor = new Rectangle(0, 0, pg.width, pg.height);
+ CTBackgroundProperties pr = ((CTBackground) getXmlObject()).getBgPr();
+ if (pr == null) return;
+
+ XSLFTheme theme = getSheet().getTheme();
+ if (pr.isSetSolidFill()) {
+ Color color = theme.getSolidFillColor(pr.getSolidFill());
+ graphics.setPaint(color);
+ graphics.fill(anchor);
+ }
+ if (pr.isSetBlipFill()) {
+
+ String blipId = pr.getBlipFill().getBlip().getEmbed();
+ PackagePart p = getSheet().getPackagePart();
+ PackageRelationship rel = p.getRelationship(blipId);
+ if (rel != null) {
+ try {
+ BufferedImage img = ImageIO.read(p.getRelatedPart(rel).getInputStream());
+ graphics.drawImage(img, (int) anchor.getX(), (int) anchor.getY(),
+ (int) anchor.getWidth(), (int) anchor.getHeight(), null);
+ }
+ catch (Exception e) {
+ return;
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java
new file mode 100644
index 0000000000..614262a9e5
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java
@@ -0,0 +1,54 @@
+/*
+ * ====================================================================
+ * 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.awt.Color;
+
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeStyleSheet;
+
+public class XSLFColor {
+ private final CTColor _ctColor;
+
+ XSLFColor(CTColor ctColor){
+ _ctColor = ctColor;
+ }
+
+ @Internal
+ public CTColor getXmlObject() {
+ return _ctColor;
+ }
+
+ public Color getColor(){
+ return getColor(0xFF);
+ }
+
+ public Color getColor(int alpha){
+ Color color = Color.black;
+ if(_ctColor.isSetSrgbClr()){
+ byte[] val = _ctColor.getSrgbClr().getVal();
+ color = new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2], alpha);
+ } else if (_ctColor.isSetSysClr()){
+ byte[] val = _ctColor.getSysClr().getLastClr();
+ color = new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2], alpha);
+ }
+ return color;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java
index d93c1351f6..6eb49b4b9c 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java
@@ -32,6 +32,10 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength;
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnectorNonVisual;
+import java.awt.*;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+
/**
*
* Specifies a connection shape.
@@ -192,4 +196,36 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
return len == null ? null : LineEndLength.values()[len.intValue() - 1];
}
+ @Override
+ public void draw(Graphics2D graphics){
+ java.awt.Shape outline = getOutline();
+
+ // shadow
+ XSLFShadow shadow = getShadow();
+ if(shadow != null) shadow.draw(graphics);
+
+ //border
+ Color lineColor = getLineColor();
+ if (lineColor != null){
+ graphics.setColor(lineColor);
+ applyStroke(graphics);
+ graphics.draw(outline);
+ }
+ }
+
+ @Override
+ protected java.awt.Shape getOutline(){
+ Rectangle2D anchor = getAnchor();
+ double x1 = anchor.getX(),
+ y1 = anchor.getY(),
+ x2 = anchor.getX() + anchor.getWidth(),
+ y2 = anchor.getY() + anchor.getHeight();
+
+ GeneralPath line = new GeneralPath();
+ line.moveTo((float)x1, (float)y1);
+ line.lineTo((float)x2, (float)y2);
+
+ return line;
+ }
+
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
index a0b3ab0558..594aa277b3 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java
@@ -111,34 +111,45 @@ public class XSLFFreeformShape extends XSLFAutoShape {
return numPoints;
}
+ /**
+ * Gets the shape path.
+ * <p>
+ * The path is translated in the shape's coordinate system, i.e.
+ * freeform.getPath().getBounds2D() equals to freeform.getAnchor()
+ * (small discrepancies are possible due to rounding errors)
+ * </p>
+ *
+ * @return the path
+ */
public GeneralPath getPath() {
GeneralPath path = new GeneralPath();
Rectangle2D bounds = getAnchor();
- int x0 = Units.toEMU(bounds.getX());
- int y0 = Units.toEMU(bounds.getY());
+
CTCustomGeometry2D geom = getSpPr().getCustGeom();
for(CTPath2D spPath : geom.getPathLst().getPathList()){
+ double scaleW = bounds.getWidth() / Units.toPoints(spPath.getW());
+ double scaleH = bounds.getHeight() / Units.toPoints(spPath.getH());
for(XmlObject ch : spPath.selectPath("*")){
if(ch instanceof CTPath2DMoveTo){
CTAdjPoint2D pt = ((CTPath2DMoveTo)ch).getPt();
- path.moveTo((float)Units.toPoints((Long)pt.getX() + x0),
- (float)Units.toPoints((Long)pt.getY() + y0));
+ path.moveTo((float)Units.toPoints((Long)pt.getX())*scaleW,
+ (float)Units.toPoints((Long)pt.getY())*scaleH);
} else if (ch instanceof CTPath2DLineTo){
CTAdjPoint2D pt = ((CTPath2DLineTo)ch).getPt();
- path.lineTo((float)Units.toPoints((Long)pt.getX() + x0),
- (float)Units.toPoints((Long)pt.getY() + y0));
+ path.lineTo((float)Units.toPoints((Long)pt.getX()),
+ (float)Units.toPoints((Long)pt.getY()));
} else if (ch instanceof CTPath2DCubicBezierTo){
CTPath2DCubicBezierTo bez = ((CTPath2DCubicBezierTo)ch);
CTAdjPoint2D pt1 = bez.getPtArray(0);
CTAdjPoint2D pt2 = bez.getPtArray(1);
CTAdjPoint2D pt3 = bez.getPtArray(2);
path.curveTo(
- (float)Units.toPoints((Long) pt1.getX() + x0),
- (float)Units.toPoints((Long) pt1.getY() + y0),
- (float)Units.toPoints((Long) pt2.getX() + x0),
- (float)Units.toPoints((Long) pt2.getY() + y0),
- (float)Units.toPoints((Long) pt3.getX() + x0),
- (float)Units.toPoints((Long) pt3.getY() + y0)
+ (float)Units.toPoints((Long) pt1.getX())*scaleW,
+ (float)Units.toPoints((Long) pt1.getY())*scaleH,
+ (float)Units.toPoints((Long) pt2.getX())*scaleW,
+ (float)Units.toPoints((Long) pt2.getY())*scaleH,
+ (float)Units.toPoints((Long) pt3.getX())*scaleW,
+ (float)Units.toPoints((Long) pt3.getY())*scaleH
);
} else if (ch instanceof CTPath2DClose){
@@ -147,7 +158,11 @@ public class XSLFFreeformShape extends XSLFAutoShape {
}
}
- return path;
+ // the created path starts at (x=0, y=0).
+ // The returned path should fit in the bounding rectangle
+ AffineTransform at = new AffineTransform();
+ at.translate(bounds.getX(), bounds.getY());
+ return new GeneralPath(at.createTransformedShape(path));
}
/**
* @param shapeId 1-based shapeId
@@ -175,4 +190,9 @@ public class XSLFFreeformShape extends XSLFAutoShape {
return ct;
}
+ @Override
+ protected java.awt.Shape getOutline(){
+ return getPath();
+ }
+
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
index 7e0990331f..9077e256f1 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java
@@ -23,8 +23,16 @@ import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeGroup;
import org.apache.poi.util.Beta;
+import org.apache.poi.util.Units;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
/**
@@ -61,11 +69,31 @@ public class XSLFGraphicFrame extends XSLFShape {
}
public Rectangle2D getAnchor(){
- throw new RuntimeException("NotImplemented");
+ CTTransform2D xfrm = _shape.getXfrm();
+ CTPoint2D off = xfrm.getOff();
+ long x = off.getX();
+ long y = off.getY();
+ CTPositiveSize2D ext = xfrm.getExt();
+ long cx = ext.getCx();
+ long cy = ext.getCy();
+ return new Rectangle2D.Double(
+ Units.toPoints(x), Units.toPoints(y),
+ Units.toPoints(cx), Units.toPoints(cy));
}
public void setAnchor(Rectangle2D anchor){
- throw new RuntimeException("NotImplemented");
+ CTTransform2D xfrm = _shape.getXfrm();
+ CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
+ long x = Units.toEMU(anchor.getX());
+ long y = Units.toEMU(anchor.getY());
+ off.setX(x);
+ off.setY(y);
+ CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm
+ .addNewExt();
+ long cx = Units.toEMU(anchor.getWidth());
+ long cy = Units.toEMU(anchor.getHeight());
+ ext.setCx(cx);
+ ext.setCy(cy);
}
@@ -78,4 +106,56 @@ public class XSLFGraphicFrame extends XSLFShape {
}
}
+ /**
+ * Rotate this shape.
+ * <p>
+ * Positive angles are clockwise (i.e., towards the positive y axis);
+ * negative angles are counter-clockwise (i.e., towards the negative y axis).
+ * </p>
+ *
+ * @param theta the rotation angle in degrees.
+ */
+ public void setRotation(double theta){
+ throw new IllegalArgumentException("Operation not supported");
+ }
+
+ /**
+ * Rotation angle in degrees
+ * <p>
+ * Positive angles are clockwise (i.e., towards the positive y axis);
+ * negative angles are counter-clockwise (i.e., towards the negative y axis).
+ * </p>
+ *
+ * @return rotation angle in degrees
+ */
+ public double getRotation(){
+ return 0;
+ }
+
+ public void setFlipHorizontal(boolean flip){
+ throw new IllegalArgumentException("Operation not supported");
+ }
+
+ public void setFlipVertical(boolean flip){
+ throw new IllegalArgumentException("Operation not supported");
+ }
+
+ /**
+ * Whether the shape is horizontally flipped
+ *
+ * @return whether the shape is horizontally flipped
+ */
+ public boolean getFlipHorizontal(){
+ return false;
+ }
+
+ public boolean getFlipVertical(){
+ return false;
+ }
+
+ public void draw(Graphics2D graphics){
+
+ }
+
+
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
index 804420854d..3d5b2f6a5e 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java
@@ -33,11 +33,14 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupTransform2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.List;
import java.util.regex.Pattern;
@@ -217,4 +220,80 @@ public class XSLFGroupShape extends XSLFShape {
return sh;
}
+
+ public void setFlipHorizontal(boolean flip){
+ _spPr.getXfrm().setFlipH(flip);
+ }
+
+ public void setFlipVertical(boolean flip){
+ _spPr.getXfrm().setFlipV(flip);
+ }
+ /**
+ * Whether the shape is horizontally flipped
+ *
+ * @return whether the shape is horizontally flipped
+ */
+ public boolean getFlipHorizontal(){
+ return _spPr.getXfrm().getFlipH();
+ }
+
+ public boolean getFlipVertical(){
+ return _spPr.getXfrm().getFlipV();
+ }
+
+ /**
+ * Rotate this shape.
+ * <p>
+ * Positive angles are clockwise (i.e., towards the positive y axis);
+ * negative angles are counter-clockwise (i.e., towards the negative y axis).
+ * </p>
+ *
+ * @param theta the rotation angle in degrees.
+ */
+ public void setRotation(double theta){
+ _spPr.getXfrm().setRot((int)(theta*60000));
+ }
+
+ /**
+ * Rotation angle in degrees
+ * <p>
+ * Positive angles are clockwise (i.e., towards the positive y axis);
+ * negative angles are counter-clockwise (i.e., towards the negative y axis).
+ * </p>
+ *
+ * @return rotation angle in degrees
+ */
+ public double getRotation(){
+ return (double)_spPr.getXfrm().getRot()/60000;
+ }
+
+ public void draw(Graphics2D graphics){
+
+ // the coordinate system of this group of shape
+ Rectangle2D interior = getInteriorAnchor();
+ // anchor of this group relative to the parent shape
+ Rectangle2D exterior = getAnchor();
+
+ graphics.translate(exterior.getX(), exterior.getY());
+ double scaleX = exterior.getWidth() / interior.getWidth();
+ double scaleY = exterior.getHeight() / interior.getHeight();
+ graphics.scale(scaleX, scaleY);
+ graphics.translate(-interior.getX(), -interior.getY());
+
+ for (XSLFShape shape : getShapes()) {
+ // remember the initial transform and restore it after we are done with the drawing
+ AffineTransform at0 = graphics.getTransform();
+ graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true);
+
+ // apply rotation and flipping
+ shape.applyTransform(graphics);
+
+ shape.draw(graphics);
+
+ // restore the coordinate system
+ graphics.setTransform(at0);
+ graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true);
+ }
+ }
+
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
index c2ce2bd969..4e17d62c05 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
@@ -22,16 +22,24 @@ package org.apache.poi.xslf.usermodel;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.util.Beta;
+import org.apache.poi.util.POILogger;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPictureNonVisual;
import javax.imageio.ImageIO;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
@@ -104,4 +112,43 @@ public class XSLFPictureShape extends XSLFSimpleShape {
}
return _data;
}
+
+ @Override
+ public void draw(Graphics2D graphics){
+ java.awt.Shape outline = getOutline();
+
+ //fill
+ Color fillColor = getFillColor();
+ if (fillColor != null) {
+ graphics.setColor(fillColor);
+ applyFill(graphics);
+ graphics.fill(outline);
+ }
+
+ // text
+
+ XSLFPictureData data = getPictureData();
+ if(data == null) return;
+
+ BufferedImage img;
+ try {
+ img = ImageIO.read(new ByteArrayInputStream(data.getData()));
+ }
+ catch (Exception e){
+ return;
+ }
+ Rectangle2D anchor = getAnchor();
+ graphics.drawImage(img, (int)anchor.getX(), (int)anchor.getY(),
+ (int)anchor.getWidth(), (int)anchor.getHeight(), null);
+
+
+ //border overlays the image
+ Color lineColor = getLineColor();
+ if (lineColor != null){
+ graphics.setColor(lineColor);
+ applyStroke(graphics);
+ graphics.draw(outline);
+ }
+ }
+
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPresetGeometry.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPresetGeometry.java
new file mode 100644
index 0000000000..dcd4910b8b
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPresetGeometry.java
@@ -0,0 +1,637 @@
+/*
+ * ====================================================================
+ * 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.awt.*;
+import java.awt.geom.*;
+
+/**
+ * TODO: re-write and initialize from presetShapeDefinitions.xml
+ *
+ * @author Yegor Kozlov
+ */
+public class XSLFPresetGeometry {
+ public static final int LINE = 1;
+ public static final int LINE_INV = 2;
+ public static final int TRIANGLE = 3;
+ public static final int RT_TRIANGLE = 4;
+ public static final int RECT = 5;
+ public static final int DIAMOND = 6;
+ public static final int PARALLELOGRAM = 7;
+ public static final int TRAPEZOID = 8;
+ public static final int NON_ISOSCELES_TRAPEZOID = 9;
+ public static final int PENTAGON = 10;
+ public static final int HEXAGON = 11;
+ public static final int HEPTAGON = 12;
+ public static final int OCTAGON = 13;
+ public static final int DECAGON = 14;
+ public static final int DODECAGON = 15;
+ public static final int STAR_4 = 16;
+ public static final int STAR_5 = 17;
+ public static final int STAR_6 = 18;
+ public static final int STAR_7 = 19;
+ public static final int STAR_8 = 20;
+ public static final int STAR_10 = 21;
+ public static final int STAR_12 = 22;
+ public static final int STAR_16 = 23;
+ public static final int STAR_24 = 24;
+ public static final int STAR_32 = 25;
+ public static final int ROUND_RECT = 26;
+ public static final int ROUND_1_RECT = 27;
+ public static final int ROUND_2_SAME_RECT = 28;
+ public static final int ROUND_2_DIAG_RECT = 29;
+ public static final int SNIP_ROUND_RECT = 30;
+ public static final int SNIP_1_RECT = 31;
+ public static final int SNIP_2_SAME_RECT = 32;
+ public static final int SNIP_2_DIAG_RECT = 33;
+ public static final int PLAQUE = 34;
+ public static final int ELLIPSE = 35;
+ public static final int TEARDROP = 36;
+ public static final int HOME_PLATE = 37;
+ public static final int CHEVRON = 38;
+ public static final int PIE_WEDGE = 39;
+ public static final int PIE = 40;
+ public static final int BLOCK_ARC = 41;
+ public static final int DONUT = 42;
+ public static final int NO_SMOKING = 43;
+ public static final int RIGHT_ARROW = 44;
+ public static final int LEFT_ARROW = 45;
+ public static final int UP_ARROW = 46;
+ public static final int DOWN_ARROW = 47;
+ public static final int STRIPED_RIGHT_ARROW = 48;
+ public static final int NOTCHED_RIGHT_ARROW = 49;
+ public static final int BENT_UP_ARROW = 50;
+ public static final int LEFT_RIGHT_ARROW = 51;
+ public static final int UP_DOWN_ARROW = 52;
+ public static final int LEFT_UP_ARROW = 53;
+ public static final int LEFT_RIGHT_UP_ARROW = 54;
+ public static final int QUAD_ARROW = 55;
+ public static final int LEFT_ARROW_CALLOUT = 56;
+ public static final int RIGHT_ARROW_CALLOUT = 57;
+ public static final int UP_ARROW_CALLOUT = 58;
+ public static final int DOWN_ARROW_CALLOUT = 59;
+ public static final int LEFT_RIGHT_ARROW_CALLOUT = 60;
+ public static final int UP_DOWN_ARROW_CALLOUT = 61;
+ public static final int QUAD_ARROW_CALLOUT = 62;
+ public static final int BENT_ARROW = 63;
+ public static final int UTURN_ARROW = 64;
+ public static final int CIRCULAR_ARROW = 65;
+ public static final int LEFT_CIRCULAR_ARROW = 66;
+ public static final int LEFT_RIGHT_CIRCULAR_ARROW = 67;
+ public static final int CURVED_RIGHT_ARROW = 68;
+ public static final int CURVED_LEFT_ARROW = 69;
+ public static final int CURVED_UP_ARROW = 70;
+ public static final int CURVED_DOWN_ARROW = 71;
+ public static final int SWOOSH_ARROW = 72;
+ public static final int CUBE = 73;
+ public static final int CAN = 74;
+ public static final int LIGHTNING_BOLT = 75;
+ public static final int HEART = 76;
+ public static final int SUN = 77;
+ public static final int MOON = 78;
+ public static final int SMILEY_FACE = 79;
+ public static final int IRREGULAR_SEAL_1 = 80;
+ public static final int IRREGULAR_SEAL_2 = 81;
+ public static final int FOLDED_CORNER = 82;
+ public static final int BEVEL = 83;
+ public static final int FRAME = 84;
+ public static final int HALF_FRAME = 85;
+ public static final int CORNER = 86;
+ public static final int DIAG_STRIPE = 87;
+ public static final int CHORD = 88;
+ public static final int ARC = 89;
+ public static final int LEFT_BRACKET = 90;
+ public static final int RIGHT_BRACKET = 91;
+ public static final int LEFT_BRACE = 92;
+ public static final int RIGHT_BRACE = 93;
+ public static final int BRACKET_PAIR = 94;
+ public static final int BRACE_PAIR = 95;
+ public static final int STRAIGHT_CONNECTOR_1 = 96;
+ public static final int BENT_CONNECTOR_2 = 97;
+ public static final int BENT_CONNECTOR_3 = 98;
+ public static final int BENT_CONNECTOR_4 = 99;
+ public static final int BENT_CONNECTOR_5 = 100;
+ public static final int CURVED_CONNECTOR_2 = 101;
+ public static final int CURVED_CONNECTOR_3 = 102;
+ public static final int CURVED_CONNECTOR_4 = 103;
+ public static final int CURVED_CONNECTOR_5 = 104;
+ public static final int CALLOUT_1 = 105;
+ public static final int CALLOUT_2 = 106;
+ public static final int CALLOUT_3 = 107;
+ public static final int ACCENT_CALLOUT_1 = 108;
+ public static final int ACCENT_CALLOUT_2 = 109;
+ public static final int ACCENT_CALLOUT_3 = 110;
+ public static final int BORDER_CALLOUT_1 = 111;
+ public static final int BORDER_CALLOUT_2 = 112;
+ public static final int BORDER_CALLOUT_3 = 113;
+ public static final int ACCENT_BORDER_CALLOUT_1 = 114;
+ public static final int ACCENT_BORDER_CALLOUT_2 = 115;
+ public static final int ACCENT_BORDER_CALLOUT_3 = 116;
+ public static final int WEDGE_RECT_CALLOUT = 117;
+ public static final int WEDGE_ROUND_RECT_CALLOUT = 118;
+ public static final int WEDGE_ELLIPSE_CALLOUT = 119;
+ public static final int CLOUD_CALLOUT = 120;
+ public static final int CLOUD = 121;
+ public static final int RIBBON = 122;
+ public static final int RIBBON_2 = 123;
+ public static final int ELLIPSE_RIBBON = 124;
+ public static final int ELLIPSE_RIBBON_2 = 125;
+ public static final int LEFT_RIGHT_RIBBON = 126;
+ public static final int VERTICAL_SCROLL = 127;
+ public static final int HORIZONTAL_SCROLL = 128;
+ public static final int WAVE = 129;
+ public static final int DOUBLE_WAVE = 130;
+ public static final int PLUS = 131;
+ public static final int FLOW_CHART_PROCESS = 132;
+ public static final int FLOW_CHART_DECISION = 133;
+ public static final int FLOW_CHART_INPUT_OUTPUT = 134;
+ public static final int FLOW_CHART_PREDEFINED_PROCESS = 135;
+ public static final int FLOW_CHART_INTERNAL_STORAGE = 136;
+ public static final int FLOW_CHART_DOCUMENT = 137;
+ public static final int FLOW_CHART_MULTIDOCUMENT = 138;
+ public static final int FLOW_CHART_TERMINATOR = 139;
+ public static final int FLOW_CHART_PREPARATION = 140;
+ public static final int FLOW_CHART_MANUAL_INPUT = 141;
+ public static final int FLOW_CHART_MANUAL_OPERATION = 142;
+ public static final int FLOW_CHART_CONNECTOR = 143;
+ public static final int FLOW_CHART_PUNCHED_CARD = 144;
+ public static final int FLOW_CHART_PUNCHED_TAPE = 145;
+ public static final int FLOW_CHART_SUMMING_JUNCTION = 146;
+ public static final int FLOW_CHART_OR = 147;
+ public static final int FLOW_CHART_COLLATE = 148;
+ public static final int FLOW_CHART_SORT = 149;
+ public static final int FLOW_CHART_EXTRACT = 150;
+ public static final int FLOW_CHART_MERGE = 151;
+ public static final int FLOW_CHART_OFFLINE_STORAGE = 152;
+ public static final int FLOW_CHART_ONLINE_STORAGE = 153;
+ public static final int FLOW_CHART_MAGNETIC_TAPE = 154;
+ public static final int FLOW_CHART_MAGNETIC_DISK = 155;
+ public static final int FLOW_CHART_MAGNETIC_DRUM = 156;
+ public static final int FLOW_CHART_DISPLAY = 157;
+ public static final int FLOW_CHART_DELAY = 158;
+ public static final int FLOW_CHART_ALTERNATE_PROCESS = 159;
+ public static final int FLOW_CHART_OFFPAGE_CONNECTOR = 160;
+ public static final int ACTION_BUTTON_BLANK = 161;
+ public static final int ACTION_BUTTON_HOME = 162;
+ public static final int ACTION_BUTTON_HELP = 163;
+ public static final int ACTION_BUTTON_INFORMATION = 164;
+ public static final int ACTION_BUTTON_FORWARD_NEXT = 165;
+ public static final int ACTION_BUTTON_BACK_PREVIOUS = 166;
+ public static final int ACTION_BUTTON_END = 167;
+ public static final int ACTION_BUTTON_BEGINNING = 168;
+ public static final int ACTION_BUTTON_RETURN = 169;
+ public static final int ACTION_BUTTON_DOCUMENT = 170;
+ public static final int ACTION_BUTTON_SOUND = 171;
+ public static final int ACTION_BUTTON_MOVIE = 172;
+ public static final int GEAR_6 = 173;
+ public static final int GEAR_9 = 174;
+ public static final int FUNNEL = 175;
+ public static final int MATH_PLUS = 176;
+ public static final int MATH_MINUS = 177;
+ public static final int MATH_MULTIPLY = 178;
+ public static final int MATH_DIVIDE = 179;
+ public static final int MATH_EQUAL = 180;
+ public static final int MATH_NOT_EQUAL = 181;
+ public static final int CORNER_TABS = 182;
+ public static final int SQUARE_TABS = 183;
+ public static final int PLAQUE_TABS = 184;
+ public static final int CHART_X = 185;
+ public static final int CHART_STAR = 186;
+ public static final int CHART_PLUS = 187;
+
+ private static interface ShapeOutline {
+ java.awt.Shape getOutline(XSLFAutoShape shape);
+ }
+
+
+ static ShapeOutline[] shapes;
+ static {
+ shapes = new ShapeOutline[255];
+
+ shapes[RECT] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ Rectangle2D path = new Rectangle2D.Float(0, 0, 21600, 21600);
+ return path;
+ }
+ };
+
+ shapes[ROUND_RECT] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ int adjval = shape.getAdjustValue("adj1", 5400);
+ RoundRectangle2D path = new RoundRectangle2D.Float(0, 0, 21600, 21600, adjval, adjval);
+ return path;
+ }
+ };
+
+ shapes[ELLIPSE] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ Ellipse2D path = new Ellipse2D.Float(0, 0, 21600, 21600);
+ return path;
+ }
+ };
+
+ shapes[DIAMOND] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ GeneralPath path = new GeneralPath();
+ path.moveTo(10800, 0);
+ path.lineTo(21600, 10800);
+ path.lineTo(10800, 21600);
+ path.lineTo(0, 10800);
+ path.closePath();
+ return path;
+ }
+ };
+
+ //m@0,l,21600r21600
+ shapes[TRIANGLE] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ int adjval = shape.getAdjustValue("adj1", 5400);
+ GeneralPath path = new GeneralPath();
+ path.moveTo(adjval, 0);
+ path.lineTo(0, 21600);
+ path.lineTo(21600, 21600);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[RT_TRIANGLE] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ GeneralPath path = new GeneralPath();
+ path.moveTo(0, 0);
+ path.lineTo(21600, 21600);
+ path.lineTo(0, 21600);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[PARALLELOGRAM] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ int adjval = shape.getAdjustValue("adj1", 5400);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(adjval, 0);
+ path.lineTo(21600, 0);
+ path.lineTo(21600 - adjval, 21600);
+ path.lineTo(0, 21600);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[TRAPEZOID] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ int adjval = shape.getAdjustValue("adj1", 5400);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(0, 0);
+ path.lineTo(adjval, 21600);
+ path.lineTo(21600 - adjval, 21600);
+ path.lineTo(21600, 0);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[HEXAGON] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ int adjval = shape.getAdjustValue("adj1", 5400);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(adjval, 0);
+ path.lineTo(21600 - adjval, 0);
+ path.lineTo(21600, 10800);
+ path.lineTo(21600 - adjval, 21600);
+ path.lineTo(adjval, 21600);
+ path.lineTo(0, 10800);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[OCTAGON] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ int adjval = shape.getAdjustValue("adj1", 6324);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(adjval, 0);
+ path.lineTo(21600 - adjval, 0);
+ path.lineTo(21600, adjval);
+ path.lineTo(21600, 21600-adjval);
+ path.lineTo(21600-adjval, 21600);
+ path.lineTo(adjval, 21600);
+ path.lineTo(0, 21600-adjval);
+ path.lineTo(0, adjval);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[PLUS] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ int adjval = shape.getAdjustValue("adj1", 5400);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(adjval, 0);
+ path.lineTo(21600 - adjval, 0);
+ path.lineTo(21600 - adjval, adjval);
+ path.lineTo(21600, adjval);
+ path.lineTo(21600, 21600-adjval);
+ path.lineTo(21600-adjval, 21600-adjval);
+ path.lineTo(21600-adjval, 21600);
+ path.lineTo(adjval, 21600);
+ path.lineTo(adjval, 21600-adjval);
+ path.lineTo(0, 21600-adjval);
+ path.lineTo(0, adjval);
+ path.lineTo(adjval, adjval);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[PENTAGON] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(10800, 0);
+ path.lineTo(21600, 8259);
+ path.lineTo(21600 - 4200, 21600);
+ path.lineTo(4200, 21600);
+ path.lineTo(0, 8259);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[HOME_PLATE] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+
+ GeneralPath path = new GeneralPath();
+ int adjval = shape.getAdjustValue("adj1", 16200);
+ path.moveTo(0, 0);
+ path.lineTo(adjval, 0 );
+ path.lineTo(21600, 10800);
+ path.lineTo(adjval, 21600);
+ path.lineTo(0, 21600);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[CHEVRON] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ GeneralPath path = new GeneralPath();
+ int adjval = shape.getAdjustValue("adj1", 16200);
+ path.moveTo(0, 0);
+ path.lineTo(adjval, 0 );
+ path.lineTo(21600, 10800);
+ path.lineTo(adjval, 21600);
+ path.lineTo(0, 21600);
+ path.lineTo(21600 - adjval, 10800);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[CAN] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ int adjval = shape.getAdjustValue("adj1", 5400);
+ GeneralPath path = new GeneralPath();
+ path.moveTo(0, 0);
+ path.lineTo(21600, 0);
+ path.lineTo(21600, 21600);
+ path.lineTo(0, 21600);
+
+ //path.lineTo(21600, adjval);
+
+ path.closePath();
+ path.moveTo(10800, 0);
+ //path.append(new Arc2D.Float(10800, 0, 10800, adjval, 0, 90, Arc2D.OPEN), true);
+ path.moveTo(10800, adjval/2);
+ path.append(new Arc2D.Float(10800, adjval/2, 10800, adjval, 90, 180, Arc2D.OPEN), true);
+ //path.append(new Arc2D.Float(0, adjval/2, 10800, adjval, 180, 270, Arc2D.OPEN), true);
+ //path.append(new Arc2D.Float(0, 0, 10800, adjval, 270, 360, Arc2D.OPEN), true);
+ return path;
+ }
+ };
+
+ shapes[DOWN_ARROW] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m0@0 l@1@0 @1,0 @2,0 @2@0,21600@0,10800,21600xe
+ int adjval = shape.getAdjustValue("adj1", 16200);
+ int adjval2 = shape.getAdjustValue("adj2", 5400);
+ GeneralPath path = new GeneralPath();
+ path.moveTo(0, adjval);
+ path.lineTo(adjval2, adjval);
+ path.lineTo(adjval2, 0);
+ path.lineTo(21600-adjval2, 0);
+ path.lineTo(21600-adjval2, adjval);
+ path.lineTo(21600, adjval);
+ path.lineTo(10800, 21600);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[UP_ARROW] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m0@0 l@1@0 @1,21600@2,21600@2@0,21600@0,10800,xe
+ int adjval = shape.getAdjustValue("adj1", 5400);
+ int adjval2 = shape.getAdjustValue("adj2", 5400);
+ GeneralPath path = new GeneralPath();
+ path.moveTo(0, adjval);
+ path.lineTo(adjval2, adjval);
+ path.lineTo(adjval2, 21600);
+ path.lineTo(21600-adjval2, 21600);
+ path.lineTo(21600-adjval2, adjval);
+ path.lineTo(21600, adjval);
+ path.lineTo(10800, 0);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[RIGHT_ARROW] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m@0, l@0@1 ,0@1,0@2@0@2@0,21600,21600,10800xe
+ int adjval = shape.getAdjustValue("adj1", 16200);
+ int adjval2 = shape.getAdjustValue("adj2", 5400);
+ GeneralPath path = new GeneralPath();
+ path.moveTo(adjval, 0);
+ path.lineTo(adjval, adjval2);
+ path.lineTo(0, adjval2);
+ path.lineTo(0, 21600-adjval2);
+ path.lineTo(adjval, 21600-adjval2);
+ path.lineTo(adjval, 21600);
+ path.lineTo(21600, 10800);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[LEFT_ARROW] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m@0, l@0@1,21600@1,21600@2@0@2@0,21600,,10800xe
+ int adjval = shape.getAdjustValue("adj1", 5400);
+ int adjval2 = shape.getAdjustValue("adj2", 5400);
+ GeneralPath path = new GeneralPath();
+ path.moveTo(adjval, 0);
+ path.lineTo(adjval, adjval2);
+ path.lineTo(21600, adjval2);
+ path.lineTo(21600, 21600-adjval2);
+ path.lineTo(adjval, 21600-adjval2);
+ path.lineTo(adjval, 21600);
+ path.lineTo(0, 10800);
+ path.closePath();
+ return path;
+ }
+ };
+ shapes[LEFT_BRACE] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m21600,qx10800@0l10800@2qy0@11,10800@3l10800@1qy21600,21600e
+ int adjval = shape.getAdjustValue("adj1", 1800);
+ int adjval2 = shape.getAdjustValue("adj2", 10800);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(21600, 0);
+
+ path.append(new Arc2D.Float(10800, 0, 21600, adjval*2, 90, 90, Arc2D.OPEN), false);
+ path.moveTo(10800, adjval);
+
+ path.lineTo(10800, adjval2 - adjval);
+
+ path.append(new Arc2D.Float(-10800, adjval2 - 2*adjval, 21600, adjval*2, 270, 90, Arc2D.OPEN), false);
+ path.moveTo(0, adjval2);
+
+ path.append(new Arc2D.Float(-10800, adjval2, 21600, adjval*2, 0, 90, Arc2D.OPEN), false);
+ path.moveTo(10800, adjval2 + adjval);
+
+ path.lineTo(10800, 21600 - adjval);
+
+ path.append(new Arc2D.Float(10800, 21600 - 2*adjval, 21600, adjval*2, 180, 90, Arc2D.OPEN), false);
+
+ return path;
+ }
+ };
+
+ shapes[RIGHT_BRACE] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m,qx10800@0 l10800@2qy21600@11,10800@3l10800@1qy,21600e
+ int adjval = shape.getAdjustValue("adj1", 1800);
+ int adjval2 = shape.getAdjustValue("adj2", 10800);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(0, 0);
+
+ path.append(new Arc2D.Float(-10800, 0, 21600, adjval*2, 0, 90, Arc2D.OPEN), false);
+ path.moveTo(10800, adjval);
+
+ path.lineTo(10800, adjval2 - adjval);
+
+ path.append(new Arc2D.Float(10800, adjval2 - 2*adjval, 21600, adjval*2, 180, 90, Arc2D.OPEN), false);
+ path.moveTo(21600, adjval2);
+
+ path.append(new Arc2D.Float(10800, adjval2, 21600, adjval*2, 90, 90, Arc2D.OPEN), false);
+ path.moveTo(10800, adjval2 + adjval);
+
+ path.lineTo(10800, 21600 - adjval);
+
+ path.append(new Arc2D.Float(-10800, 21600 - 2*adjval, 21600, adjval*2, 270, 90, Arc2D.OPEN), false);
+
+ return path;
+ }
+ };
+
+
+ shapes[LEFT_RIGHT_ARROW] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m,10800l@0,21600@0@3@2@3@2,21600,21600,10800@2,0@2@1@0@1@0,xe
+ int adjval = shape.getAdjustValue("adj1", 4320);
+ int adjval2 = shape.getAdjustValue("adj2", 5400);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(0, 10800);
+ path.lineTo(adjval, 0);
+ path.lineTo(adjval, adjval2);
+ path.lineTo(21600 - adjval, adjval2);
+ path.lineTo(21600 - adjval, 0);
+ path.lineTo(21600, 10800);
+ path.lineTo(21600 - adjval, 21600);
+ path.lineTo(21600 - adjval, 21600 - adjval2);
+ path.lineTo(adjval, 21600 - adjval2);
+ path.lineTo(adjval, 21600);
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[UP_DOWN_ARROW] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m10800,l21600@0@3@0@3@2,21600@2,10800,21600,0@2@1@2@1@0,0@0xe
+ int adjval1 = shape.getAdjustValue("adj1", 5400);
+ int adjval2 = shape.getAdjustValue("adj2", 4320);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(10800, 0);
+ path.lineTo(21600, adjval2);
+ path.lineTo(21600 - adjval1, adjval2);
+ path.lineTo(21600 - adjval1, 21600 - adjval2);
+ path.lineTo(21600, 21600 - adjval2);
+
+ path.lineTo(10800, 21600);
+ path.lineTo(0, 21600 - adjval2);
+ path.lineTo(adjval1, 21600 - adjval2);
+ path.lineTo(adjval1, adjval2);
+ path.lineTo(0, adjval2);
+
+ path.closePath();
+ return path;
+ }
+ };
+
+ shapes[NOTCHED_RIGHT_ARROW] = new ShapeOutline(){
+ public java.awt.Shape getOutline(XSLFAutoShape shape){
+ //m@0,l@0@1,0@1@5,10800,0@2@0@2@0,21600,21600,10800xe
+ int adjval1 = shape.getAdjustValue("adj1", 16200);
+ int adjval2 = shape.getAdjustValue("adj2", 5400);
+
+ GeneralPath path = new GeneralPath();
+ path.moveTo(adjval1, 0);
+ path.lineTo(adjval1, adjval2);
+ path.lineTo(0, adjval2);
+ //The notch at the end stays adjusted so that it matches the shape of the arrowhead.
+ int notch = (21600-2*adjval2)*(21600-adjval1)/21600;
+ path.lineTo(notch, 10800);
+ path.lineTo(0, 21600 - adjval2);
+ path.lineTo(adjval1, 21600 - adjval2);
+ path.lineTo(adjval1, 21600);
+ path.lineTo(21600, 10800);
+ path.closePath();
+ return path;
+ }
+ };
+ }
+
+ static Shape getOutline(XSLFAutoShape shape){
+ ShapeOutline outline = shapes[shape.getShapeType()];
+ return outline == null ? null : outline.getOutline(shape);
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRenderingHint.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRenderingHint.java
new file mode 100644
index 0000000000..aff8c90c41
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRenderingHint.java
@@ -0,0 +1,42 @@
+/*
+ * ====================================================================
+ * 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.awt.*;
+
+/**
+ *
+ * @author Yegor Kozlov
+ */
+public class XSLFRenderingHint extends RenderingHints.Key {
+
+ public XSLFRenderingHint(int i){
+ super(i);
+ }
+
+ @Override
+ public boolean isCompatibleValue(Object val) {
+ return true;
+ }
+
+ public static final XSLFRenderingHint GSAVE = new XSLFRenderingHint(1);
+ public static final XSLFRenderingHint GRESTORE = new XSLFRenderingHint(2);
+ public static final XSLFRenderingHint SKIP_PLACEHOLDERS = new XSLFRenderingHint(3);
+} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java
new file mode 100644
index 0000000000..e897e29fba
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java
@@ -0,0 +1,106 @@
+/* ====================================================================
+ 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 org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.util.Units;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+
+/**
+ * Represents a shadow of a shape. For now supports only outer shadows.
+ *
+ * @author Yegor Kozlov
+ */
+public class XSLFShadow extends XSLFSimpleShape {
+ private XSLFSimpleShape _parent;
+
+ /* package */XSLFShadow(CTOuterShadowEffect shape, XSLFSimpleShape parentShape) {
+ super(shape, parentShape.getSheet());
+
+ _parent = parentShape;
+ }
+
+ public void draw(Graphics2D graphics) {
+ Shape outline = _parent.getOutline();
+
+ double angle = getAngle();
+ double dist = getDistance();
+ double dx = dist * Math.cos( Math.toRadians(angle));
+ double dy = dist * Math.sin( Math.toRadians(angle));
+
+ graphics.translate(dx, dy);
+
+ //fill
+ Color fillColor = getFillColor();
+ if (fillColor != null) {
+ graphics.setColor(fillColor);
+ graphics.fill(outline);
+ }
+
+ graphics.translate(-dx, -dy);
+ }
+
+ @Override
+ public Rectangle2D getAnchor(){
+ return _parent.getAnchor();
+ }
+
+ @Override
+ public void setAnchor(Rectangle2D anchor){
+ throw new IllegalStateException("You can't set anchor of a shadow");
+ }
+
+ public double getDistance(){
+ CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
+ return ct.isSetDist() ? Units.toPoints(ct.getDist()) : 0;
+ }
+
+ public double getAngle(){
+ CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
+ return ct.isSetDir() ? (double)ct.getDir() / 60000 : 0;
+ }
+
+ public double getBlur(){
+ CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
+ return ct.isSetBlurRad() ? Units.toPoints(ct.getBlurRad()) : 0;
+ }
+
+ @Override
+ public Color getFillColor() {
+ XSLFTheme theme = getSheet().getTheme();
+ CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
+ if(ct.isSetSchemeClr()) {
+ return theme.getSchemeColor(ct.getSchemeClr());
+ }
+ else if (ct.isSetPrstClr()) {
+ return theme.getPresetColor(ct.getPrstClr());
+ }
+
+ return Color.black;
+ }
+} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
index dfb659557f..2c676caf40 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
@@ -19,10 +19,11 @@
package org.apache.poi.xslf.usermodel;
-import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
/**
@@ -41,4 +42,76 @@ public abstract class XSLFShape {
public abstract String getShapeName();
public abstract int getShapeId();
+
+ /**
+ * Rotate this shape.
+ * <p>
+ * Positive angles are clockwise (i.e., towards the positive y axis);
+ * negative angles are counter-clockwise (i.e., towards the negative y axis).
+ * </p>
+ *
+ * @param theta the rotation angle in degrees.
+ */
+ public abstract void setRotation(double theta);
+
+ /**
+ * Rotation angle in degrees
+ * <p>
+ * Positive angles are clockwise (i.e., towards the positive y axis);
+ * negative angles are counter-clockwise (i.e., towards the negative y axis).
+ * </p>
+ *
+ * @return rotation angle in degrees
+ */
+ public abstract double getRotation();
+
+ public abstract void setFlipHorizontal(boolean flip);
+
+ public abstract void setFlipVertical(boolean flip);
+
+ /**
+ * Whether the shape is horizontally flipped
+ *
+ * @return whether the shape is horizontally flipped
+ */
+ public abstract boolean getFlipHorizontal();
+
+ public abstract boolean getFlipVertical();
+
+ public abstract void draw(Graphics2D graphics);
+
+ protected java.awt.Shape getOutline(){
+ return getAnchor();
+ }
+
+ protected void applyTransform(Graphics2D graphics){
+ Rectangle2D anchor = getAnchor();
+
+ // rotation
+ double rotation = getRotation();
+ if(rotation != 0.) {
+ // PowerPoint rotates shapes relative to the geometric center
+ double centerX = anchor.getX() + anchor.getWidth()/2;
+ double centerY = anchor.getY() + anchor.getHeight()/2;
+
+ graphics.translate(centerX, centerY);
+ graphics.rotate(Math.toRadians(rotation));
+ graphics.translate(-centerX, -centerY);
+ }
+
+ //flip horizontal
+ if(getFlipHorizontal()){
+ graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());
+ graphics.scale(-1, 1);
+ graphics.translate(-anchor.getX() , -anchor.getY());
+ }
+
+ //flip vertical
+ if(getFlipVertical()){
+ graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());
+ graphics.scale(1, -1);
+ graphics.translate(-anchor.getX(), -anchor.getY());
+ }
+ }
+
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
index 58e26eb873..f4a46fc901 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
@@ -21,6 +21,7 @@ import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
@@ -30,9 +31,13 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFra
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
import javax.xml.namespace.QName;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -47,6 +52,8 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
private XSLFDrawing _drawing;
private List<XSLFShape> _shapes;
private CTGroupShape _spTree;
+ private Map<Integer, XSLFSimpleShape> _placeholderByIdMap;
+ private Map<Integer, XSLFSimpleShape> _placeholderByTypeMap;
public XSLFSheet() {
super();
@@ -187,6 +194,10 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
return getShapeList().remove(xShape);
}
+ public XSLFBackground getBackground(){
+ return null;
+ }
+
protected abstract String getRootElementName();
protected CTGroupShape getSpTree(){
@@ -232,4 +243,112 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
getXmlObject().set(src.getXmlObject());
}
+ public XSLFTheme getTheme(){
+ return null;
+ }
+
+ public XSLFSlideMaster getSlideMaster(){
+ return null;
+ }
+
+ public XSLFSlideLayout getSlideLayout(){
+ return null;
+ }
+
+ protected CTTextListStyle getTextProperties(Placeholder textType) {
+ return null;
+ }
+
+ protected XSLFTextShape getTextShapeByType(Placeholder type){
+ for(XSLFShape shape : this.getShapes()){
+ if(shape instanceof XSLFTextShape) {
+ XSLFTextShape txt = (XSLFTextShape)shape;
+ if(txt.getTextType() == type) {
+ return txt;
+ }
+ }
+ }
+ return null;
+ }
+
+ XSLFSimpleShape getPlaceholder(CTPlaceholder ph) {
+ XSLFSimpleShape shape = null;
+ if(ph.isSetIdx()) shape = getPlaceholderById((int)ph.getIdx());
+
+ if (shape == null && ph.isSetType()) {
+ shape = getPlaceholderByType(ph.getType().intValue());
+ }
+ return shape;
+ }
+
+ XSLFSimpleShape getPlaceholderById(int id) {
+ if(_placeholderByIdMap == null) {
+ _placeholderByIdMap = new HashMap<Integer, XSLFSimpleShape>();
+ for(XSLFShape sh : getShapes()){
+ if(sh instanceof XSLFSimpleShape){
+ XSLFSimpleShape sShape = (XSLFSimpleShape)sh;
+ CTPlaceholder ph = sShape.getCTPlaceholder();
+ if(ph != null && ph.isSetIdx()){
+ int idx = (int)ph.getIdx();
+ _placeholderByIdMap.put(idx, sShape);
+ }
+ }
+ }
+ }
+ return _placeholderByIdMap.get(id);
+ }
+
+ XSLFSimpleShape getPlaceholderByType(int ordinal) {
+ if(_placeholderByTypeMap == null) {
+ _placeholderByTypeMap = new HashMap<Integer, XSLFSimpleShape>();
+ for(XSLFShape sh : getShapes()){
+ if(sh instanceof XSLFSimpleShape){
+ XSLFSimpleShape sShape = (XSLFSimpleShape)sh;
+ CTPlaceholder ph = sShape.getCTPlaceholder();
+ if(ph != null && ph.isSetType()){
+ _placeholderByTypeMap.put(ph.getType().intValue(), sShape);
+ }
+ }
+ }
+ }
+ return _placeholderByTypeMap.get(ordinal);
+ }
+
+ /**
+ * Checks if this <code>sheet</code> displays the specified shape.
+ *
+ * Subclasses can override it and skip certain shapes from drawings.
+ */
+ protected boolean canDraw(XSLFShape shape){
+ return true;
+ }
+
+ /**
+ * Render this sheet into the supplied graphics object
+ *
+ * @param graphics
+ */
+ public void draw(Graphics2D graphics){
+ XSLFBackground bg = getBackground();
+ if(bg != null) bg.draw(graphics);
+
+ for(XSLFShape shape : getShapeList()) {
+ if(!canDraw(shape)) continue;
+
+ // remember the initial transform and restore it after we are done with drawing
+ AffineTransform at0 = graphics.getTransform();
+
+ graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true);
+
+ // apply rotation and flipping
+ shape.applyTransform(graphics);
+
+ shape.draw(graphics);
+
+ // restore the coordinate system
+ graphics.setTransform(at0);
+ graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true);
+
+ }
+ }
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
index 3b624dc0ab..8e3b38a227 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
@@ -21,6 +21,7 @@ package org.apache.poi.xslf.usermodel;
import org.apache.poi.xslf.usermodel.LineCap;
import org.apache.poi.xslf.usermodel.LineDash;
+import org.apache.poi.xslf.model.PropertyFetcher;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlObject;
@@ -28,14 +29,22 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetLineDashProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
import java.awt.*;
import java.awt.geom.Rectangle2D;
@@ -48,26 +57,31 @@ public abstract class XSLFSimpleShape extends XSLFShape {
private final XmlObject _shape;
private final XSLFSheet _sheet;
private CTShapeProperties _spPr;
+ private CTShapeStyle _spStyle;
private CTNonVisualDrawingProps _nvPr;
+ private CTPlaceholder _ph;
- /*package*/ XSLFSimpleShape(XmlObject shape, XSLFSheet sheet){
+ /* package */XSLFSimpleShape(XmlObject shape, XSLFSheet sheet) {
_shape = shape;
_sheet = sheet;
}
- public XmlObject getXmlObject(){
+ public XmlObject getXmlObject() {
return _shape;
}
-
- public XSLFSheet getSheet(){
+
+ public XSLFSheet getSheet() {
return _sheet;
}
+
/**
- * TODO match STShapeType with {@link org.apache.poi.sl.usermodel.ShapeTypes}
+ * TODO match STShapeType with
+ * {@link org.apache.poi.sl.usermodel.ShapeTypes}
*/
public int getShapeType() {
- STShapeType.Enum stEnum = getSpPr().getPrstGeom().getPrst();
- return stEnum.intValue();
+ CTPresetGeometry2D prst = getSpPr().getPrstGeom();
+ STShapeType.Enum stEnum = prst == null ? null : prst.getPrst();
+ return stEnum == null ? 0 : stEnum.intValue();
}
public String getShapeName() {
@@ -75,36 +89,75 @@ public abstract class XSLFSimpleShape extends XSLFShape {
}
public int getShapeId() {
- return (int)getNvPr().getId();
+ return (int) getNvPr().getId();
}
- protected CTNonVisualDrawingProps getNvPr(){
- if(_nvPr == null){
- XmlObject[] rs = _shape.selectPath(
- "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:cNvPr");
- if(rs.length != 0) {
- _nvPr = (CTNonVisualDrawingProps)rs[0];
+ protected CTNonVisualDrawingProps getNvPr() {
+ if (_nvPr == null) {
+ XmlObject[] rs = _shape
+ .selectPath("declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:cNvPr");
+ if (rs.length != 0) {
+ _nvPr = (CTNonVisualDrawingProps) rs[0];
}
}
return _nvPr;
}
- protected CTShapeProperties getSpPr(){
- if(_spPr == null) {
- for(XmlObject obj : _shape.selectPath("*")){
- if(obj instanceof CTShapeProperties){
- _spPr = (CTShapeProperties)obj;
+ protected CTShapeProperties getSpPr() {
+ if (_spPr == null) {
+ for (XmlObject obj : _shape.selectPath("*")) {
+ if (obj instanceof CTShapeProperties) {
+ _spPr = (CTShapeProperties) obj;
}
}
}
- if(_spPr == null) {
+ if (_spPr == null) {
throw new IllegalStateException("CTShapeProperties was not found.");
}
return _spPr;
}
- public Rectangle2D getAnchor(){
- CTTransform2D xfrm = getSpPr().getXfrm();
+ protected CTShapeStyle getSpStyle() {
+ if (_spStyle == null) {
+ for (XmlObject obj : _shape.selectPath("*")) {
+ if (obj instanceof CTShapeStyle) {
+ _spStyle = (CTShapeStyle) obj;
+ }
+ }
+ }
+ return _spStyle;
+ }
+
+ protected CTPlaceholder getCTPlaceholder(){
+ if(_ph == null){
+ XmlObject[] obj = _shape.selectPath(
+ "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:nvPr/p:ph");
+ if(obj.length == 1){
+ _ph = (CTPlaceholder)obj[0];
+ }
+ }
+ return _ph;
+ }
+
+ private CTTransform2D getXfrm(){
+ PropertyFetcher<CTTransform2D> fetcher = new PropertyFetcher<CTTransform2D>(){
+ public boolean fetch(XSLFSimpleShape shape){
+ CTShapeProperties pr = shape.getSpPr();
+ if(pr.isSetXfrm()){
+ setValue(pr.getXfrm());
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+ return fetcher.getValue();
+ }
+
+ public Rectangle2D getAnchor() {
+
+ CTTransform2D xfrm = getXfrm();
+
CTPoint2D off = xfrm.getOff();
long x = off.getX();
long y = off.getY();
@@ -116,14 +169,16 @@ public abstract class XSLFSimpleShape extends XSLFShape {
Units.toPoints(cx), Units.toPoints(cy));
}
- public void setAnchor(Rectangle2D anchor){
- CTTransform2D xfrm = getSpPr().isSetXfrm() ? getSpPr().getXfrm() : getSpPr().addNewXfrm();
+ public void setAnchor(Rectangle2D anchor) {
+ CTShapeProperties spPr = getSpPr();
+ CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
long x = Units.toEMU(anchor.getX());
long y = Units.toEMU(anchor.getY());
off.setX(x);
off.setY(y);
- CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm.addNewExt();
+ CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm
+ .addNewExt();
long cx = Units.toEMU(anchor.getWidth());
long cy = Units.toEMU(anchor.getHeight());
ext.setCx(cx);
@@ -134,135 +189,489 @@ public abstract class XSLFSimpleShape extends XSLFShape {
* Rotate this shape.
* <p>
* Positive angles are clockwise (i.e., towards the positive y axis);
- * negative angles are counter-clockwise (i.e., towards the negative y axis).
+ * negative angles are counter-clockwise (i.e., towards the negative y
+ * axis).
* </p>
*
* @param theta the rotation angle in degrees.
*/
- public void setRotation(double theta){
- CTTransform2D xfrm = getSpPr().getXfrm();
- xfrm.setRot((int)(theta*60000));
+ public void setRotation(double theta) {
+ CTShapeProperties spPr = getSpPr();
+ CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
+ xfrm.setRot((int) (theta * 60000));
}
/**
* Rotation angle in degrees
* <p>
* Positive angles are clockwise (i.e., towards the positive y axis);
- * negative angles are counter-clockwise (i.e., towards the negative y axis).
+ * negative angles are counter-clockwise (i.e., towards the negative y
+ * axis).
* </p>
*
* @return rotation angle in degrees
*/
- public double getRotation(){
- CTTransform2D xfrm = getSpPr().getXfrm();
- return (double)xfrm.getRot()/60000;
+ public double getRotation() {
+ CTTransform2D xfrm = getXfrm();
+ return (double) xfrm.getRot() / 60000;
}
- public void setFlipHorizontal(boolean flip){
- CTTransform2D xfrm = getSpPr().getXfrm();
+ public void setFlipHorizontal(boolean flip) {
+ CTShapeProperties spPr = getSpPr();
+ CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
xfrm.setFlipH(flip);
}
- public void setFlipVertical(boolean flip){
- CTTransform2D xfrm = getSpPr().getXfrm();
+ public void setFlipVertical(boolean flip) {
+ CTShapeProperties spPr = getSpPr();
+ CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
xfrm.setFlipV(flip);
}
+
/**
* Whether the shape is horizontally flipped
*
* @return whether the shape is horizontally flipped
*/
- public boolean getFlipHorizontal(){
- return getSpPr().getXfrm().getFlipH();
+ public boolean getFlipHorizontal() {
+ return getXfrm().getFlipH();
}
- public boolean getFlipVertical(){
- return getSpPr().getXfrm().getFlipV();
+ public boolean getFlipVertical() {
+ return getXfrm().getFlipV();
}
- public void setLineColor(Color color){
- CTShapeProperties spPr = getSpPr();
- if(color == null) {
- if(spPr.isSetLn() && spPr.getLn().isSetSolidFill()) spPr.getLn().unsetSolidFill();
+ /**
+ * Get line properties defined in the theme (if any)
+ *
+ * @return line propeties from the theme of null
+ */
+ CTLineProperties getDefaultLineProperties() {
+ CTLineProperties ln = null;
+ CTShapeStyle style = getSpStyle();
+ if (style != null) {
+ // 1-based index of a line style within the style matrix
+ int idx = (int) style.getLnRef().getIdx();
+ CTStyleMatrix styleMatrix = _sheet.getTheme().getXmlObject().getThemeElements().getFmtScheme();
+ ln = styleMatrix.getLnStyleLst().getLnArray(idx - 1);
}
- else {
- CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr.addNewLn();
+ return ln;
+ }
+
+ public void setLineColor(Color color) {
+ CTShapeProperties spPr = getSpPr();
+ if (color == null) {
+ if (spPr.isSetLn() && spPr.getLn().isSetSolidFill())
+ spPr.getLn().unsetSolidFill();
+ } else {
+ CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
+ .addNewLn();
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
- rgb.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});
+ rgb.setVal(new byte[]{(byte) color.getRed(),
+ (byte) color.getGreen(), (byte) color.getBlue()});
- CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln.getSolidFill() : ln.addNewSolidFill();
+ CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln
+ .getSolidFill() : ln.addNewSolidFill();
fill.setSrgbClr(rgb);
}
}
- public Color getLineColor(){
- CTShapeProperties spPr = getSpPr();
- if(!spPr.isSetLn() || !spPr.getLn().isSetSolidFill()) return null;
-
- CTSRgbColor rgb = spPr.getLn().getSolidFill().getSrgbClr();
- byte[] val = rgb.getVal();
- return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
+ public Color getLineColor() {
+ final XSLFTheme theme = _sheet.getTheme();
+
+ PropertyFetcher<Color> fetcher = new PropertyFetcher<Color>(){
+ public boolean fetch(XSLFSimpleShape shape){
+ CTShapeProperties spPr = shape.getSpPr();
+ CTLineProperties ln = spPr.getLn();
+ if (ln != null) {
+ if (ln.isSetNoFill()) {
+ setValue(null);
+ return true;
+ }
+ CTSolidColorFillProperties solidLine = ln.getSolidFill();
+ if (solidLine != null) {
+ setValue( theme.getSolidFillColor(ln.getSolidFill()) );
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+
+ Color color = fetcher.getValue();
+ if(color == null){
+ // line color was not found, check if it is defined in the theme
+ CTShapeStyle style = getSpStyle();
+ if (style != null) {
+ CTSchemeColor schemeColor = style.getLnRef().getSchemeClr();
+ if (schemeColor != null) {
+ color = theme.getSchemeColor(schemeColor);
+ }
+ }
+ }
+ return color;
}
- public void setLineWidth(double width){
+ public void setLineWidth(double width) {
CTShapeProperties spPr = getSpPr();
- if(width == 0.) {
- if(spPr.isSetLn()) spPr.getLn().unsetW();
- }
- else {
- CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr.addNewLn();
+ if (width == 0.) {
+ if (spPr.isSetLn())
+ spPr.getLn().unsetW();
+ } else {
+ CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
+ .addNewLn();
ln.setW(Units.toEMU(width));
}
}
- public double getLineWidth(){
- CTShapeProperties spPr = getSpPr();
- CTLineProperties ln = spPr.getLn();
- if(ln == null || !ln.isSetW()) return 0;
+ public double getLineWidth() {
+ PropertyFetcher<Double> fetcher = new PropertyFetcher<Double>(){
+ public boolean fetch(XSLFSimpleShape shape){
+ CTShapeProperties spPr = shape.getSpPr();
+ CTLineProperties ln = spPr.getLn();
+ if (ln != null) {
+ if (ln.isSetNoFill()) {
+ setValue(0.);
+ return true;
+ }
+
+ if (ln.isSetW()) {
+ setValue( Units.toPoints(ln.getW()) );
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+
+ double lineWidth = 0;
+ if(fetcher.getValue() == null) {
+ CTLineProperties defaultLn = getDefaultLineProperties();
+ if (defaultLn != null) {
+ if (defaultLn.isSetW()) lineWidth = Units.toPoints(defaultLn.getW());
+ }
+ } else {
+ lineWidth = fetcher.getValue();
+ }
- return Units.toPoints(ln.getW());
+ return lineWidth;
}
- public void setLineDash(LineDash dash){
+ public void setLineDash(LineDash dash) {
CTShapeProperties spPr = getSpPr();
- if(dash == null) {
- if(spPr.isSetLn()) spPr.getLn().unsetPrstDash();
- }
- else {
- CTPresetLineDashProperties val = CTPresetLineDashProperties.Factory.newInstance();
+ if (dash == null) {
+ if (spPr.isSetLn())
+ spPr.getLn().unsetPrstDash();
+ } else {
+ CTPresetLineDashProperties val = CTPresetLineDashProperties.Factory
+ .newInstance();
val.setVal(STPresetLineDashVal.Enum.forInt(dash.ordinal() + 1));
- CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr.addNewLn();
+ CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
+ .addNewLn();
ln.setPrstDash(val);
}
}
- public LineDash getLineDash(){
+ public LineDash getLineDash() {
+
+ PropertyFetcher<LineDash> fetcher = new PropertyFetcher<LineDash>(){
+ public boolean fetch(XSLFSimpleShape shape){
+ CTShapeProperties spPr = shape.getSpPr();
+ CTLineProperties ln = spPr.getLn();
+ if (ln != null) {
+ CTPresetLineDashProperties ctDash = ln.getPrstDash();
+ if (ctDash != null) {
+ setValue( LineDash.values()[ctDash.getVal().intValue() - 1] );
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+
+ LineDash dash = fetcher.getValue();
+ if(dash == null){
+ CTLineProperties defaultLn = getDefaultLineProperties();
+ if (defaultLn != null) {
+ CTPresetLineDashProperties ctDash = defaultLn.getPrstDash();
+ if (ctDash != null) {
+ dash = LineDash.values()[ctDash.getVal().intValue() - 1];
+ }
+ }
+ }
+ return dash;
+ }
+
+ public void setLineCap(LineCap cap) {
CTShapeProperties spPr = getSpPr();
- CTLineProperties ln = spPr.getLn();
- if(ln == null || !ln.isSetPrstDash()) return null;
+ if (cap == null) {
+ if (spPr.isSetLn())
+ spPr.getLn().unsetCap();
+ } else {
+ CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr
+ .addNewLn();
+ ln.setCap(STLineCap.Enum.forInt(cap.ordinal() + 1));
+ }
+ }
- CTPresetLineDashProperties dash = ln.getPrstDash();
- return LineDash.values()[dash.getVal().intValue() - 1];
+ public LineCap getLineCap() {
+ PropertyFetcher<LineCap> fetcher = new PropertyFetcher<LineCap>(){
+ public boolean fetch(XSLFSimpleShape shape){
+ CTShapeProperties spPr = shape.getSpPr();
+ CTLineProperties ln = spPr.getLn();
+ if (ln != null) {
+ STLineCap.Enum stCap = ln.getCap();
+ if (stCap != null) {
+ setValue( LineCap.values()[stCap.intValue() - 1] );
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+
+ LineCap cap = fetcher.getValue();
+ if(cap == null){
+ CTLineProperties defaultLn = getDefaultLineProperties();
+ if (defaultLn != null) {
+ STLineCap.Enum stCap = defaultLn.getCap();
+ if (stCap != null) {
+ cap = LineCap.values()[stCap.intValue() - 1];
+ }
+ }
+ }
+ return cap;
}
- public void setLineCap(LineCap cap){
+ /**
+ * Specifies a solid color fill. The shape is filled entirely with the
+ * specified color.
+ *
+ * @param color the solid color fill. The value of <code>null</code> unsets
+ * the solidFIll attribute from the underlying xml
+ */
+ public void setFillColor(Color color) {
CTShapeProperties spPr = getSpPr();
- if(cap == null) {
- if(spPr.isSetLn()) spPr.getLn().unsetCap();
+ if (color == null) {
+ if (spPr.isSetSolidFill()) spPr.unsetSolidFill();
+
+ if(!spPr.isSetNoFill()) spPr.addNewNoFill();
+ } else {
+ if(spPr.isSetNoFill()) spPr.unsetNoFill();
+
+ CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr
+ .getSolidFill() : spPr.addNewSolidFill();
+
+ CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
+ rgb.setVal(new byte[]{(byte) color.getRed(),
+ (byte) color.getGreen(), (byte) color.getBlue()});
+
+ fill.setSrgbClr(rgb);
}
- else {
- CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr.addNewLn();
- ln.setCap(STLineCap.Enum.forInt(cap.ordinal() + 1));
+ }
+
+ /**
+ * @return solid fill color of null if not set
+ */
+ public Color getFillColor() {
+ final XSLFTheme theme = _sheet.getTheme();
+
+ PropertyFetcher<Color> fetcher = new PropertyFetcher<Color>(){
+ public boolean fetch(XSLFSimpleShape shape){
+ CTShapeProperties spPr = shape.getSpPr();
+ if (spPr.isSetNoFill()) {
+ setValue(null);
+ return true;
+ }
+ if (spPr.isSetSolidFill()) {
+ setValue( theme.getSolidFillColor(spPr.getSolidFill()) );
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+
+ Color color = fetcher.getValue();
+ if(color == null){
+ // fill color was not found, check if it is defined in the theme
+ CTShapeStyle style = getSpStyle();
+ if (style != null) {
+ CTSchemeColor schemeColor = style.getFillRef().getSchemeClr();
+ if (schemeColor != null) {
+ color = theme.getSchemeColor(schemeColor);
+ }
+ }
}
+ return color;
}
- public LineCap getLineCap(){
- CTShapeProperties spPr = getSpPr();
- CTLineProperties ln = spPr.getLn();
- if(ln == null || !ln.isSetCap()) return null;
+ public XSLFShadow getShadow(){
+ PropertyFetcher<CTOuterShadowEffect> fetcher = new PropertyFetcher<CTOuterShadowEffect>(){
+ public boolean fetch(XSLFSimpleShape shape){
+ CTShapeProperties spPr = shape.getSpPr();
+ if (spPr.isSetEffectLst()) {
+ CTOuterShadowEffect obj = spPr.getEffectLst().getOuterShdw();
+ setValue(obj);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+
+ CTOuterShadowEffect obj = fetcher.getValue();
+ if(obj == null){
+ // fill color was not found, check if it is defined in the theme
+ CTShapeStyle style = getSpStyle();
+ if (style != null) {
+ // 1-based index of a shadow style within the style matrix
+ int idx = (int) style.getEffectRef().getIdx();
+
+ CTStyleMatrix styleMatrix = _sheet.getTheme().getXmlObject().getThemeElements().getFmtScheme();
+ CTEffectStyleItem ef = styleMatrix.getEffectStyleLst().getEffectStyleArray(idx - 1);
+ obj = ef.getEffectLst().getOuterShdw();
+ }
+ }
+ return obj == null ? null : new XSLFShadow(obj, this);
+ }
+
+ public void draw(Graphics2D graphics) {
+
+ }
+
+ protected void applyFill(Graphics2D graphics) {
+
+ }
+
+ protected float[] getDashPattern(LineDash lineDash, float lineWidth) {
+ float[] dash = null;
+ switch (lineDash) {
+ case SYS_DOT:
+ dash = new float[]{lineWidth, lineWidth};
+ break;
+ case SYS_DASH:
+ dash = new float[]{2 * lineWidth, 2 * lineWidth};
+ break;
+ case DASH:
+ dash = new float[]{3 * lineWidth, 4 * lineWidth};
+ break;
+ case DASH_DOT:
+ dash = new float[]{4 * lineWidth, 3 * lineWidth, lineWidth,
+ 3 * lineWidth};
+ break;
+ case LG_DASH:
+ dash = new float[]{8 * lineWidth, 3 * lineWidth};
+ break;
+ case LG_DASH_DOT:
+ dash = new float[]{8 * lineWidth, 3 * lineWidth, lineWidth,
+ 3 * lineWidth};
+ break;
+ case LG_DASH_DOT_DOT:
+ dash = new float[]{8 * lineWidth, 3 * lineWidth, lineWidth,
+ 3 * lineWidth, lineWidth, 3 * lineWidth};
+ break;
+ }
+ return dash;
+ }
+
+ protected void applyStroke(Graphics2D graphics) {
+
+ float lineWidth = (float) getLineWidth();
+ LineDash lineDash = getLineDash();
+ float[] dash = null;
+ float dash_phase = 0;
+ if (lineDash != null) {
+ dash = getDashPattern(lineDash, lineWidth);
+ }
+
+ int cap = BasicStroke.CAP_BUTT;
+ LineCap lineCap = getLineCap();
+ if (lineCap != null) {
+ switch (lineCap) {
+ case ROUND:
+ cap = BasicStroke.CAP_ROUND;
+ break;
+ case SQUARE:
+ cap = BasicStroke.CAP_SQUARE;
+ break;
+ default:
+ cap = BasicStroke.CAP_BUTT;
+ break;
+ }
+ }
+
+ int meter = BasicStroke.JOIN_ROUND;
+
+ Stroke stroke = new BasicStroke(lineWidth, cap, meter, 0.0f, dash,
+ dash_phase);
+ graphics.setStroke(stroke);
+ }
+
+ /**
+ * Walk up the inheritance tree and fetch properties.
+ *
+ * slide <-- slideLayout <-- slideMaster
+ *
+ *
+ * @param visitor the object that collects the desired property
+ * @return true if the property was fetched
+ */
+ boolean fetchShapeProperty(PropertyFetcher visitor){
+ boolean ok = visitor.fetch(this);
+
+ XSLFSimpleShape masterShape;
+ if(!ok){
+
+ // first try to fetch from the slide layout
+ XSLFSlideLayout layout = getSheet().getSlideLayout();
+ if(layout != null) {
+ CTPlaceholder ph = getCTPlaceholder();
+ if (ph != null) {
+ masterShape = layout.getPlaceholder(ph);
+ if (masterShape != null) {
+ ok = visitor.fetch(masterShape);
+ }
+ }
+ }
+ }
+
+ // try slide master
+ if (!ok) {
+ int textType;
+ CTPlaceholder ph = getCTPlaceholder();
+ if(ph == null || !ph.isSetType()) textType = STPlaceholderType.INT_BODY;
+ else {
+ switch(ph.getType().intValue()){
+ case STPlaceholderType.INT_TITLE:
+ case STPlaceholderType.INT_CTR_TITLE:
+ textType = STPlaceholderType.INT_TITLE;
+ break;
+ case STPlaceholderType.INT_FTR:
+ case STPlaceholderType.INT_SLD_NUM:
+ case STPlaceholderType.INT_DT:
+ textType = ph.getType().intValue();
+ break;
+ default:
+ textType = STPlaceholderType.INT_BODY;
+ break;
+ }
+ }
+ XSLFSlideMaster master = getSheet().getSlideMaster();
+ if(master != null) {
+ masterShape = master.getPlaceholderByType(textType);
+ if (masterShape != null) {
+ ok = visitor.fetch(masterShape);
+ }
+ }
+ }
- return LineCap.values()[ln.getCap().intValue() - 1];
+ return ok;
}
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java
index f0a8e9b8e3..d9f7c88e6d 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java
@@ -16,6 +16,7 @@
==================================================================== */
package org.apache.poi.xslf.usermodel;
+import java.awt.*;
import java.io.IOException;
import org.apache.poi.POIXMLDocumentPart;
@@ -23,16 +24,20 @@ import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupTransform2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual;
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
@Beta
public final class XSLFSlide extends XSLFSheet {
@@ -112,6 +117,7 @@ public final class XSLFSlide extends XSLFSheet {
return getSlideLayout().getSlideMaster();
}
+ @Override
public XSLFSlideLayout getSlideLayout(){
if(_layout == null){
for (POIXMLDocumentPart p : getRelations()) {
@@ -125,7 +131,12 @@ public final class XSLFSlide extends XSLFSheet {
}
return _layout;
}
-
+
+ @Override
+ public XSLFSlideMaster getSlideMaster(){
+ return getSlideLayout().getSlideMaster();
+ }
+
public XSLFComments getComments() {
if(_comments == null) {
for (POIXMLDocumentPart p : getRelations()) {
@@ -165,4 +176,37 @@ public final class XSLFSlide extends XSLFSheet {
public boolean getFollowMasterBackground(){
return !_slide.isSetShowMasterSp() || _slide.getShowMasterSp();
}
+
+ /**
+ *
+ * @return title of this slide or empty string if title is not set
+ */
+ public String getTitle(){
+ XSLFTextShape txt = getTextShapeByType(Placeholder.TITLE);
+ return txt == null ? "" : txt.getText();
+ }
+
+ public XSLFTheme getTheme(){
+ return getSlideLayout().getSlideMaster().getTheme();
+ }
+
+ @Override
+ public void draw(Graphics2D graphics){
+
+ if (getFollowMasterBackground()){
+ XSLFSlideLayout layout = getSlideLayout();
+ layout.draw(graphics);
+ }
+
+ super.draw(graphics);
+ }
+
+ @Override
+ public XSLFBackground getBackground(){
+ if(_slide.getCSld().isSetBg()) {
+ return new XSLFBackground(_slide.getCSld().getBg(), this);
+ }
+ return null;
+ }
+
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java
index 2d385382f5..ab6661125e 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java
@@ -22,11 +22,18 @@ import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal;
import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideLayout;
import org.openxmlformats.schemas.presentationml.x2006.main.SldLayoutDocument;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
import java.io.IOException;
+import java.util.Map;
+import java.util.HashMap;
+import java.awt.*;
+import java.awt.geom.AffineTransform;
@Beta
public class XSLFSlideLayout extends XSLFSheet {
@@ -84,6 +91,7 @@ public class XSLFSlideLayout extends XSLFSheet {
* @return slide master. Never null.
* @throws IllegalStateException if slide master was not found
*/
+ @Override
public XSLFSlideMaster getSlideMaster(){
if(_master == null){
for (POIXMLDocumentPart p : getRelations()) {
@@ -101,4 +109,40 @@ public class XSLFSlideLayout extends XSLFSheet {
public XMLSlideShow getSlideShow() {
return (XMLSlideShow)getParent().getParent();
}
+
+ public XSLFTheme getTheme(){
+ return getSlideMaster().getTheme();
+ }
+
+
+ @Override
+ protected CTTextListStyle getTextProperties(Placeholder textType) {
+ XSLFTextShape lp = getTextShapeByType(textType);
+ CTTextListStyle props = lp.getTextBody(false).getLstStyle();
+ return props;
+ }
+
+ /**
+ * Render this sheet into the supplied graphics object
+ *
+ */
+ @Override
+ protected boolean canDraw(XSLFShape shape){
+ if(shape instanceof XSLFSimpleShape){
+ XSLFSimpleShape txt = (XSLFSimpleShape)shape;
+ CTPlaceholder ph = txt.getCTPlaceholder();
+ if(ph != null) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public XSLFBackground getBackground(){
+ if(_layout.getCSld().isSetBg()) {
+ return new XSLFBackground(_layout.getCSld().getBg(), this);
+ }
+ return null;
+ }
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java
index b7dcad7ce8..269b76cd1f 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java
@@ -24,6 +24,8 @@ import org.apache.poi.util.Beta;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster;
import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterTextStyles;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
import java.io.IOException;
import java.util.HashMap;
@@ -101,4 +103,24 @@ import java.util.Map;
}
return _theme;
}
+
+ protected CTTextListStyle getTextProperties(Placeholder textType) {
+ CTTextListStyle props;
+ CTSlideMasterTextStyles txStyles = getXmlObject().getTxStyles();
+ switch (textType){
+ case TITLE:
+ case CENTERED_TITLE:
+ case SUBTITLE:
+ props = txStyles.getTitleStyle();
+ break;
+ case BODY:
+ props = txStyles.getBodyStyle();
+ break;
+ default:
+ props = txStyles.getOtherStyle();
+ break;
+ }
+ return props;
+ }
+
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
index dce9cc2389..173d6c8567 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
@@ -126,32 +126,4 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
gr.setUri(TABLE_URI);
return frame;
}
-
- public Rectangle2D getAnchor(){
- CTTransform2D xfrm = getXmlObject().getXfrm();
- CTPoint2D off = xfrm.getOff();
- long x = off.getX();
- long y = off.getY();
- CTPositiveSize2D ext = xfrm.getExt();
- long cx = ext.getCx();
- long cy = ext.getCy();
- return new Rectangle2D.Double(
- Units.toPoints(x), Units.toPoints(y),
- Units.toPoints(cx), Units.toPoints(cy));
- }
-
- public void setAnchor(Rectangle2D anchor){
- CTTransform2D xfrm = getXmlObject().getXfrm();
- CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
- long x = Units.toEMU(anchor.getX());
- long y = Units.toEMU(anchor.getY());
- off.setX(x);
- off.setY(y);
- CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm.addNewExt();
- long cx = Units.toEMU(anchor.getWidth());
- long cy = Units.toEMU(anchor.getHeight());
- ext.setCx(cx);
- ext.setCy(cy);
- }
-
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java
index c009f5492d..59428ef4a2 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java
@@ -21,17 +21,23 @@ package org.apache.poi.xslf.usermodel;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.util.Beta;
+import org.apache.poi.util.Units;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual;
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
+import java.awt.geom.Rectangle2D;
+
/**
* @author Yegor Kozlov
@@ -84,14 +90,4 @@ public class XSLFTextBox extends XSLFAutoShape {
nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ordinal() + 1));
}
}
-
- public Placeholder getPlaceholder(){
- CTShape sh = (CTShape)getXmlObject();
- CTPlaceholder ph = sh.getNvSpPr().getNvPr().getPh();
- if(ph == null) return null;
- else {
- int val = ph.getType().intValue();
- return Placeholder.values()[val - 1];
- }
- }
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
index e20be9b5c2..c4ac046070 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
@@ -19,15 +19,28 @@ package org.apache.poi.xslf.usermodel;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal;
import org.apache.poi.util.Units;
+import org.apache.poi.xslf.model.PropertyFetcher;
+import org.apache.poi.xslf.model.ParagraphPropertyFetcher;
+import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.font.TextLayout;
+import java.awt.font.TextAttribute;
+import java.awt.font.LineBreakMeasurer;
+import java.text.AttributedString;
+import java.text.AttributedCharacterIterator;
/**
* Represents a paragraph of text within the containing text body.
@@ -41,20 +54,29 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
private final CTTextParagraph _p;
private final List<XSLFTextRun> _runs;
private final XSLFTextShape _shape;
+ private List<TextFragment> _lines;
+ private TextFragment _bullet;
XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){
_p = p;
_runs = new ArrayList<XSLFTextRun>();
_shape = shape;
+
for (CTRegularTextRun r : _p.getRList()) {
_runs.add(new XSLFTextRun(r, this));
}
+
+ for (CTTextField f : _p.getFldList()) {
+ CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();
+ r.setT(f.getT());
+ _runs.add(new XSLFTextRun(r, this));
+ }
}
public String getText(){
StringBuilder out = new StringBuilder();
- for (CTRegularTextRun r : _p.getRList()) {
- out.append(r.getT());
+ for (XSLFTextRun r : _runs) {
+ out.append(r.getText());
}
return out.toString();
}
@@ -95,10 +117,18 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
* @return ??? alignment that is applied to the paragraph
*/
public TextAlign getTextAlign(){
- CTTextParagraphProperties pr = _p.getPPr();
- if(pr == null || !pr.isSetAlgn()) return TextAlign.LEFT;
-
- return TextAlign.values()[pr.getAlgn().intValue() - 1];
+ ParagraphPropertyFetcher<TextAlign> fetcher = new ParagraphPropertyFetcher<TextAlign>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetAlgn()){
+ TextAlign val = TextAlign.values()[props.getAlgn().intValue() - 1];
+ setValue(val);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue() == null ? TextAlign.LEFT : fetcher.getValue();
}
/**
@@ -117,6 +147,74 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
}
}
+
+ /**
+ * @return the font to be used on bullet characters within a given paragraph
+ */
+ public String getBulletFont(){
+ ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetBuFont()){
+ setValue(props.getBuFont().getTypeface());
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue();
+ }
+
+ /**
+ * @return the character to be used in place of the standard bullet point
+ */
+ public String getBulletCharacter(){
+ ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetBuChar()){
+ setValue(props.getBuChar().getChar());
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue();
+ }
+
+ public Color getBulletFontColor(){
+ final XSLFTheme theme = getParentShape().getSheet().getTheme();
+ ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetBuClr()){
+ setValue(theme.getColor(props.getBuClr()));
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue();
+ }
+
+ public double getBulletFontSize(){
+ ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetBuSzPct()){
+ setValue(props.getBuSzPct().getVal() * 0.001);
+ return true;
+ }
+ if(props.isSetBuSzPts()){
+ setValue( - props.getBuSzPts().getVal() * 0.01);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue() == null ? 100 : fetcher.getValue();
+ }
+
/**
* Specifies the indent size that will be applied to the first line of text in the paragraph.
*
@@ -137,10 +235,19 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
* @return the indent applied to the first line of text in the paragraph.
*/
public double getIndent(){
- CTTextParagraphProperties pr = _p.getPPr();
- if(pr == null || !pr.isSetIndent()) return 0;
- return Units.toPoints(pr.getIndent());
+ ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetIndent()){
+ setValue(Units.toPoints(props.getIndent()));
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+
+ return fetcher.getValue() == null ? 0 : fetcher.getValue();
}
/**
@@ -160,10 +267,18 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
* @return the left margin of the paragraph
*/
public double getLeftMargin(){
- CTTextParagraphProperties pr = _p.getPPr();
- if(pr == null || !pr.isSetMarL()) return 0;
-
- return Units.toPoints(pr.getMarL());
+ ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetMarL()){
+ double val = Units.toPoints(props.getMarL());
+ setValue(val);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue() == null ? 0 : fetcher.getValue();
}
/**
@@ -206,13 +321,20 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
* @return the vertical line spacing.
*/
public double getLineSpacing(){
- CTTextParagraphProperties pr = _p.getPPr();
- if(pr == null || !pr.isSetLnSpc()) return 100; // TODO fetch from master
-
- CTTextSpacing spc = pr.getLnSpc();
- if(spc.isSetSpcPct()) return spc.getSpcPct().getVal()*0.001;
- else if (spc.isSetSpcPts()) return -spc.getSpcPts().getVal()*0.01;
- else return 100;
+ ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetLnSpc()){
+ CTTextSpacing spc = props.getLnSpc();
+
+ if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );
+ else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue() == null ? 100 : fetcher.getValue();
}
/**
@@ -253,13 +375,20 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
* @return the vertical white space before the paragraph
*/
public double getSpaceBefore(){
- CTTextParagraphProperties pr = _p.getPPr();
- if(pr == null || !pr.isSetSpcBef()) return 0; // TODO fetch from master
-
- CTTextSpacing spc = pr.getSpcBef();
- if(spc.isSetSpcPct()) return spc.getSpcPct().getVal()*0.001;
- else if (spc.isSetSpcPts()) return -spc.getSpcPts().getVal()*0.01;
- else return 0;
+ ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetSpcBef()){
+ CTTextSpacing spc = props.getSpcBef();
+
+ if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );
+ else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue() == null ? 0 : fetcher.getValue();
}
/**
@@ -300,13 +429,20 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
* @return the vertical white space after the paragraph
*/
public double getSpaceAfter(){
- CTTextParagraphProperties pr = _p.getPPr();
- if(pr == null || !pr.isSetSpcAft()) return 0; // TODO fetch from master
-
- CTTextSpacing spc = pr.getSpcAft();
- if(spc.isSetSpcPct()) return spc.getSpcPct().getVal()*0.001;
- else if (spc.isSetSpcPts()) return -spc.getSpcPts().getVal()*0.01;
- else return 0;
+ ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetSpcAft()){
+ CTTextSpacing spc = props.getSpcAft();
+
+ if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );
+ else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue() == null ? 0 : fetcher.getValue();
}
/**
@@ -334,8 +470,256 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
}
+ /**
+ * Returns whether this paragraph has bullets
+ */
+ public boolean isBullet() {
+ ParagraphPropertyFetcher<Boolean> fetcher = new ParagraphPropertyFetcher<Boolean>(getLevel()){
+ public boolean fetch(CTTextParagraphProperties props){
+ if(props.isSetBuNone()) {
+ setValue(false);
+ return true;
+ }
+ if(props.isSetBuFont()){
+ setValue(true);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchParagraphProperty(fetcher);
+ return fetcher.getValue() == null ? false : fetcher.getValue();
+ }
+
@Override
public String toString(){
return "[" + getClass() + "]" + getText();
}
+
+ public List<TextFragment> getTextLines(){
+ return _lines;
+ }
+
+ public double draw(Graphics2D graphics, double x, double y){
+ double marginLeft = _shape.getMarginLeft();
+ double marginRight = _shape.getMarginRight();
+ Rectangle2D anchor = _shape.getAnchor();
+ double penY = y;
+
+ double textOffset = getLeftMargin();
+ for(TextFragment line : _lines){
+ double penX = x;
+ switch (getTextAlign()) {
+ case CENTER:
+ penX += textOffset + (anchor.getWidth() - textOffset - line.getWidth() - marginLeft - marginRight) / 2;
+ break;
+ case RIGHT:
+ penX += (anchor.getWidth() - line.getWidth() - marginLeft - marginRight);
+ break;
+ default:
+ penX = x + textOffset;
+ break;
+ }
+
+ if(_bullet != null){
+ _bullet.draw(graphics, penX + getIndent(), penY);
+ }
+ line.draw(graphics, penX, penY);
+
+ //The vertical line spacing
+ double spacing = getLineSpacing();
+ if(spacing > 0) {
+ // If linespacing >= 0, then linespacing is a percentage of normal line height.
+ penY += spacing*0.01*line.getHeight();
+ } else {
+ // positive value means absolute spacing in points
+ penY += -spacing;
+ }
+ }
+ return penY - y;
+ }
+
+ static class TextFragment {
+ private TextLayout _layout;
+ private AttributedString _str;
+
+ TextFragment(TextLayout layout, AttributedString str){
+ _layout = layout;
+ _str = str;
+ }
+
+ void draw(Graphics2D graphics, double x, double y){
+ double yBaseline = y + _layout.getAscent();
+
+ graphics.drawString(_str.getIterator(), (float)x, (float)yBaseline );
+
+ }
+
+ public float getHeight(){
+ return _layout.getAscent() + _layout.getDescent() + _layout.getLeading();
+ }
+ public float getWidth(){
+ return _layout.getAdvance();
+ }
+
+ }
+
+ public AttributedString getAttributedString(){
+ String text = getText();
+
+ AttributedString string = new AttributedString(text);
+
+ int startIndex = 0;
+ for (XSLFTextRun run : _runs){
+ int length = run.getText().length();
+ if(length == 0) {
+ // skip empty runs
+ continue;
+ }
+ int endIndex = startIndex + length;
+
+ string.addAttribute(TextAttribute.FOREGROUND, run.getFontColor(), startIndex, endIndex);
+ string.addAttribute(TextAttribute.FAMILY, run.getFontFamily(), startIndex, endIndex);
+ string.addAttribute(TextAttribute.SIZE, run.getFontSize(), startIndex, endIndex);
+ if(run.isBold()) {
+ string.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIndex, endIndex);
+ }
+ if(run.isItalic()) {
+ string.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, startIndex, endIndex);
+ }
+ if(run.isUnderline()) {
+ string.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, startIndex, endIndex);
+ }
+ if(run.isStrikethrough()) {
+ string.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, startIndex, endIndex);
+ }
+
+ startIndex = endIndex;
+ }
+
+ return string;
+ }
+
+ void breakText(Graphics2D graphics){
+ _lines = new ArrayList<TextFragment>();
+
+ AttributedString at = getAttributedString();
+ AttributedCharacterIterator it = at.getIterator();
+ if(it.getBeginIndex() == it.getEndIndex()) {
+ return;
+ }
+ LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());
+ for (;;) {
+ int startIndex = measurer.getPosition();
+ double wrappingWidth = getWrappingWidth() + 1; // add a pixel to compensate rounding errors
+ TextLayout layout = measurer.nextLayout((float)wrappingWidth, it.getEndIndex(), true);
+ if (layout == null) {
+ // layout can be null if the entire word at the current position
+ // does not fit within the wrapping width. Try with requireNextWord=false.
+ layout = measurer.nextLayout((float)wrappingWidth, it.getEndIndex(), false);
+ }
+
+ int endIndex = measurer.getPosition();
+
+ if(getTextAlign() == TextAlign.JUSTIFY) {
+ layout = layout.getJustifiedLayout((float)wrappingWidth);
+ }
+
+ AttributedString str = new AttributedString(it, startIndex, endIndex);
+ TextFragment line = new TextFragment(layout, str);
+ _lines.add(line);
+
+ if(endIndex == it.getEndIndex()) break;
+ }
+
+ if(isBullet()) {
+ String buCharacter = getBulletCharacter();
+ String buFont = getBulletFont();
+ if(buCharacter != null && buFont != null && _lines.size() > 0) {
+ AttributedString str = new AttributedString(buCharacter);
+
+ TextFragment firstLine = _lines.get(0);
+ AttributedCharacterIterator bit = firstLine._str.getIterator();
+
+ Color buColor = getBulletFontColor();
+ str.addAttribute(TextAttribute.FOREGROUND, buColor == null ?
+ bit.getAttribute(TextAttribute.FOREGROUND) : buColor);
+ str.addAttribute(TextAttribute.FAMILY, buFont);
+
+ double fontSize = (Double)bit.getAttribute(TextAttribute.SIZE);
+ double buSz = getBulletFontSize();
+ if(buSz > 0) fontSize *= buSz* 0.01;
+ else fontSize = -buSz;
+
+ str.addAttribute(TextAttribute.SIZE, fontSize);
+
+ TextLayout layout = new TextLayout(str.getIterator(), graphics.getFontRenderContext());
+ _bullet = new TextFragment(layout, str);
+ }
+ }
+
+ }
+
+ double getWrappingWidth(){
+ double width;
+ if(!_shape.getWordWrap()) {
+ width = _shape.getSheet().getSlideShow().getPageSize().getWidth();
+ } else {
+ width = _shape.getAnchor().getWidth() -
+ _shape.getMarginLeft() - _shape.getMarginRight() - getLeftMargin();
+ }
+ return width;
+ }
+
+ CTTextParagraphProperties getDefaultStyle(){
+ CTPlaceholder ph = _shape.getCTPlaceholder();
+ String defaultStyleSelector;
+ if(ph == null) defaultStyleSelector = "otherStyle";
+ else {
+ switch(ph.getType().intValue()){
+ case STPlaceholderType.INT_TITLE:
+ case STPlaceholderType.INT_CTR_TITLE:
+ defaultStyleSelector = "titleStyle";
+ break;
+ case STPlaceholderType.INT_FTR:
+ case STPlaceholderType.INT_SLD_NUM:
+ case STPlaceholderType.INT_DT:
+ defaultStyleSelector = "otherStyle";
+ break;
+ default:
+ defaultStyleSelector = "bodyStyle";
+ break;
+ }
+ }
+
+ int level = getLevel();
+ XmlObject[] o = _shape.getSheet().getSlideMaster().getXmlObject().selectPath(
+ "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " +
+ "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " +
+ ".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr");
+ if(o.length == 1){
+ return (CTTextParagraphProperties)o[0];
+ }
+ throw new IllegalArgumentException("Failed to fetch default style for " +
+ defaultStyleSelector + " and level=" + level);
+ }
+
+
+ private boolean fetchParagraphProperty(ParagraphPropertyFetcher visitor){
+ boolean ok = false;
+
+ if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());
+
+ if(!ok) {
+ XSLFTextShape shape = getParentShape();
+ ok = shape.fetchShapeProperty(visitor);
+ if(!ok) {
+ CTTextParagraphProperties defaultProps = getDefaultStyle();
+ if(defaultProps != null) ok = visitor.fetch(defaultProps);
+ }
+ }
+
+ return ok;
+ }
+
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
index c62775e086..558dbdd450 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
@@ -17,6 +17,8 @@
package org.apache.poi.xslf.usermodel;
import org.apache.poi.util.Beta;
+import org.apache.poi.xslf.model.CharacterPropertyFetcher;
+import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
@@ -24,6 +26,9 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
import java.awt.*;
@@ -66,6 +71,23 @@ public class XSLFTextRun {
clr.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});
}
+ public Color getFontColor(){
+ final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
+
+ CharacterPropertyFetcher<Color> fetcher = new CharacterPropertyFetcher<Color>(_p.getLevel()){
+ public boolean fetch(CTTextCharacterProperties props){
+ CTSolidColorFillProperties solidFill = props.getSolidFill();
+ if(solidFill != null){
+ setValue(theme.getSolidFillColor(solidFill));
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchCharacterProperty(fetcher);
+ return fetcher.getValue();
+ }
+
/**
*
* @param fontSize font size in points.
@@ -84,9 +106,17 @@ public class XSLFTextRun {
* @return font size in points or -1 if font size is not set.
*/
public double getFontSize(){
- if(!_r.isSetRPr() || !_r.getRPr().isSetSz()) return -1;
-
- return _r.getRPr().getSz()*0.01;
+ CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getLevel()){
+ public boolean fetch(CTTextCharacterProperties props){
+ if(props.isSetSz()){
+ setValue(props.getSz()*0.01);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchCharacterProperty(fetcher);
+ return fetcher.getValue() == null ? -1 : fetcher.getValue();
}
/**
@@ -120,12 +150,30 @@ public class XSLFTextRun {
}
/**
- * @return font family or null if niot set
+ * @return font family or null if not set
*/
public String getFontFamily(){
- if(!_r.isSetRPr() || !_r.getRPr().isSetLatin()) return null;
+ final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
+
+ CharacterPropertyFetcher<String> visitor = new CharacterPropertyFetcher<String>(_p.getLevel()){
+ public boolean fetch(CTTextCharacterProperties props){
+ CTTextFont font = props.getLatin();
+ if(font != null){
+ String typeface = font.getTypeface();
+ if("+mj-lt".equals(typeface)) {
+ typeface = theme.getMajorFont();
+ } else if ("+mn-lt".equals(typeface)){
+ typeface = theme.getMinorFont();
+ }
+ setValue(typeface);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchCharacterProperty(visitor);
- return _r.getRPr().getLatin().getTypeface();
+ return visitor.getValue();
}
/**
@@ -140,10 +188,18 @@ public class XSLFTextRun {
/**
* @return whether a run of text will be formatted as strikethrough text. Default is false.
*/
- public boolean isStrikethrough(){
- if(!_r.isSetRPr()) return false;
-
- return _r.getRPr().getStrike() == STTextStrikeType.SNG_STRIKE;
+ public boolean isStrikethrough() {
+ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getLevel()){
+ public boolean fetch(CTTextCharacterProperties props){
+ if(props.isSetStrike()){
+ setValue(props.getStrike() != STTextStrikeType.NO_STRIKE);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchCharacterProperty(fetcher);
+ return fetcher.getValue() == null ? false : fetcher.getValue();
}
/**
@@ -159,9 +215,17 @@ public class XSLFTextRun {
* @return whether this run of text is formatted as bold text
*/
public boolean isBold(){
- if(!_r.isSetRPr()) return false;
-
- return _r.getRPr().getB();
+ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getLevel()){
+ public boolean fetch(CTTextCharacterProperties props){
+ if(props.isSetB()){
+ setValue(props.getB());
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchCharacterProperty(fetcher);
+ return fetcher.getValue() == null ? false : fetcher.getValue();
}
/**
@@ -175,9 +239,17 @@ public class XSLFTextRun {
* @return whether this run of text is formatted as italic text
*/
public boolean isItalic(){
- if(!_r.isSetRPr()) return false;
-
- return _r.getRPr().getI();
+ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getLevel()){
+ public boolean fetch(CTTextCharacterProperties props){
+ if(props.isSetI()){
+ setValue(props.getI());
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchCharacterProperty(fetcher);
+ return fetcher.getValue() == null ? false : fetcher.getValue();
}
/**
@@ -191,9 +263,17 @@ public class XSLFTextRun {
* @return whether this run of text is formatted as underlined text
*/
public boolean isUnderline(){
- if(!_r.isSetRPr() || !_r.getRPr().isSetU()) return false;
-
- return _r.getRPr().getU() != STTextUnderlineType.NONE;
+ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getLevel()){
+ public boolean fetch(CTTextCharacterProperties props){
+ if(props.isSetU()){
+ setValue(props.getU() != STTextUnderlineType.NONE);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchCharacterProperty(fetcher);
+ return fetcher.getValue() == null ? false : fetcher.getValue();
}
protected CTTextCharacterProperties getRpR(){
@@ -216,4 +296,22 @@ public class XSLFTextRun {
return new XSLFHyperlink(_r.getRPr().getHlinkClick(), this);
}
+
+ private boolean fetchCharacterProperty(CharacterPropertyFetcher fetcher){
+ boolean ok = false;
+
+ if(_r.isSetRPr()) ok = fetcher.fetch(_r.getRPr());
+
+ if(!ok) {
+ XSLFTextShape shape = _p.getParentShape();
+ ok = shape.fetchShapeProperty(fetcher);
+ if(!ok) {
+ CTTextParagraphProperties defaultProps = _p.getDefaultStyle();
+ if(defaultProps != null) ok = fetcher.fetch(defaultProps);
+ }
+ }
+
+ return ok;
+ }
+
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
index 5bb48b600b..3d303002e0 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
@@ -21,18 +21,20 @@ package org.apache.poi.xslf.usermodel;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Units;
+import org.apache.poi.xslf.model.PropertyFetcher;
+import org.apache.poi.xslf.model.TextBodyPropertyFetcher;
import org.apache.xmlbeans.XmlObject;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
@@ -79,43 +81,6 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
return paragraph;
}
- /**
- * Specifies a solid color fill. The shape is filled entirely with the specified color.
- *
- * @param color the solid color fill.
- * The value of <code>null</code> unsets the solidFIll attribute from the underlying xml
- */
- public void setFillColor(Color color) {
- CTShapeProperties spPr = getSpPr();
- if (color == null) {
- if(spPr.isSetSolidFill()) spPr.unsetSolidFill();
- }
- else {
- CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill();
-
- CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
- rgb.setVal(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()});
-
- fill.setSrgbClr(rgb);
- }
- }
-
- /**
- *
- * @return solid fill color of null if not set
- */
- public Color getFillColor(){
- CTShapeProperties spPr = getSpPr();
- if(!spPr.isSetSolidFill() ) return null;
-
- CTSolidColorFillProperties fill = spPr.getSolidFill();
- if(!fill.isSetSrgbClr()) {
- // TODO for now return null for all colors except explicit RGB
- return null;
- }
- byte[] val = fill.getSrgbClr().getVal();
- return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
- }
/**
* Sets the type of vertical alignment for the text.
@@ -140,14 +105,18 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
* @return the type of alignment
*/
public VerticalAlignment getVerticalAlignment(){
- CTTextBodyProperties bodyPr = getTextBodyPr();
- if (bodyPr != null) {
- STTextAnchoringType.Enum val = bodyPr.getAnchor();
- if(val != null){
- return VerticalAlignment.values()[val.intValue() - 1];
+ PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){
+ public boolean fetch(CTTextBodyProperties props){
+ if(props.isSetAnchor()){
+ int val = props.getAnchor().intValue();
+ setValue(VerticalAlignment.values()[val - 1]);
+ return true;
+ }
+ return false;
}
- }
- return VerticalAlignment.TOP;
+ };
+ fetchShapeProperty(fetcher);
+ return fetcher.getValue() == null ? VerticalAlignment.TOP : fetcher.getValue();
}
/**
@@ -185,11 +154,18 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
* @return the bottom margin or -1 if not set
*/
public double getMarginBottom(){
- CTTextBodyProperties bodyPr = getTextBodyPr();
- if (bodyPr != null) {
- return bodyPr.isSetBIns() ? Units.toPoints(bodyPr.getBIns()) : -1;
- }
- return -1;
+ PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
+ public boolean fetch(CTTextBodyProperties props){
+ if(props.isSetBIns()){
+ double val = Units.toPoints(props.getBIns());
+ setValue(val);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+ return fetcher.getValue() == null ? 0 : fetcher.getValue();
}
/**
@@ -200,11 +176,18 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
* @return the left margin
*/
public double getMarginLeft(){
- CTTextBodyProperties bodyPr = getTextBodyPr();
- if (bodyPr != null) {
- return bodyPr.isSetLIns() ? Units.toPoints(bodyPr.getLIns()) : -1;
- }
- return -1;
+ PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
+ public boolean fetch(CTTextBodyProperties props){
+ if(props.isSetLIns()){
+ double val = Units.toPoints(props.getLIns());
+ setValue(val);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+ return fetcher.getValue() == null ? 0 : fetcher.getValue();
}
/**
@@ -215,11 +198,18 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
* @return the right margin
*/
public double getMarginRight(){
- CTTextBodyProperties bodyPr = getTextBodyPr();
- if (bodyPr != null) {
- return bodyPr.isSetRIns() ? Units.toPoints(bodyPr.getRIns()) : -1;
- }
- return -1;
+ PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
+ public boolean fetch(CTTextBodyProperties props){
+ if(props.isSetRIns()){
+ double val = Units.toPoints(props.getRIns());
+ setValue(val);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+ return fetcher.getValue() == null ? 0 : fetcher.getValue();
}
/**
@@ -229,11 +219,18 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
* @return the top margin
*/
public double getMarginTop(){
- CTTextBodyProperties bodyPr = getTextBodyPr();
- if (bodyPr != null) {
- return bodyPr.isSetTIns() ? Units.toPoints(bodyPr.getTIns()) : -1;
- }
- return -1;
+ PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
+ public boolean fetch(CTTextBodyProperties props){
+ if(props.isSetTIns()){
+ double val = Units.toPoints(props.getTIns());
+ setValue(val);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+ return fetcher.getValue() == null ? 0 : fetcher.getValue();
}
/**
@@ -300,11 +297,17 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
* @return the value indicating word wrap
*/
public boolean getWordWrap(){
- CTTextBodyProperties bodyPr = getTextBodyPr();
- if (bodyPr != null) {
- return bodyPr.getWrap() == STTextWrappingType.SQUARE;
- }
- return false;
+ PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
+ public boolean fetch(CTTextBodyProperties props){
+ if(props.isSetWrap()){
+ setValue(props.getWrap() == STTextWrappingType.SQUARE);
+ return true;
+ }
+ return false;
+ }
+ };
+ fetchShapeProperty(fetcher);
+ return fetcher.getValue() == null ? true : fetcher.getValue();
}
/**
@@ -362,4 +365,132 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
protected abstract CTTextBody getTextBody(boolean create);
+
+
+ public Placeholder getTextType(){
+ CTPlaceholder ph;
+ XmlObject[] obj = getXmlObject().selectPath(
+ "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:nvPr/p:ph");
+ if(obj.length == 1){
+ ph = (CTPlaceholder)obj[0];
+ int val = ph.getType().intValue();
+ return Placeholder.values()[val - 1];
+ }
+ else {
+ return null;
+ }
+ }
+
+ @Override
+ public void draw(Graphics2D graphics){
+ java.awt.Shape outline = getOutline();
+
+ // shadow
+ XSLFShadow shadow = getShadow();
+ if(shadow != null) shadow.draw(graphics);
+
+ //fill
+ Color fillColor = getFillColor();
+ if (fillColor != null) {
+ graphics.setColor(fillColor);
+ applyFill(graphics);
+ graphics.fill(outline);
+ }
+
+ //border
+ Color lineColor = getLineColor();
+ if (lineColor != null){
+ graphics.setColor(lineColor);
+ applyStroke(graphics);
+ graphics.draw(outline);
+ }
+
+ // text
+ if(getText().length() > 0) drawText(graphics);
+ }
+
+ /**
+ * Compute the cumulative height occupied by the text
+ */
+ private double getTextHeight(){
+ // dry-run in a 1x1 image and return the vertical advance
+ BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
+ return drawParagraphs(img.createGraphics(), 0, 0);
+ }
+
+ void breakText(Graphics2D graphics){
+ for(XSLFTextParagraph p : _paragraphs) p.breakText(graphics);
+ }
+
+ public void drawText(Graphics2D graphics) {
+ breakText(graphics);
+
+ Rectangle2D anchor = getAnchor();
+ double x = anchor.getX() + getMarginLeft();
+ double y = anchor.getY();
+
+ // first dry-run to calculate the total height of the text
+ double textHeight = getTextHeight();
+
+ switch (getVerticalAlignment()){
+ case TOP:
+ y += getMarginTop();
+ break;
+ case BOTTOM:
+ y += anchor.getHeight() - textHeight - getMarginBottom();
+ break;
+ default:
+ case MIDDLE:
+ double delta = anchor.getHeight() - textHeight -
+ getMarginTop() - getMarginBottom();
+ y += getMarginTop() + delta/2;
+ break;
+ }
+
+ drawParagraphs(graphics, x, y);
+
+ }
+
+
+ /**
+ * pain the paragraphs starting from top left (x,y)
+ *
+ * @return the vertical advance, i.e. the cumulative space occupied by the text
+ */
+ private double drawParagraphs(Graphics2D graphics, double x, double y) {
+ double y0 = y;
+ for(int i = 0; i < _paragraphs.size(); i++){
+ XSLFTextParagraph p = _paragraphs.get(i);
+ java.util.List<XSLFTextParagraph.TextFragment> lines = p.getTextLines();
+
+ if(i > 0 && lines.size() > 0) {
+ // the amount of vertical white space before the paragraph
+ double spaceBefore = p.getSpaceBefore();
+ if(spaceBefore > 0) {
+ // positive value means percentage spacing of the height of the first line, e.g.
+ // the higher the first line, the bigger the space before the paragraph
+ y += spaceBefore*0.01*lines.get(0).getHeight();
+ } else {
+ // negative value means the absolute spacing in points
+ y += -spaceBefore;
+ }
+ }
+
+ y += p.draw(graphics, x, y);
+
+ if(i < _paragraphs.size() - 1) {
+ double spaceAfter = p.getSpaceAfter();
+ if(spaceAfter > 0) {
+ // positive value means percentage spacing of the height of the last line, e.g.
+ // the higher the last line, the bigger the space after the paragraph
+ y += spaceAfter*0.01*lines.get(lines.size() - 1).getHeight();
+ } else {
+ // negative value means the absolute spacing in points
+ y += -spaceAfter;
+ }
+ }
+ }
+ return y - y0;
+ }
+
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java
index d107b3a27f..a648dbdf7a 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java
@@ -22,15 +22,21 @@ import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal;
import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideLayout;
-import org.openxmlformats.schemas.presentationml.x2006.main.SldLayoutDocument;
-import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTColorScheme;
import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument;
import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeStyleSheet;
-import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor;
import javax.xml.namespace.QName;
+
+import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
@@ -39,7 +45,8 @@ import java.util.HashMap;
@Beta
public class XSLFTheme extends POIXMLDocumentPart {
private CTOfficeStyleSheet _theme;
-
+ private Map<String, XSLFColor> _schemeColors;
+
XSLFTheme() {
super();
_theme = CTOfficeStyleSheet.Factory.newInstance();
@@ -50,8 +57,24 @@ public class XSLFTheme extends POIXMLDocumentPart {
ThemeDocument doc =
ThemeDocument.Factory.parse(getPackagePart().getInputStream());
_theme = doc.getTheme();
+ initialize();
}
+ private void initialize(){
+ CTBaseStyles elems = _theme.getThemeElements();
+ CTColorScheme scheme = elems.getClrScheme();
+ // The color scheme is responsible for defining a list of twelve colors.
+ _schemeColors = new HashMap<String, XSLFColor>(12);
+ for(XmlObject o : scheme.selectPath("*")){
+ CTColor c = (CTColor)o;
+ String name = c.getDomNode().getLocalName();
+ _schemeColors.put(name, new XSLFColor(c));
+ }
+ _schemeColors.put("bg1", _schemeColors.get("lt1"));
+ _schemeColors.put("bg2", _schemeColors.get("lt2"));
+ _schemeColors.put("tx1", _schemeColors.get("dk1"));
+ _schemeColors.put("tx2", _schemeColors.get("dk2"));
+ }
public String getName(){
return _theme.getName();
@@ -62,6 +85,146 @@ public class XSLFTheme extends POIXMLDocumentPart {
}
/**
+ * Get a color from the theme's color scheme by name
+ *
+ * @return a theme color or <code>null</code> if not found
+ */
+ public XSLFColor getColor(String name){
+ return _schemeColors.get(name);
+ }
+
+ Color getSchemeColor(CTSchemeColor schemeColor){
+ String colorRef = schemeColor.getVal().toString();
+ int alpha = 0xFF;
+ if(schemeColor.sizeOfAlphaArray() > 0){
+ int aval = schemeColor.getAlphaArray(0).getVal();
+ alpha = Math.round(255 * aval / 100000f);
+ }
+ Color themeColor = _schemeColors.get(colorRef).getColor(alpha);
+
+ int lumMod = 100, lumOff = 0;
+ if (schemeColor.sizeOfLumModArray() > 0) {
+ lumMod = schemeColor.getLumModArray(0).getVal() / 1000;
+ }
+ if (schemeColor.sizeOfLumOffArray() > 0) {
+ lumOff = schemeColor.getLumOffArray(0).getVal() / 1000;
+ }
+ if(schemeColor.sizeOfShadeArray() > 0) {
+ lumMod = schemeColor.getShadeArray(0).getVal() / 1000;
+ }
+ Color color = modulateLuminanace(themeColor, lumMod, lumOff);
+
+ if(schemeColor.sizeOfTintArray() > 0) {
+ float tint = schemeColor.getTintArray(0).getVal() / 100000f;
+ int red = Math.round(tint * themeColor.getRed() + (1 - tint) * 255);
+ int green = Math.round(tint * themeColor.getGreen() + (1 - tint) * 255);
+ int blue = Math.round(tint * themeColor.getBlue() + (1 - tint) * 255);
+ color = new Color(red, green, blue);
+ }
+
+ return color;
+ }
+
+ /**
+ * TODO get rid of code duplication. Re-write to use xpath instead of beans
+ */
+ Color getPresetColor(CTPresetColor presetColor){
+ String colorName = presetColor.getVal().toString();
+ Color color;
+ try {
+ color = (Color)Color.class.getField(colorName).get(null);
+ } catch (Exception e){
+ color = Color.black;
+ }
+ if(presetColor.sizeOfAlphaArray() > 0){
+ int aval = presetColor.getAlphaArray(0).getVal();
+ int alpha = Math.round(255 * aval / 100000f);
+ color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
+ }
+
+ int lumMod = 100, lumOff = 0;
+ if (presetColor.sizeOfLumModArray() > 0) {
+ lumMod = presetColor.getLumModArray(0).getVal() / 1000;
+ }
+ if (presetColor.sizeOfLumOffArray() > 0) {
+ lumOff = presetColor.getLumOffArray(0).getVal() / 1000;
+ }
+ if(presetColor.sizeOfShadeArray() > 0) {
+ lumMod = presetColor.getShadeArray(0).getVal() / 1000;
+ }
+ color = modulateLuminanace(color, lumMod, lumOff);
+
+ if(presetColor.sizeOfTintArray() > 0) {
+ float tint = presetColor.getTintArray(0).getVal() / 100000f;
+ int red = Math.round(tint * color.getRed() + (1 - tint) * 255);
+ int green = Math.round(tint * color.getGreen() + (1 - tint) * 255);
+ int blue = Math.round(tint * color.getBlue() + (1 - tint) * 255);
+ color = new Color(red, green, blue);
+ }
+
+ return color;
+ }
+
+ public Color brighter(Color color, double tint) {
+ int r = color.getRed();
+ int g = color.getGreen();
+ int b = color.getBlue();
+
+ /* From 2D group:
+ * 1. black.brighter() should return grey
+ * 2. applying brighter to blue will always return blue, brighter
+ * 3. non pure color (non zero rgb) will eventually return white
+ */
+ int i = (int)(1.0/(1.0-tint));
+ if ( r == 0 && g == 0 && b == 0) {
+ return new Color(i, i, i);
+ }
+ if ( r > 0 && r < i ) r = i;
+ if ( g > 0 && g < i ) g = i;
+ if ( b > 0 && b < i ) b = i;
+
+ return new Color(Math.min((int)(r/tint), 255),
+ Math.min((int)(g/tint), 255),
+ Math.min((int)(b/tint), 255));
+ }
+
+ Color getSrgbColor(CTSRgbColor srgb){
+ byte[] val = srgb.getVal();
+ int alpha = 0xFF;
+ if(srgb.sizeOfAlphaArray() > 0){
+ int aval = srgb.getAlphaArray(0).getVal();
+ alpha = Math.round(255 * aval / 100000f);
+ }
+ return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2], alpha);
+ }
+
+ Color getSolidFillColor(CTSolidColorFillProperties solidFill){
+ Color color;
+ if (solidFill.isSetSrgbClr()) {
+ color = getSrgbColor(solidFill.getSrgbClr());
+ } else if (solidFill.isSetSchemeClr()) {
+ color = getSchemeColor(solidFill.getSchemeClr());
+ } else {
+ // TODO support other types
+ color = Color.black;
+ }
+ return color;
+ }
+
+ Color getColor(CTColor solidFill){
+ Color color;
+ if (solidFill.isSetSrgbClr()) {
+ color = getSrgbColor(solidFill.getSrgbClr());
+ } else if (solidFill.isSetSchemeClr()) {
+ color = getSchemeColor(solidFill.getSchemeClr());
+ } else {
+ // TODO support other types
+ color = Color.black;
+ }
+ return color;
+ }
+
+ /**
* While developing only!
*/
@Internal
@@ -84,4 +247,31 @@ public class XSLFTheme extends POIXMLDocumentPart {
out.close();
}
-} \ No newline at end of file
+ public static Color modulateLuminanace(Color c, int lumMod, int lumOff) {
+ Color color;
+ if (lumOff > 0) {
+ color = new Color(
+ (int) (Math.round((255 - c.getRed()) * (100.0 - lumMod) / 100.0 + c.getRed())),
+ (int) (Math.round((255 - c.getGreen()) * lumOff / 100.0 + c.getGreen())),
+ (int) (Math.round((255 - c.getBlue()) * lumOff / 100.0 + c.getBlue())),
+ c.getAlpha()
+ );
+ } else {
+ color = new Color(
+ (int) (Math.round(c.getRed() * lumMod / 100.0)),
+ (int) (Math.round(c.getGreen() * lumMod / 100.0)),
+ (int) (Math.round(c.getBlue() * lumMod / 100.0)),
+ c.getAlpha()
+ );
+ }
+ return color;
+ }
+
+ public String getMajorFont(){
+ return _theme.getThemeElements().getFontScheme().getMajorFont().getLatin().getTypeface();
+ }
+
+ public String getMinorFont(){
+ return _theme.getThemeElements().getFontScheme().getMinorFont().getLatin().getTypeface();
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java b/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java
new file mode 100644
index 0000000000..f4e6955e6a
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java
@@ -0,0 +1,101 @@
+/*
+ * ====================================================================
+ * 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.util;
+
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+
+import javax.imageio.ImageIO;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileOutputStream;
+
+/**
+ * Date: 10/11/11
+ *
+ * @author Yegor Kozlov
+ */
+public class PPTX2PNG {
+ public static void main(String[] args) throws Exception {
+ if (args.length == 0) {
+ System.out.println("Usage: PPTX2PNG [options] <pptx file>");
+ return;
+ }
+
+ int slidenum = -1;
+ float scale = 1;
+ String file = null;
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].startsWith("-")) {
+ if ("-scale".equals(args[i])) {
+ scale = Float.parseFloat(args[++i]);
+ } else if ("-slide".equals(args[i])) {
+ slidenum = Integer.parseInt(args[++i]);
+ }
+ } else {
+ file = args[i];
+ }
+ }
+
+ System.out.println("Processing " + file);
+ XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file));
+
+ Dimension pgsize = ppt.getPageSize();
+ int width = (int) (pgsize.width * scale);
+ int height = (int) (pgsize.height * scale);
+
+ XSLFSlide[] slide = ppt.getSlides();
+ for (int i = 0; i < slide.length; i++) {
+ if (slidenum != -1 && slidenum != (i + 1)) continue;
+
+ String title = slide[i].getTitle();
+ System.out.println("Rendering slide " + (i + 1) + (title == null ? "" : ": " + title));
+
+ BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+ Graphics2D graphics = img.createGraphics();
+
+ graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+ graphics.setPaint(Color.white);
+ graphics.fill(new Rectangle2D.Float(0, 0, width, height));
+
+ graphics.scale((double) width / pgsize.width, (double) height / pgsize.height);
+
+ slide[i].draw(graphics);
+
+ String fname = file.replaceAll("\\.pptx", "-" + (i + 1) + ".png");
+ FileOutputStream out = new FileOutputStream(fname);
+ ImageIO.write(img, "png", out);
+ out.close();
+ }
+ System.out.println("Done");
+ }
+}