mirror of https://github.com/apache/poi.git
more progress with xlsf: support for gradient and texture fills, backgrounds, improved drawing of preset shapes and many more updates ...
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1198658 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d6093ba1e3
commit
de14b40a97
|
@ -108,6 +108,7 @@ under the License.
|
|||
|
||||
<!-- OOXML support: -->
|
||||
<property name="ooxml.src" location="src/ooxml/java"/>
|
||||
<property name="ooxml.resource1.dir" value="src/resources/ooxml"/>
|
||||
<property name="ooxml.src.test" location="src/ooxml/testcases"/>
|
||||
<property name="ooxml.reports.test" location="build/ooxml-test-results"/>
|
||||
<property name="ooxml.output.dir" location="build/ooxml-classes"/>
|
||||
|
@ -553,6 +554,9 @@ under the License.
|
|||
<pathelement path="${main.output.test.dir}"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
<copy todir="${ooxml.output.dir}">
|
||||
<fileset dir="${ooxml.resource1.dir}"/>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="compile-excelant" depends="compile-main,compile-ooxml">
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.tutorial;
|
||||
|
||||
import org.apache.poi.xslf.usermodel.XMLSlideShow;
|
||||
import org.apache.poi.xslf.usermodel.XSLFShape;
|
||||
import org.apache.poi.xslf.usermodel.XSLFSlide;
|
||||
import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
|
||||
import org.apache.poi.xslf.usermodel.XSLFTextRun;
|
||||
import org.apache.poi.xslf.usermodel.XSLFTextShape;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/**
|
||||
* Reading a .pptx presentation and printing basic shape properties
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Step1 {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if(args.length == 0) {
|
||||
System.out.println("Input file is required");
|
||||
return;
|
||||
}
|
||||
|
||||
XMLSlideShow ppt = new XMLSlideShow(new FileInputStream(args[0]));
|
||||
|
||||
for(XSLFSlide slide : ppt.getSlides()){
|
||||
System.out.println("Title: " + slide.getTitle());
|
||||
|
||||
for(XSLFShape shape : slide.getShapes()){
|
||||
if(shape instanceof XSLFTextShape) {
|
||||
XSLFTextShape tsh = (XSLFTextShape)shape;
|
||||
for(XSLFTextParagraph p : tsh){
|
||||
System.out.println("Paragraph level: " + p.getLevel());
|
||||
for(XSLFTextRun r : p){
|
||||
System.out.println(r.getText());
|
||||
System.out.println(" bold: " + r.isBold());
|
||||
System.out.println(" italic: " + r.isItalic());
|
||||
System.out.println(" underline: " + r.isUnderline());
|
||||
System.out.println(" font.family: " + r.getFontFamily());
|
||||
System.out.println(" font.size: " + r.getFontSize());
|
||||
System.out.println(" font.color: " + r.getFontColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.tutorial;
|
||||
|
||||
import org.apache.poi.xslf.usermodel.SlideLayout;
|
||||
import org.apache.poi.xslf.usermodel.XMLSlideShow;
|
||||
import org.apache.poi.xslf.usermodel.XSLFSlide;
|
||||
import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
|
||||
import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
|
||||
import org.apache.poi.xslf.usermodel.XSLFTextShape;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
/**
|
||||
* Create slides from pre-defined slide layouts
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Step2 {
|
||||
public static void main(String[] args) throws Exception{
|
||||
XMLSlideShow ppt = new XMLSlideShow();
|
||||
|
||||
|
||||
// first see what slide layouts are available by default
|
||||
System.out.println("Available slide layouts:");
|
||||
for(XSLFSlideMaster master : ppt.getSlideMasters()){
|
||||
for(XSLFSlideLayout layout : master.getSlideLayouts()){
|
||||
System.out.println(layout.getType());
|
||||
}
|
||||
}
|
||||
|
||||
// blank slide
|
||||
XSLFSlide blankSlide = ppt.createSlide();
|
||||
|
||||
XSLFSlideMaster defaultMaster = ppt.getSlideMasters()[0];
|
||||
|
||||
// title slide
|
||||
XSLFSlideLayout titleLayout = defaultMaster.getLayout(SlideLayout.TITLE);
|
||||
XSLFSlide slide1 = ppt.createSlide(titleLayout);
|
||||
XSLFTextShape title1 = slide1.getPlaceholder(0);
|
||||
title1.setText("First Title");
|
||||
|
||||
// title and content
|
||||
XSLFSlideLayout titleBodyLayout = defaultMaster.getLayout(SlideLayout.TITLE_AND_CONTENT);
|
||||
XSLFSlide slide2 = ppt.createSlide(titleBodyLayout);
|
||||
|
||||
XSLFTextShape title2 = slide2.getPlaceholder(0);
|
||||
title2.setText("Second Title");
|
||||
|
||||
XSLFTextShape body2 = slide2.getPlaceholder(1);
|
||||
body2.clearText(); // unset any existing text
|
||||
body2.addNewTextParagraph().addNewTextRun().setText("First paragraph");
|
||||
body2.addNewTextParagraph().addNewTextRun().setText("Second paragraph");
|
||||
body2.addNewTextParagraph().addNewTextRun().setText("Third paragraph");
|
||||
|
||||
|
||||
|
||||
FileOutputStream out = new FileOutputStream("step2.pptx");
|
||||
ppt.write(out);
|
||||
out.close();
|
||||
|
||||
}
|
||||
}
|
|
@ -128,7 +128,7 @@ public class XSLFPowerPointExtractor extends POIXMLTextExtractor {
|
|||
XSLFNotes notes = slide.getNotes();
|
||||
XSLFComments comments = slide.getComments();
|
||||
XSLFSlideLayout layout = slide.getSlideLayout();
|
||||
XSLFSlideMaster master = slide.getMasterSheet();
|
||||
XSLFSlideMaster master = layout.getSlideMaster();
|
||||
|
||||
// TODO Do the slide's name
|
||||
// (Stored in docProps/app.xml)
|
||||
|
|
|
@ -57,15 +57,11 @@ public class ArcToCommand implements PathCommand {
|
|||
double x0 = pt.getX() - rx - rx * Math.cos(Math.toRadians(start));
|
||||
double y0 = pt.getY() - ry - ry * Math.sin(Math.toRadians(start));
|
||||
|
||||
if(start == 180 && extent == 180) {
|
||||
x0 -= rx*2; //YK: TODO revisit the code and get rid of this hack
|
||||
}
|
||||
|
||||
Arc2D arc = new Arc2D.Double(
|
||||
x0,
|
||||
y0,
|
||||
2 * rx, 2 * ry,
|
||||
-start, -extent, // negate angles because DrawingML rotates counter-clockwise
|
||||
-start, -extent,
|
||||
Arc2D.OPEN);
|
||||
path.append(arc, true);
|
||||
}
|
||||
|
|
|
@ -29,17 +29,19 @@ import java.util.Map;
|
|||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Context {
|
||||
Map<String, Double> _ctx = new HashMap<String, Double>();
|
||||
IAdjustableShape _props;
|
||||
|
||||
public Context(CustomGeometry geom, IAdjustableShape props){
|
||||
final Map<String, Double> _ctx = new HashMap<String, Double>();
|
||||
final IAdjustableShape _props;
|
||||
final Rectangle2D _anchor;
|
||||
|
||||
public Context(CustomGeometry geom, Rectangle2D anchor, IAdjustableShape props){
|
||||
_props = props;
|
||||
_anchor = anchor;
|
||||
for(Guide gd : geom.adjusts) evaluate(gd);
|
||||
for(Guide gd : geom.guides) evaluate(gd);
|
||||
}
|
||||
|
||||
public Rectangle2D getShapeAnchor(){
|
||||
return _props.getAnchor();
|
||||
return _anchor;
|
||||
}
|
||||
|
||||
public Guide getAdjustValue(String name){
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.*;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* Definition of a custom geometric shape
|
||||
|
@ -34,8 +35,9 @@ public class CustomGeometry implements Iterable<Path>{
|
|||
List<Guide> adjusts = new ArrayList<Guide>();
|
||||
List<Guide> guides = new ArrayList<Guide>();
|
||||
List<Path> paths = new ArrayList<Path>();
|
||||
Path textBounds;
|
||||
|
||||
public CustomGeometry(CTCustomGeometry2D geom){
|
||||
public CustomGeometry(CTCustomGeometry2D geom) {
|
||||
CTGeomGuideList avLst = geom.getAvLst();
|
||||
if(avLst != null) for(CTGeomGuide gd : avLst.getGdList()){
|
||||
adjusts.add(new AdjustValue(gd));
|
||||
|
@ -50,6 +52,21 @@ public class CustomGeometry implements Iterable<Path>{
|
|||
if(pathLst != null) for(CTPath2D spPath : pathLst.getPathList()){
|
||||
paths.add(new Path(spPath));
|
||||
}
|
||||
|
||||
if(geom.isSetRect()) {
|
||||
CTGeomRect rect = geom.getRect();
|
||||
textBounds = new Path();
|
||||
textBounds.addCommand(
|
||||
new MoveToCommand(rect.getL().toString(), rect.getT().toString()));
|
||||
textBounds.addCommand(
|
||||
new LineToCommand(rect.getR().toString(), rect.getT().toString()));
|
||||
textBounds.addCommand(
|
||||
new LineToCommand(rect.getR().toString(), rect.getB().toString()));
|
||||
textBounds.addCommand(
|
||||
new LineToCommand(rect.getL().toString(), rect.getB().toString()));
|
||||
textBounds.addCommand(
|
||||
new ClosePathCommand());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,4 +75,7 @@ public class CustomGeometry implements Iterable<Path>{
|
|||
return paths.iterator();
|
||||
}
|
||||
|
||||
public Path getTextBounds(){
|
||||
return textBounds;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package org.apache.poi.xslf.model.geom;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* A bridge to the consumer application.
|
||||
|
@ -29,12 +28,6 @@ import java.awt.geom.Rectangle2D;
|
|||
* @author Yegor Kozlov
|
||||
*/
|
||||
public interface IAdjustableShape {
|
||||
/**
|
||||
*
|
||||
* @return bounds of the shape
|
||||
*/
|
||||
Rectangle2D getAnchor();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name name of a adjust value, e.g. adj1
|
||||
|
|
|
@ -36,6 +36,11 @@ public class LineToCommand implements PathCommand {
|
|||
arg2 = pt.getY().toString();
|
||||
}
|
||||
|
||||
LineToCommand(String s1, String s2){
|
||||
arg1 = s1;
|
||||
arg2 = s2;
|
||||
}
|
||||
|
||||
public void execute(GeneralPath path, Context ctx){
|
||||
double x = ctx.getValue(arg1);
|
||||
double y = ctx.getValue(arg2);
|
||||
|
|
|
@ -36,6 +36,11 @@ public class MoveToCommand implements PathCommand {
|
|||
arg2 = pt.getY().toString();
|
||||
}
|
||||
|
||||
MoveToCommand(String s1, String s2){
|
||||
arg1 = s1;
|
||||
arg2 = s2;
|
||||
}
|
||||
|
||||
public void execute(GeneralPath path, Context ctx){
|
||||
double x = ctx.getValue(arg1);
|
||||
double y = ctx.getValue(arg2);
|
||||
|
|
|
@ -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.geom;
|
||||
|
||||
import java.awt.Shape;
|
||||
|
||||
/**
|
||||
* Date: 11/6/11
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class Outline {
|
||||
private Shape shape;
|
||||
private Path path;
|
||||
|
||||
public Outline(Shape shape, Path path){
|
||||
this.shape = shape;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Path getPath(){
|
||||
return path;
|
||||
}
|
||||
|
||||
public Shape getOutline(){
|
||||
return shape;
|
||||
}
|
||||
}
|
|
@ -39,11 +39,26 @@ import java.util.List;
|
|||
public class Path {
|
||||
private final List<PathCommand> commands;
|
||||
boolean _fill, _stroke;
|
||||
long _w, _h;
|
||||
|
||||
public Path(){
|
||||
this(true, true);
|
||||
}
|
||||
|
||||
public Path(boolean fill, boolean stroke){
|
||||
commands = new ArrayList<PathCommand>();
|
||||
_w = -1;
|
||||
_h = -1;
|
||||
_fill = fill;
|
||||
_stroke = stroke;
|
||||
}
|
||||
|
||||
public Path(CTPath2D spPath){
|
||||
_fill = spPath.getFill() != STPathFillMode.NONE;
|
||||
_stroke = spPath.getStroke();
|
||||
|
||||
_w = spPath.isSetW() ? spPath.getW() : -1;
|
||||
_h = spPath.isSetH() ? spPath.getH() : -1;
|
||||
|
||||
commands = new ArrayList<PathCommand>();
|
||||
for(XmlObject ch : spPath.selectPath("*")){
|
||||
if(ch instanceof CTPath2DMoveTo){
|
||||
|
@ -74,6 +89,13 @@ public class Path {
|
|||
}
|
||||
}
|
||||
|
||||
public void addCommand(PathCommand cmd){
|
||||
commands.add(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the internal represenation to java.awt.GeneralPath
|
||||
*/
|
||||
public GeneralPath getPath(Context ctx) {
|
||||
GeneralPath path = new GeneralPath();
|
||||
for(PathCommand cmd : commands)
|
||||
|
@ -88,4 +110,12 @@ public class Path {
|
|||
public boolean isFilled(){
|
||||
return _fill;
|
||||
}
|
||||
|
||||
public long getW(){
|
||||
return _w;
|
||||
}
|
||||
|
||||
public long getH(){
|
||||
return _h;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public enum Placeholder {
|
|||
SLIDE_NUMBER,
|
||||
FOOTER,
|
||||
HEADER,
|
||||
OBJECT,
|
||||
CONTENT,
|
||||
CHART,
|
||||
TABLE,
|
||||
CLIP_ART,
|
||||
|
@ -38,5 +38,4 @@ public enum Placeholder {
|
|||
MEDIA,
|
||||
SLIDE_IMAGE,
|
||||
PICTURE
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,563 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.Internal;
|
||||
import org.apache.poi.util.Units;
|
||||
import org.apache.poi.xslf.model.PropertyFetcher;
|
||||
import org.apache.poi.xslf.model.geom.Context;
|
||||
import org.apache.poi.xslf.model.geom.CustomGeometry;
|
||||
import org.apache.poi.xslf.model.geom.Guide;
|
||||
import org.apache.poi.xslf.model.geom.IAdjustableShape;
|
||||
import org.apache.poi.xslf.model.geom.Outline;
|
||||
import org.apache.poi.xslf.model.geom.Path;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientStop;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTNoFillProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPathShadeProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
|
||||
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.CTStyleMatrixReference;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.TexturePaint;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yegor
|
||||
* Date: Oct 27, 2011
|
||||
* Time: 4:50:08 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
* Encapsulates logic to translate DrawingML objects to Java2D
|
||||
*/
|
||||
@Internal
|
||||
class RenderableShape {
|
||||
public final static Color NO_PAINT = new Color(0xFF, 0xFF, 0xFF, 0);
|
||||
|
||||
private XSLFSimpleShape _shape;
|
||||
|
||||
public RenderableShape(XSLFSimpleShape shape){
|
||||
_shape = shape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert shape fill into java.awt.Paint. The result is either Color or
|
||||
* TexturePaint or GradientPaint or null
|
||||
*
|
||||
* @param graphics the target graphics
|
||||
* @param obj the xml to read. Must contain elements from the EG_ColorChoice group:
|
||||
* <code>
|
||||
* a:scrgbClr RGB Color Model - Percentage Variant
|
||||
* a:srgbClr RGB Color Model - Hex Variant
|
||||
* a:hslClr Hue, Saturation, Luminance Color Model
|
||||
* a:sysClr System Color
|
||||
* a:schemeClr Scheme Color
|
||||
* a:prstClr Preset Color
|
||||
* </code>
|
||||
*
|
||||
* @param phClr context color
|
||||
* @param parentPart the parent package part. Any external references (images, etc.) are resolved relative to it.
|
||||
*
|
||||
* @return the applied Paint or null if none was applied
|
||||
*/
|
||||
public Paint selectPaint(Graphics2D graphics, XmlObject obj, CTSchemeColor phClr, PackagePart parentPart) {
|
||||
XSLFTheme theme = _shape.getSheet().getTheme();
|
||||
Rectangle2D anchor = _shape.getAnchor();
|
||||
|
||||
Paint paint = null;
|
||||
if (obj instanceof CTNoFillProperties) {
|
||||
paint = NO_PAINT;
|
||||
|
||||
}
|
||||
else if (obj instanceof CTSolidColorFillProperties) {
|
||||
CTSolidColorFillProperties solidFill = (CTSolidColorFillProperties) obj;
|
||||
XSLFColor c = new XSLFColor(solidFill, theme, phClr);
|
||||
paint = c.getColor();
|
||||
}
|
||||
else if (obj instanceof CTBlipFillProperties) {
|
||||
CTBlipFillProperties blipFill = (CTBlipFillProperties)obj;
|
||||
paint = createTexturePaint(blipFill, graphics, parentPart);
|
||||
}
|
||||
else if (obj instanceof CTGradientFillProperties) {
|
||||
CTGradientFillProperties gradFill = (CTGradientFillProperties) obj;
|
||||
if (gradFill.isSetLin()) {
|
||||
paint = createLinearGradientPaint(gradFill, anchor, theme, phClr);
|
||||
} else if (gradFill.isSetPath()){
|
||||
CTPathShadeProperties ps = gradFill.getPath();
|
||||
if(ps.getPath() == STPathShadeType.CIRCLE){
|
||||
paint = createRadialGradientPaint(gradFill, anchor, theme, phClr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paint;
|
||||
}
|
||||
|
||||
private Paint createTexturePaint(CTBlipFillProperties blipFill, Graphics2D graphics,
|
||||
PackagePart parentPart){
|
||||
Paint paint = null;
|
||||
CTBlip blip = blipFill.getBlip();
|
||||
String blipId = blip.getEmbed();
|
||||
PackageRelationship rel = parentPart.getRelationship(blipId);
|
||||
if (rel != null) {
|
||||
XSLFImageRendener renderer = null;
|
||||
if (graphics != null)
|
||||
renderer = (XSLFImageRendener) graphics.getRenderingHint(XSLFRenderingHint.IMAGE_RENDERER);
|
||||
if (renderer == null) renderer = new XSLFImageRendener();
|
||||
|
||||
try {
|
||||
BufferedImage img = renderer.readImage(parentPart.getRelatedPart(rel));
|
||||
if (blip.sizeOfAlphaModFixArray() > 0) {
|
||||
float alpha = blip.getAlphaModFixArray(0).getAmt() / 100000.f;
|
||||
AlphaComposite ac = AlphaComposite.getInstance(
|
||||
AlphaComposite.SRC_OVER, alpha);
|
||||
if (graphics != null) graphics.setComposite(ac);
|
||||
}
|
||||
|
||||
if(img != null) {
|
||||
paint = new TexturePaint(
|
||||
img, new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return paint;
|
||||
}
|
||||
|
||||
private static Paint createLinearGradientPaint(
|
||||
CTGradientFillProperties gradFill, Rectangle2D anchor,
|
||||
XSLFTheme theme, CTSchemeColor phClr) {
|
||||
double angle = gradFill.getLin().getAng() / 60000;
|
||||
CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
|
||||
|
||||
Arrays.sort(gs, new Comparator<CTGradientStop>() {
|
||||
public int compare(CTGradientStop o1, CTGradientStop o2) {
|
||||
Integer pos1 = o1.getPos();
|
||||
Integer pos2 = o2.getPos();
|
||||
return pos1.compareTo(pos2);
|
||||
}
|
||||
});
|
||||
|
||||
Color[] colors = new Color[gs.length];
|
||||
float[] fractions = new float[gs.length];
|
||||
|
||||
AffineTransform at = AffineTransform.getRotateInstance(
|
||||
Math.toRadians(angle),
|
||||
anchor.getX() + anchor.getWidth() / 2,
|
||||
anchor.getY() + anchor.getHeight() / 2);
|
||||
|
||||
double diagonal = Math.sqrt(anchor.getHeight() * anchor.getHeight() + anchor.getWidth() * anchor.getWidth());
|
||||
Point2D p1 = new Point2D.Double(anchor.getX() + anchor.getWidth() / 2 - diagonal / 2,
|
||||
anchor.getY() + anchor.getHeight() / 2);
|
||||
p1 = at.transform(p1, null);
|
||||
|
||||
Point2D p2 = new Point2D.Double(anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight() / 2);
|
||||
p2 = at.transform(p2, null);
|
||||
|
||||
snapToAnchor(p1, anchor);
|
||||
snapToAnchor(p2, anchor);
|
||||
|
||||
for (int i = 0; i < gs.length; i++) {
|
||||
CTGradientStop stop = gs[i];
|
||||
colors[i] = new XSLFColor(stop, theme, phClr).getColor();
|
||||
fractions[i] = stop.getPos() / 100000.f;
|
||||
}
|
||||
|
||||
// Trick to return GradientPaint on JDK 1.5 and LinearGradientPaint on JDK 1.6+
|
||||
Paint paint;
|
||||
try {
|
||||
Class clz = Class.forName("java.awt.LinearGradientPaint");
|
||||
Constructor c =
|
||||
clz.getConstructor(Point2D.class, Point2D.class, float[].class, Color[].class);
|
||||
paint = (Paint) c.newInstance(p1, p2, fractions, colors);
|
||||
} catch (ClassNotFoundException e) {
|
||||
paint = new GradientPaint(p1, colors[0], p2, colors[colors.length - 1]);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return paint;
|
||||
}
|
||||
|
||||
private static Paint createRadialGradientPaint(
|
||||
CTGradientFillProperties gradFill, Rectangle2D anchor,
|
||||
XSLFTheme theme, CTSchemeColor phClr) {
|
||||
CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
|
||||
|
||||
Point2D pCenter = new Point2D.Double(anchor.getX() + anchor.getWidth()/2,
|
||||
anchor.getY() + anchor.getHeight()/2);
|
||||
|
||||
float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight());
|
||||
|
||||
Arrays.sort(gs, new Comparator<CTGradientStop>() {
|
||||
public int compare(CTGradientStop o1, CTGradientStop o2) {
|
||||
Integer pos1 = o1.getPos();
|
||||
Integer pos2 = o2.getPos();
|
||||
return pos1.compareTo(pos2);
|
||||
}
|
||||
});
|
||||
|
||||
Color[] colors = new Color[gs.length];
|
||||
float[] fractions = new float[gs.length];
|
||||
|
||||
|
||||
for (int i = 0; i < gs.length; i++) {
|
||||
CTGradientStop stop = gs[i];
|
||||
colors[i] = new XSLFColor(stop, theme, phClr).getColor();
|
||||
fractions[i] = stop.getPos() / 100000.f;
|
||||
}
|
||||
|
||||
// Trick to return GradientPaint on JDK 1.5 and RadialGradientPaint on JDK 1.6+
|
||||
Paint paint;
|
||||
try {
|
||||
Class clz = Class.forName("java.awt.RadialGradientPaint");
|
||||
Constructor c =
|
||||
clz.getConstructor(Point2D.class, float.class,
|
||||
float[].class, Color[].class);
|
||||
paint = (Paint) c.newInstance(pCenter, radius, fractions, colors);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// the result on JDK 1.5 is incorrect, but it is better than nothing
|
||||
paint = new GradientPaint(
|
||||
new Point2D.Double(anchor.getX(), anchor.getY()),
|
||||
colors[0], pCenter, colors[colors.length - 1]);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return paint;
|
||||
}
|
||||
|
||||
private static void snapToAnchor(Point2D p, Rectangle2D anchor) {
|
||||
if (p.getX() < anchor.getX()) {
|
||||
p.setLocation(anchor.getX(), p.getY());
|
||||
} else if (p.getX() > (anchor.getX() + anchor.getWidth())) {
|
||||
p.setLocation(anchor.getX() + anchor.getWidth(), p.getY());
|
||||
}
|
||||
|
||||
if (p.getY() < anchor.getY()) {
|
||||
p.setLocation(p.getX(), anchor.getY());
|
||||
} else if (p.getY() > (anchor.getY() + anchor.getHeight())) {
|
||||
p.setLocation(p.getX(), anchor.getY() + anchor.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation") // getXYZArray() array accessors are deprecated
|
||||
Paint getPaint(Graphics2D graphics, XmlObject spPr, CTSchemeColor phClr) {
|
||||
|
||||
Paint paint = null;
|
||||
for (XmlObject obj : spPr.selectPath("*")) {
|
||||
paint = selectPaint(graphics, obj, phClr, _shape.getSheet().getPackagePart());
|
||||
if(paint != null) break;
|
||||
}
|
||||
return paint == NO_PAINT ? null : paint;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetch shape fill as a java.awt.Paint
|
||||
*
|
||||
* @return either Color or GradientPaint or TexturePaint or null
|
||||
*/
|
||||
Paint getFillPaint(final Graphics2D graphics) {
|
||||
PropertyFetcher<Paint> fetcher = new PropertyFetcher<Paint>() {
|
||||
public boolean fetch(XSLFSimpleShape shape) {
|
||||
CTShapeProperties spPr = shape.getSpPr();
|
||||
if (spPr.isSetNoFill()) {
|
||||
setValue(RenderableShape.NO_PAINT); // use it as 'nofill' value
|
||||
return true;
|
||||
}
|
||||
Paint paint = getPaint(graphics, spPr, null);
|
||||
if (paint != null) {
|
||||
setValue(paint);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
_shape.fetchShapeProperty(fetcher);
|
||||
|
||||
Paint paint = fetcher.getValue();
|
||||
if (paint == null) {
|
||||
// fill color was not found, check if it is defined in the theme
|
||||
CTShapeStyle style = _shape.getSpStyle();
|
||||
if (style != null) {
|
||||
// get a reference to a fill style within the style matrix.
|
||||
CTStyleMatrixReference fillRef = style.getFillRef();
|
||||
// The idx attribute refers to the index of a fill style or
|
||||
// background fill style within the presentation's style matrix, defined by the fmtScheme element.
|
||||
// value of 0 or 1000 indicates no background,
|
||||
// values 1-999 refer to the index of a fill style within the fillStyleLst element
|
||||
// values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element.
|
||||
int idx = (int)fillRef.getIdx();
|
||||
CTSchemeColor phClr = fillRef.getSchemeClr();
|
||||
XSLFSheet sheet = _shape.getSheet();
|
||||
XSLFTheme theme = sheet.getTheme();
|
||||
XmlObject fillProps = null;
|
||||
if(idx >= 1 && idx <= 999){
|
||||
fillProps = theme.getXmlObject().
|
||||
getThemeElements().getFmtScheme().getFillStyleLst().selectPath("*")[idx - 1];
|
||||
} else if (idx >= 1001 ){
|
||||
fillProps = theme.getXmlObject().
|
||||
getThemeElements().getFmtScheme().getBgFillStyleLst().selectPath("*")[idx - 1001];
|
||||
}
|
||||
if(fillProps != null) {
|
||||
paint = selectPaint(graphics, fillProps, phClr, sheet.getPackagePart());
|
||||
}
|
||||
}
|
||||
}
|
||||
return paint == RenderableShape.NO_PAINT ? null : paint;
|
||||
}
|
||||
|
||||
public Paint getLinePaint(final Graphics2D graphics) {
|
||||
PropertyFetcher<Paint> fetcher = new PropertyFetcher<Paint>() {
|
||||
public boolean fetch(XSLFSimpleShape shape) {
|
||||
CTLineProperties spPr = shape.getSpPr().getLn();
|
||||
if (spPr != null) {
|
||||
if (spPr.isSetNoFill()) {
|
||||
setValue(NO_PAINT); // use it as 'nofill' value
|
||||
return true;
|
||||
}
|
||||
Paint paint = getPaint(graphics, spPr, null);
|
||||
if (paint != null) {
|
||||
setValue(paint);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
};
|
||||
_shape.fetchShapeProperty(fetcher);
|
||||
|
||||
Paint paint = fetcher.getValue();
|
||||
if (paint == null) {
|
||||
// line color was not found, check if it is defined in the theme
|
||||
CTShapeStyle style = _shape.getSpStyle();
|
||||
if (style != null) {
|
||||
// get a reference to a line style within the style matrix.
|
||||
CTStyleMatrixReference lnRef = style.getLnRef();
|
||||
int idx = (int)lnRef.getIdx();
|
||||
CTSchemeColor phClr = lnRef.getSchemeClr();
|
||||
if(idx > 0){
|
||||
XSLFTheme theme = _shape.getSheet().getTheme();
|
||||
XmlObject lnProps = theme.getXmlObject().
|
||||
getThemeElements().getFmtScheme().getLnStyleLst().selectPath("*")[idx - 1];
|
||||
paint = getPaint(graphics, lnProps, phClr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paint == NO_PAINT ? null : paint;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert PPT dash into java.awt.BasicStroke
|
||||
*
|
||||
* The mapping is derived empirically on PowerPoint 2010
|
||||
*/
|
||||
private static 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;
|
||||
}
|
||||
|
||||
|
||||
public Stroke applyStroke(Graphics2D graphics) {
|
||||
|
||||
float lineWidth = (float) _shape.getLineWidth();
|
||||
LineDash lineDash = _shape.getLineDash();
|
||||
float[] dash = null;
|
||||
float dash_phase = 0;
|
||||
if (lineDash != null) {
|
||||
dash = getDashPattern(lineDash, lineWidth);
|
||||
}
|
||||
|
||||
int cap = BasicStroke.CAP_BUTT;
|
||||
LineCap lineCap = _shape.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, Math.max(1, lineWidth), dash,
|
||||
dash_phase);
|
||||
graphics.setStroke(stroke);
|
||||
return stroke;
|
||||
}
|
||||
|
||||
public void render(Graphics2D graphics){
|
||||
Collection<Outline> elems = computeOutlines();
|
||||
|
||||
// shadow
|
||||
XSLFShadow shadow = _shape.getShadow();
|
||||
|
||||
// first fill
|
||||
Paint fill = getFillPaint(graphics);
|
||||
if(fill != null) for(Outline o : elems){
|
||||
if(o.getPath().isFilled()){
|
||||
if(shadow != null) shadow.fill(graphics, o.getOutline());
|
||||
|
||||
graphics.setPaint(fill);
|
||||
graphics.fill(o.getOutline());
|
||||
}
|
||||
}
|
||||
|
||||
// then draw any content within this shape (text, image, etc.)
|
||||
_shape.drawContent(graphics);
|
||||
|
||||
// then stroke the shape outline
|
||||
Paint line = getLinePaint(graphics);
|
||||
if(line != null) for(Outline o : elems){
|
||||
if(o.getPath().isStroked()){
|
||||
applyStroke(graphics); // the stroke applies both to the shadow and the shape
|
||||
|
||||
if(shadow != null) shadow.draw(graphics, o.getOutline());
|
||||
|
||||
graphics.setPaint(line);
|
||||
graphics.draw(o.getOutline());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<Outline> computeOutlines() {
|
||||
CustomGeometry geom = _shape.getGeometry();
|
||||
|
||||
Collection<Outline> lst = new ArrayList<Outline>();
|
||||
|
||||
Rectangle2D anchor = _shape.getAnchor();
|
||||
for (Path p : geom) {
|
||||
|
||||
double w = p.getW() == -1 ? anchor.getWidth() * Units.EMU_PER_POINT : p.getW();
|
||||
double h = p.getH() == -1 ? anchor.getHeight() * Units.EMU_PER_POINT : p.getH();
|
||||
|
||||
// the guides in the shape definitions are all defined relative to each other,
|
||||
// so we build the path starting from (0,0).
|
||||
final Rectangle2D pathAnchor = new Rectangle2D.Double(
|
||||
0,
|
||||
0,
|
||||
w,
|
||||
h
|
||||
);
|
||||
|
||||
Context ctx = new Context(geom, pathAnchor, new IAdjustableShape() {
|
||||
|
||||
public Guide getAdjustValue(String name) {
|
||||
CTPresetGeometry2D prst = _shape.getSpPr().getPrstGeom();
|
||||
if (prst.isSetAvLst()) {
|
||||
for (CTGeomGuide g : prst.getAvLst().getGdList()) {
|
||||
if (g.getName().equals(name)) {
|
||||
return new Guide(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}) ;
|
||||
|
||||
Shape gp = p.getPath(ctx);
|
||||
|
||||
// translate the result to the canvas coordinates in points
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.translate(anchor.getX(), anchor.getY());
|
||||
|
||||
double scaleX, scaleY;
|
||||
if (p.getW() != -1) {
|
||||
scaleX = anchor.getWidth() / p.getW();
|
||||
} else {
|
||||
scaleX = 1.0 / Units.EMU_PER_POINT;
|
||||
}
|
||||
if (p.getH() != -1) {
|
||||
scaleY = anchor.getHeight() / p.getH();
|
||||
} else {
|
||||
scaleY = 1.0 / Units.EMU_PER_POINT;
|
||||
}
|
||||
|
||||
at.scale(scaleX, scaleY);
|
||||
|
||||
Shape canvasShape = at.createTransformedShape(gp);
|
||||
|
||||
lst.add(new Outline(canvasShape, p));
|
||||
}
|
||||
|
||||
// add any shape-specific stuff here (line decorations, etc.)
|
||||
lst.addAll(_shape.getCustomOutlines());
|
||||
return lst;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Date: 11/5/11
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public enum SlideLayout {
|
||||
/**
|
||||
* Title layout with centered title and subtitle placeholders
|
||||
*/
|
||||
TITLE,
|
||||
/**
|
||||
* Title and text
|
||||
*/
|
||||
TEXT,
|
||||
|
||||
TWO_COL_TX,
|
||||
TBL,
|
||||
TEXT_AND_CHART,
|
||||
|
||||
/**
|
||||
* Title, chart on left and text on right
|
||||
*/
|
||||
CHART_AND_TEXT,
|
||||
|
||||
DGM,
|
||||
|
||||
/**
|
||||
* Title and chart
|
||||
*/
|
||||
CHART,
|
||||
|
||||
TX_AND_CLIP_ART,
|
||||
/**
|
||||
* Title, clipart on left, text on right
|
||||
*/
|
||||
CLIP_ART_AND_TEXT,
|
||||
|
||||
/**
|
||||
* Title only
|
||||
*/
|
||||
TITLE_ONLY,
|
||||
|
||||
/**
|
||||
* Blank
|
||||
*/
|
||||
BLANK,
|
||||
|
||||
TX_AND_OBJ,
|
||||
OBJ_AND_TX,
|
||||
OBJ_ONLY,
|
||||
/**
|
||||
* title and content
|
||||
*/
|
||||
TITLE_AND_CONTENT,
|
||||
TX_AND_MEDIA,
|
||||
MEDIA_AND_TX,
|
||||
OBJ_OVER_TX,
|
||||
TX_OVER_OBJ,
|
||||
TX_AND_TWO_OBJ,
|
||||
TWO_OBJ_AND_TX,
|
||||
TWO_OBJ_OVER_TX,
|
||||
FOUR_OBJ,
|
||||
VERT_TX,
|
||||
CLIP_ART_AND_VERT_TX,
|
||||
VERT_TITLE_AND_TX,
|
||||
VERT_TITLE_AND_TX_OVER_CHART,
|
||||
TWO_OBJ,
|
||||
OBJ_AND_TWO_OBJ,
|
||||
TWO_OBJ_AND_OBJ,
|
||||
CUST,
|
||||
/**
|
||||
* Section Header
|
||||
*/
|
||||
SECTION_HEADER,
|
||||
TWO_TX_TWO_OBJ,
|
||||
OBJ_TX,
|
||||
PIC_TX,
|
||||
}
|
|
@ -43,5 +43,8 @@ public enum TextAlign {
|
|||
* is smart in the sense that it will not justify sentences
|
||||
* which are short
|
||||
*/
|
||||
JUSTIFY
|
||||
JUSTIFY,
|
||||
JUSTIFY_LOW,
|
||||
DIST,
|
||||
THAI_DIST
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: yegor
|
||||
* Date: 11/3/11
|
||||
* Time: 5:07 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
public enum TextCap {
|
||||
NONE,
|
||||
SMALL,
|
||||
ALL
|
||||
}
|
|
@ -40,7 +40,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry;
|
|||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideSize;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.PresentationDocument;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Dimension;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -190,7 +190,13 @@ public class XMLSlideShow extends POIXMLDocument {
|
|||
return Collections.unmodifiableList(_pictures);
|
||||
}
|
||||
|
||||
public XSLFSlide createSlide() {
|
||||
/**
|
||||
* Create a slide and initialize it from the specified layout.
|
||||
*
|
||||
* @param layout
|
||||
* @return created slide
|
||||
*/
|
||||
public XSLFSlide createSlide(XSLFSlideLayout layout) {
|
||||
int slideNumber = 256, cnt = 1;
|
||||
CTSlideIdList slideList;
|
||||
if (!_presentation.isSetSldIdLst()) slideList = _presentation.addNewSldIdLst();
|
||||
|
@ -209,12 +215,7 @@ public class XMLSlideShow extends POIXMLDocument {
|
|||
slideId.setId(slideNumber);
|
||||
slideId.setId2(slide.getPackageRelationship().getId());
|
||||
|
||||
String masterId = _presentation.getSldMasterIdLst().getSldMasterIdArray(0).getId2();
|
||||
XSLFSlideMaster master = _masters.get(masterId);
|
||||
|
||||
XSLFSlideLayout layout = master.getLayout("blank");
|
||||
if(layout == null) throw new IllegalArgumentException("Blank layout was not found");
|
||||
|
||||
layout.copyLayout(slide);
|
||||
slide.addRelation(layout.getPackageRelationship().getId(), layout);
|
||||
|
||||
PackagePartName ppName = layout.getPackagePart().getPartName();
|
||||
|
@ -224,7 +225,20 @@ public class XMLSlideShow extends POIXMLDocument {
|
|||
_slides.add(slide);
|
||||
return slide;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a blank slide.
|
||||
*/
|
||||
public XSLFSlide createSlide() {
|
||||
String masterId = _presentation.getSldMasterIdLst().getSldMasterIdArray(0).getId2();
|
||||
XSLFSlideMaster master = _masters.get(masterId);
|
||||
|
||||
XSLFSlideLayout layout = master.getLayout(SlideLayout.BLANK);
|
||||
if(layout == null) throw new IllegalArgumentException("Blank layout was not found");
|
||||
|
||||
return createSlide(layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Notes Master, if there is one.
|
||||
* (May not be present if no notes exist)
|
||||
|
|
|
@ -28,16 +28,14 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
|
|||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents a preset geometric shape.
|
||||
* Represents a shape with a preset geometry.
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
@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);
|
||||
|
|
|
@ -17,16 +17,16 @@
|
|||
|
||||
package org.apache.poi.xslf.usermodel;
|
||||
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBackgroundFillStyleList;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBackgroundFillStyleList;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Paint;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
|
@ -49,31 +49,46 @@ public class XSLFBackground extends XSLFSimpleShape {
|
|||
public void draw(Graphics2D graphics) {
|
||||
Rectangle2D anchor = getAnchor();
|
||||
|
||||
XmlObject spPr = null;
|
||||
CTBackground bg = (CTBackground)getXmlObject();
|
||||
if(bg.isSetBgPr()){
|
||||
spPr = bg.getBgPr();
|
||||
} else if (bg.isSetBgRef()){
|
||||
CTStyleMatrixReference bgRef= bg.getBgRef();
|
||||
int idx = (int)bgRef.getIdx() - 1000;
|
||||
XSLFTheme theme = getSheet().getTheme();
|
||||
CTBackgroundFillStyleList bgStyles =
|
||||
theme.getXmlObject().getThemeElements().getFmtScheme().getBgFillStyleLst();
|
||||
|
||||
// TODO pass this to getPaint
|
||||
XmlObject bgStyle = bgStyles.selectPath("*")[idx];
|
||||
}
|
||||
|
||||
if(spPr == null){
|
||||
return;
|
||||
}
|
||||
|
||||
Paint fill = getPaint(graphics, spPr);
|
||||
Paint fill = getPaint(graphics);
|
||||
if(fill != null) {
|
||||
graphics.setPaint(fill);
|
||||
graphics.fill(anchor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the Paint object to fill
|
||||
*/
|
||||
Paint getPaint(Graphics2D graphics){
|
||||
RenderableShape rShape = new RenderableShape(this);
|
||||
|
||||
Paint fill = null;
|
||||
CTBackground bg = (CTBackground)getXmlObject();
|
||||
if(bg.isSetBgPr()){
|
||||
XmlObject spPr = bg.getBgPr();
|
||||
fill = rShape.getPaint(graphics, spPr, null);
|
||||
} else if (bg.isSetBgRef()){
|
||||
CTStyleMatrixReference bgRef= bg.getBgRef();
|
||||
CTSchemeColor phClr = bgRef.getSchemeClr();
|
||||
|
||||
int idx = (int)bgRef.getIdx() - 1001;
|
||||
XSLFTheme theme = getSheet().getTheme();
|
||||
CTBackgroundFillStyleList bgStyles =
|
||||
theme.getXmlObject().getThemeElements().getFmtScheme().getBgFillStyleLst();
|
||||
|
||||
XmlObject bgStyle = bgStyles.selectPath("*")[idx];
|
||||
fill = rShape.selectPaint(graphics, bgStyle, phClr, theme.getPackagePart());
|
||||
}
|
||||
|
||||
return fill;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getFillColor(){
|
||||
Paint p = getPaint(null);
|
||||
if(p instanceof Color){
|
||||
return (Color)p;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
|
|||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSystemColor;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -40,12 +40,15 @@ import java.util.Map;
|
|||
* @author Yegor Kozlov
|
||||
*/
|
||||
@Beta
|
||||
@Internal
|
||||
public class XSLFColor {
|
||||
private XmlObject _xmlObject;
|
||||
private Color _color;
|
||||
private CTSchemeColor _phClr;
|
||||
|
||||
XSLFColor(XmlObject obj, XSLFTheme theme) {
|
||||
public XSLFColor(XmlObject obj, XSLFTheme theme, CTSchemeColor phClr) {
|
||||
_xmlObject = obj;
|
||||
_phClr = phClr;
|
||||
_color = toColor(obj, theme);
|
||||
}
|
||||
|
||||
|
@ -94,7 +97,7 @@ public class XSLFColor {
|
|||
return result;
|
||||
}
|
||||
|
||||
static Color toColor(XmlObject obj, XSLFTheme theme) {
|
||||
Color toColor(XmlObject obj, XSLFTheme theme) {
|
||||
Color color = null;
|
||||
for (XmlObject ch : obj.selectPath("*")) {
|
||||
if (ch instanceof CTHslColor) {
|
||||
|
@ -102,7 +105,8 @@ public class XSLFColor {
|
|||
int h = hsl.getHue2();
|
||||
int s = hsl.getSat2();
|
||||
int l = hsl.getLum2();
|
||||
// is it correct ?
|
||||
// This conversion is not correct and differs from PowerPoint.
|
||||
// TODO: Revisit and improve.
|
||||
color = Color.getHSBColor(h / 60000f, s / 100000f, l / 100000f);
|
||||
} else if (ch instanceof CTPresetColor) {
|
||||
CTPresetColor prst = (CTPresetColor)ch;
|
||||
|
@ -111,12 +115,13 @@ public class XSLFColor {
|
|||
} else if (ch instanceof CTSchemeColor) {
|
||||
CTSchemeColor schemeColor = (CTSchemeColor)ch;
|
||||
String colorRef = schemeColor.getVal().toString();
|
||||
if(_phClr != null) {
|
||||
// context color overrides the theme
|
||||
colorRef = _phClr.getVal().toString();
|
||||
}
|
||||
// find referenced CTColor in the theme and convert it to java.awt.Color via a recursive call
|
||||
CTColor ctColor = theme.getCTColor(colorRef);
|
||||
if(ctColor != null) color = toColor(ctColor, null);
|
||||
else {
|
||||
color = Color.black;
|
||||
}
|
||||
} else if (ch instanceof CTScRgbColor) {
|
||||
// same as CTSRgbColor but with values expressed in percents
|
||||
CTScRgbColor scrgb = (CTScRgbColor)ch;
|
||||
|
@ -145,21 +150,59 @@ public class XSLFColor {
|
|||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a perecentage value from the supplied xml bean.
|
||||
* Example:
|
||||
* <a:tint val="45000"/>
|
||||
*
|
||||
* the returned value is 45
|
||||
*
|
||||
* @return the percentage value in the range [0 .. 100]
|
||||
*/
|
||||
private int getPercentageValue(String elem){
|
||||
XmlObject[] obj = _xmlObject.selectPath(
|
||||
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' $this//a:" + elem);
|
||||
String query = "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' $this//a:" + elem;
|
||||
|
||||
XmlObject[] obj;
|
||||
|
||||
// first ask the context color and if not found, ask the actual color bean
|
||||
if(_phClr != null){
|
||||
obj = _phClr.selectPath(query);
|
||||
if(obj.length == 1){
|
||||
Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val");
|
||||
if(attr != null) {
|
||||
return Integer.parseInt(attr.getNodeValue()) / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj = _xmlObject.selectPath(query);
|
||||
if(obj.length == 1){
|
||||
Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val");
|
||||
if(attr != null) {
|
||||
return Integer.parseInt(attr.getNodeValue()) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int getAngleValue(String elem){
|
||||
XmlObject[] obj = _xmlObject.selectPath(
|
||||
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' $this//a:" + elem);
|
||||
String color = "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' $this//a:" + elem;
|
||||
XmlObject[] obj;
|
||||
|
||||
// first ask the context color and if not found, ask the actual color bean
|
||||
if(_phClr != null){
|
||||
obj = _xmlObject.selectPath( color );
|
||||
if(obj.length == 1){
|
||||
Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val");
|
||||
if(attr != null) {
|
||||
return Integer.parseInt(attr.getNodeValue()) / 60000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj = _xmlObject.selectPath( color );
|
||||
if(obj.length == 1){
|
||||
Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val");
|
||||
if(attr != null) {
|
||||
|
@ -341,7 +384,7 @@ public class XSLFColor {
|
|||
* A 10% shade is 10% of the input color combined with 90% black.
|
||||
*
|
||||
* @return the value of the shade specified as a
|
||||
* percentage with 0% indicating minimal blue and 100% indicating maximum
|
||||
* percentage with 0% indicating minimal shade and 100% indicating maximum
|
||||
* or -1 if the value is not set
|
||||
*/
|
||||
int getShade(){
|
||||
|
@ -353,7 +396,7 @@ public class XSLFColor {
|
|||
* A 10% tint is 10% of the input color combined with 90% white.
|
||||
*
|
||||
* @return the value of the tint specified as a
|
||||
* percentage with 0% indicating minimal blue and 100% indicating maximum
|
||||
* percentage with 0% indicating minimal tint and 100% indicating maximum
|
||||
* or -1 if the value is not set
|
||||
*/
|
||||
int getTint(){
|
||||
|
@ -389,6 +432,10 @@ public class XSLFColor {
|
|||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* This algorithm returns result different from PowerPoint.
|
||||
* TODO: revisit and improve
|
||||
*/
|
||||
private static Color shade(Color c, int shade) {
|
||||
return new Color(
|
||||
(int)(c.getRed() * shade * 0.01),
|
||||
|
@ -397,6 +444,10 @@ public class XSLFColor {
|
|||
c.getAlpha());
|
||||
}
|
||||
|
||||
/**
|
||||
* This algorithm returns result different from PowerPoint.
|
||||
* TODO: revisit and improve
|
||||
*/
|
||||
private static Color tint(Color c, int tint) {
|
||||
int r = c.getRed();
|
||||
int g = c.getGreen();
|
||||
|
@ -414,7 +465,7 @@ public class XSLFColor {
|
|||
/**
|
||||
* Preset colors defined in DrawingML
|
||||
*/
|
||||
static Map<String, Color> presetColors;
|
||||
static final Map<String, Color> presetColors;
|
||||
|
||||
static {
|
||||
presetColors = new HashMap<String, Color>();
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
package org.apache.poi.xslf.usermodel;
|
||||
|
||||
import org.apache.poi.util.Beta;
|
||||
import org.apache.poi.xslf.model.geom.Outline;
|
||||
import org.apache.poi.xslf.model.geom.Path;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
|
||||
|
@ -32,11 +34,14 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
|
|||
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnectorNonVisual;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Specifies a connection shape.
|
||||
|
@ -197,36 +202,7 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
|
|||
return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D graphics) {
|
||||
java.awt.Shape outline = getOutline();
|
||||
|
||||
// shadow
|
||||
XSLFShadow shadow = getShadow();
|
||||
|
||||
//border
|
||||
Paint line = getLinePaint(graphics);
|
||||
if (line != null) {
|
||||
if (shadow != null) shadow.draw(graphics);
|
||||
|
||||
graphics.setPaint(line);
|
||||
applyStroke(graphics);
|
||||
graphics.draw(outline);
|
||||
|
||||
Shape tailDecoration = getTailDecoration();
|
||||
if (tailDecoration != null) {
|
||||
graphics.draw(tailDecoration);
|
||||
}
|
||||
|
||||
Shape headDecoration = getHeadDecoration();
|
||||
if (headDecoration != null) {
|
||||
graphics.draw(headDecoration);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Shape getTailDecoration() {
|
||||
Outline getTailDecoration() {
|
||||
LineEndLength tailLength = getLineTailLength();
|
||||
LineEndWidth tailWidth = getLineTailWidth();
|
||||
|
||||
|
@ -239,17 +215,20 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
|
|||
|
||||
AffineTransform at = new AffineTransform();
|
||||
Shape shape = null;
|
||||
Path p = null;
|
||||
Rectangle2D bounds;
|
||||
double scaleY = Math.pow(2, tailWidth.ordinal());
|
||||
double scaleX = Math.pow(2, tailLength.ordinal());
|
||||
switch (getLineHeadDecoration()) {
|
||||
switch (getLineTailDecoration()) {
|
||||
case OVAL:
|
||||
p = new Path();
|
||||
shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
|
||||
bounds = shape.getBounds2D();
|
||||
at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2);
|
||||
at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
|
||||
break;
|
||||
case ARROW:
|
||||
p = new Path();
|
||||
GeneralPath arrow = new GeneralPath();
|
||||
arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2));
|
||||
arrow.lineTo(0, 0);
|
||||
|
@ -259,6 +238,7 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
|
|||
at.rotate(alpha);
|
||||
break;
|
||||
case TRIANGLE:
|
||||
p = new Path();
|
||||
scaleY = tailWidth.ordinal() + 1;
|
||||
scaleX = tailLength.ordinal() + 1;
|
||||
GeneralPath triangle = new GeneralPath();
|
||||
|
@ -277,10 +257,10 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
|
|||
if (shape != null) {
|
||||
shape = at.createTransformedShape(shape);
|
||||
}
|
||||
return shape;
|
||||
return shape == null ? null : new Outline(shape, p);
|
||||
}
|
||||
|
||||
Shape getHeadDecoration() {
|
||||
Outline getHeadDecoration() {
|
||||
LineEndLength headLength = getLineHeadLength();
|
||||
LineEndWidth headWidth = getLineHeadWidth();
|
||||
|
||||
|
@ -293,11 +273,13 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
|
|||
|
||||
AffineTransform at = new AffineTransform();
|
||||
Shape shape = null;
|
||||
Path p = null;
|
||||
Rectangle2D bounds;
|
||||
double scaleY = 1;
|
||||
double scaleX = 1;
|
||||
switch (getLineHeadDecoration()) {
|
||||
case OVAL:
|
||||
p = new Path();
|
||||
shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY);
|
||||
bounds = shape.getBounds2D();
|
||||
at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2);
|
||||
|
@ -305,6 +287,7 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
|
|||
break;
|
||||
case STEALTH:
|
||||
case ARROW:
|
||||
p = new Path();
|
||||
GeneralPath arrow = new GeneralPath();
|
||||
arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2));
|
||||
arrow.lineTo(0, 0);
|
||||
|
@ -314,6 +297,7 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
|
|||
at.rotate(alpha);
|
||||
break;
|
||||
case TRIANGLE:
|
||||
p = new Path();
|
||||
scaleY = headWidth.ordinal() + 1;
|
||||
scaleX = headLength.ordinal() + 1;
|
||||
GeneralPath triangle = new GeneralPath();
|
||||
|
@ -332,7 +316,19 @@ public class XSLFConnectorShape extends XSLFSimpleShape {
|
|||
if (shape != null) {
|
||||
shape = at.createTransformedShape(shape);
|
||||
}
|
||||
return shape;
|
||||
return shape == null ? null : new Outline(shape, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Outline> getCustomOutlines(){
|
||||
List<Outline> lst = new ArrayList<Outline>();
|
||||
|
||||
Outline head = getHeadDecoration();
|
||||
if(head != null) lst.add(head);
|
||||
|
||||
Outline tail = getTailDecoration();
|
||||
if(tail != null) lst.add(tail);
|
||||
return lst;
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,8 @@ 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 java.awt.*;
|
||||
import java.awt.Color;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -188,10 +188,4 @@ public class XSLFFreeformShape extends XSLFAutoShape {
|
|||
geom.addNewPathLst();
|
||||
return ct;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected java.awt.Shape getOutline(){
|
||||
return getPath();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
|
|||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,7 +35,7 @@ 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.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.List;
|
||||
|
@ -62,10 +62,12 @@ public class XSLFGroupShape extends XSLFShape {
|
|||
_spPr = shape.getGrpSpPr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CTGroupShape getXmlObject(){
|
||||
return _shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getAnchor(){
|
||||
CTGroupTransform2D xfrm = _spPr.getXfrm();
|
||||
CTPoint2D off = xfrm.getOff();
|
||||
|
@ -79,6 +81,7 @@ public class XSLFGroupShape extends XSLFShape {
|
|||
Units.toPoints(cx), Units.toPoints(cy));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnchor(Rectangle2D anchor){
|
||||
CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm();
|
||||
CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
|
||||
|
@ -93,6 +96,12 @@ public class XSLFGroupShape extends XSLFShape {
|
|||
ext.setCy(cy);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the coordinates of the child extents rectangle
|
||||
* used for calculations of grouping, scaling, and rotation
|
||||
* behavior of shapes placed within a group.
|
||||
*/
|
||||
public Rectangle2D getInteriorAnchor(){
|
||||
CTGroupTransform2D xfrm = _spPr.getXfrm();
|
||||
CTPoint2D off = xfrm.getChOff();
|
||||
|
@ -106,6 +115,12 @@ public class XSLFGroupShape extends XSLFShape {
|
|||
Units.toPoints(cx), Units.toPoints(cy));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param anchor the coordinates of the child extents rectangle
|
||||
* used for calculations of grouping, scaling, and rotation
|
||||
* behavior of shapes placed within a group.
|
||||
*/
|
||||
public void setInteriorAnchor(Rectangle2D anchor){
|
||||
CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm();
|
||||
CTPoint2D off = xfrm.isSetChOff() ? xfrm.getChOff() : xfrm.addNewChOff();
|
||||
|
@ -120,10 +135,17 @@ public class XSLFGroupShape extends XSLFShape {
|
|||
ext.setCy(cy);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return child shapes contained witin this group
|
||||
*/
|
||||
public XSLFShape[] getShapes(){
|
||||
return _shapes.toArray(new XSLFShape[_shapes.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified shape from this group
|
||||
*/
|
||||
public boolean removeShape(XSLFShape xShape) {
|
||||
XmlObject obj = xShape.getXmlObject();
|
||||
if(obj instanceof CTShape){
|
||||
|
@ -138,10 +160,12 @@ public class XSLFGroupShape extends XSLFShape {
|
|||
return _shapes.remove(xShape);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShapeName(){
|
||||
return _shape.getNvGrpSpPr().getCNvPr().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShapeId(){
|
||||
return (int)_shape.getNvGrpSpPr().getCNvPr().getId();
|
||||
}
|
||||
|
@ -216,53 +240,37 @@ public class XSLFGroupShape extends XSLFShape {
|
|||
return sh;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFlipHorizontal(boolean flip){
|
||||
_spPr.getXfrm().setFlipH(flip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlipVertical(boolean flip){
|
||||
_spPr.getXfrm().setFlipV(flip);
|
||||
}
|
||||
/**
|
||||
* Whether the shape is horizontally flipped
|
||||
*
|
||||
* @return whether the shape is horizontally flipped
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean getFlipHorizontal(){
|
||||
return _spPr.getXfrm().getFlipH();
|
||||
}
|
||||
|
||||
@Override
|
||||
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.
|
||||
*/
|
||||
@Override
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public double getRotation(){
|
||||
return (double)_spPr.getXfrm().getRot()/60000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D graphics){
|
||||
|
||||
// the coordinate system of this group of shape
|
||||
|
@ -278,16 +286,14 @@ public class XSLFGroupShape extends XSLFShape {
|
|||
|
||||
for (XSLFShape shape : getShapes()) {
|
||||
// remember the initial transform and restore it after we are done with the drawing
|
||||
AffineTransform at0 = graphics.getTransform();
|
||||
AffineTransform at = graphics.getTransform();
|
||||
graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true);
|
||||
|
||||
// apply rotation and flipping
|
||||
shape.applyTransform(graphics);
|
||||
|
||||
shape.applyTransform(graphics);
|
||||
shape.draw(graphics);
|
||||
|
||||
// restore the coordinate system
|
||||
graphics.setTransform(at0);
|
||||
graphics.setTransform(at);
|
||||
graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
|
||||
package org.apache.poi.xslf.usermodel;
|
||||
|
||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||
import org.apache.poi.util.Beta;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
@ -76,11 +77,10 @@ public class XSLFImageRendener {
|
|||
public boolean drawImage(Graphics2D graphics, XSLFPictureData data,
|
||||
Rectangle2D anchor) {
|
||||
try {
|
||||
BufferedImage img = readImage(new ByteArrayInputStream(data.getData()));
|
||||
if (img != null){
|
||||
graphics.drawImage(img, (int) anchor.getX(), (int) anchor.getY(),
|
||||
(int) anchor.getWidth(), (int) anchor.getHeight(), null);
|
||||
}
|
||||
BufferedImage img = ImageIO.read(data.getPackagePart().getInputStream());
|
||||
graphics.drawImage(img,
|
||||
(int) anchor.getX(), (int) anchor.getY(),
|
||||
(int) anchor.getWidth(), (int) anchor.getHeight(), null);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
|
@ -89,12 +89,13 @@ public class XSLFImageRendener {
|
|||
}
|
||||
|
||||
/**
|
||||
* create a buffered image from input stream
|
||||
* Create a buffered image from the supplied package part.
|
||||
* This method is called to create texture paints.
|
||||
*
|
||||
* @return a <code>BufferedImage</code> containing the decoded
|
||||
* contents of the input, or <code>null</code>.
|
||||
*/
|
||||
public BufferedImage readImage(InputStream is) throws IOException {
|
||||
return ImageIO.read(is);
|
||||
public BufferedImage readImage(PackagePart packagePart) throws IOException {
|
||||
return ImageIO.read(packagePart.getInputStream());
|
||||
}
|
||||
}
|
|
@ -75,4 +75,9 @@ public final class XSLFNotes extends XSLFSheet {
|
|||
protected String getRootElementName(){
|
||||
return "notes";
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSLFSheet getMasterSheet() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMaster;
|
|||
import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Notes master object associated with this layout.
|
||||
|
@ -45,8 +44,6 @@ import java.util.Map;
|
|||
@Beta
|
||||
public class XSLFNotesMaster extends XSLFSheet {
|
||||
private CTNotesMaster _slide;
|
||||
private Map<String, XSLFSlideLayout> _layouts;
|
||||
private XSLFTheme _theme;
|
||||
|
||||
XSLFNotesMaster() {
|
||||
super();
|
||||
|
@ -70,4 +67,10 @@ import java.util.Map;
|
|||
protected String getRootElementName(){
|
||||
return "notesMaster";
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSLFSheet getMasterSheet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -33,12 +33,14 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
|
|||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPictureNonVisual;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
/**
|
||||
* Represents a picture shape
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
@Beta
|
||||
|
@ -114,37 +116,14 @@ public class XSLFPictureShape extends XSLFSimpleShape {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D graphics){
|
||||
java.awt.Shape outline = getOutline();
|
||||
|
||||
// shadow
|
||||
XSLFShadow shadow = getShadow();
|
||||
|
||||
Paint fill = getFill(graphics);
|
||||
Paint line = getLinePaint(graphics);
|
||||
if(shadow != null) {
|
||||
shadow.draw(graphics);
|
||||
}
|
||||
|
||||
if(fill != null) {
|
||||
graphics.setPaint(fill);
|
||||
graphics.fill(outline);
|
||||
}
|
||||
|
||||
public void drawContent(Graphics2D graphics) {
|
||||
|
||||
XSLFPictureData data = getPictureData();
|
||||
if(data == null) return;
|
||||
|
||||
|
||||
XSLFImageRendener renderer = (XSLFImageRendener)graphics.getRenderingHint(XSLFRenderingHint.IMAGE_RENDERER);
|
||||
if(renderer == null) renderer = new XSLFImageRendener();
|
||||
|
||||
renderer.drawImage(graphics, data, getAnchor());
|
||||
|
||||
if (line != null){
|
||||
graphics.setPaint(line);
|
||||
applyStroke(graphics);
|
||||
graphics.draw(outline);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
package org.apache.poi.xslf.usermodel;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.RenderingHints;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -38,5 +38,37 @@ public class XSLFRenderingHint extends RenderingHints.Key {
|
|||
|
||||
public static final XSLFRenderingHint GSAVE = new XSLFRenderingHint(1);
|
||||
public static final XSLFRenderingHint GRESTORE = new XSLFRenderingHint(2);
|
||||
|
||||
/**
|
||||
* Use a custom image rendener
|
||||
*
|
||||
* @see XSLFImageRendener
|
||||
*/
|
||||
public static final XSLFRenderingHint IMAGE_RENDERER = new XSLFRenderingHint(3);
|
||||
|
||||
/**
|
||||
* how to render text:
|
||||
*
|
||||
* {@link #TEXT_MODE_CHARACTERS} (default) means to draw via
|
||||
* {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}.
|
||||
* This mode draws text as characters. Use it if the target graphics writes the actual
|
||||
* character codes instead of glyph outlines (PDFGraphics2D, SVGGraphics2D, etc.)
|
||||
*
|
||||
* {@link #TEXT_MODE_GLYPHS} means to render via
|
||||
* {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}.
|
||||
* This mode draws glyphs as shapes and provides some advanced capabilities such as
|
||||
* justification and font substitution. Use it if the target graphics is an image.
|
||||
*
|
||||
*/
|
||||
public static final XSLFRenderingHint TEXT_RENDERING_MODE = new XSLFRenderingHint(4);
|
||||
|
||||
/**
|
||||
* draw text via {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}
|
||||
*/
|
||||
public static final int TEXT_MODE_CHARACTERS = 1;
|
||||
|
||||
/**
|
||||
* draw text via {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}
|
||||
*/
|
||||
public static final int TEXT_MODE_GLYPHS = 2;
|
||||
}
|
|
@ -19,8 +19,11 @@ package org.apache.poi.xslf.usermodel;
|
|||
|
||||
import org.apache.poi.util.Units;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
|
@ -37,36 +40,44 @@ public class XSLFShadow extends XSLFSimpleShape {
|
|||
_parent = parentShape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D graphics) {
|
||||
Shape outline = _parent.getOutline();
|
||||
|
||||
Paint parentFillColor = _parent.getFill(graphics);
|
||||
Paint parentLineColor = _parent.getLinePaint(graphics);
|
||||
public void fill(Graphics2D graphics, Shape outline) {
|
||||
|
||||
double angle = getAngle();
|
||||
double dist = getDistance();
|
||||
double dx = dist * Math.cos( Math.toRadians(angle));
|
||||
double dy = dist * Math.sin( Math.toRadians(angle));
|
||||
double dx = dist * Math.cos(Math.toRadians(angle));
|
||||
double dy = dist * Math.sin(Math.toRadians(angle));
|
||||
|
||||
graphics.translate(dx, dy);
|
||||
|
||||
Color fillColor = getFillColor();
|
||||
if (fillColor != null) {
|
||||
graphics.setColor(fillColor);
|
||||
}
|
||||
|
||||
if(parentFillColor != null) {
|
||||
graphics.fill(outline);
|
||||
}
|
||||
if(parentLineColor != null) {
|
||||
_parent.applyStroke(graphics);
|
||||
graphics.draw(outline);
|
||||
}
|
||||
}
|
||||
|
||||
graphics.translate(-dx, -dy);
|
||||
}
|
||||
|
||||
public void draw(Graphics2D graphics, Shape outline) {
|
||||
|
||||
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);
|
||||
|
||||
Color fillColor = getFillColor();
|
||||
if (fillColor != null) {
|
||||
graphics.setColor(fillColor);
|
||||
graphics.draw(outline);
|
||||
}
|
||||
|
||||
graphics.translate(-dx, -dy);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Rectangle2D getAnchor(){
|
||||
return _parent.getAnchor();
|
||||
|
@ -112,6 +123,11 @@ public class XSLFShadow extends XSLFSimpleShape {
|
|||
public Color getFillColor() {
|
||||
XSLFTheme theme = getSheet().getTheme();
|
||||
CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
|
||||
return ct == null ? null : new XSLFColor(ct, theme).getColor();
|
||||
if(ct == null) {
|
||||
return null;
|
||||
} else {
|
||||
CTSchemeColor phClr = ct.getSchemeClr();
|
||||
return new XSLFColor(ct, theme, phClr).getColor();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,24 +22,54 @@ package org.apache.poi.xslf.usermodel;
|
|||
import org.apache.poi.util.Beta;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
/**
|
||||
* Base super-class class for all shapes in PresentationML
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
@Beta
|
||||
public abstract class XSLFShape {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the position of this shape within the drawing canvas.
|
||||
* The coordinates are expressed in points
|
||||
*/
|
||||
public abstract Rectangle2D getAnchor();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param anchor the position of this shape within the drawing canvas.
|
||||
* The coordinates are expressed in points
|
||||
*/
|
||||
public abstract void setAnchor(Rectangle2D anchor);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the xml bean holding this shape's data
|
||||
*/
|
||||
public abstract XmlObject getXmlObject();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return human-readable name of this shape, e.g. "Rectange 3"
|
||||
*/
|
||||
public abstract String getShapeName();
|
||||
|
||||
/**
|
||||
* Returns a unique identifier for this shape within the current document.
|
||||
* This ID may be used to assist in uniquely identifying this object so that it can
|
||||
* be referred to by other parts of the document.
|
||||
* <p>
|
||||
* If multiple objects within the same document share the same id attribute value,
|
||||
* then the document shall be considered non-conformant.
|
||||
* </p>
|
||||
*
|
||||
* @return unique id of this shape
|
||||
*/
|
||||
public abstract int getShapeId();
|
||||
|
||||
/**
|
||||
|
@ -64,8 +94,16 @@ public abstract class XSLFShape {
|
|||
*/
|
||||
public abstract double getRotation();
|
||||
|
||||
/**
|
||||
* @param flip whether the shape is horizontally flipped
|
||||
*/
|
||||
public abstract void setFlipHorizontal(boolean flip);
|
||||
|
||||
/**
|
||||
* Whether the shape is vertically flipped
|
||||
*
|
||||
* @param flip whether the shape is vertically flipped
|
||||
*/
|
||||
public abstract void setFlipVertical(boolean flip);
|
||||
|
||||
/**
|
||||
|
@ -75,14 +113,25 @@ public abstract class XSLFShape {
|
|||
*/
|
||||
public abstract boolean getFlipHorizontal();
|
||||
|
||||
/**
|
||||
* Whether the shape is vertically flipped
|
||||
*
|
||||
* @return whether the shape is vertically flipped
|
||||
*/
|
||||
public abstract boolean getFlipVertical();
|
||||
|
||||
/**
|
||||
* Draw this shape into the supplied canvas
|
||||
*
|
||||
* @param graphics the graphics to draw into
|
||||
*/
|
||||
public abstract void draw(Graphics2D graphics);
|
||||
|
||||
protected java.awt.Shape getOutline(){
|
||||
return getAnchor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply 2-D transforms before drawing this shape. This includes rotation and flipping.
|
||||
*
|
||||
* @param graphics the graphics whos transform matrix will be modified
|
||||
*/
|
||||
protected void applyTransform(Graphics2D graphics){
|
||||
Rectangle2D anchor = getAnchor();
|
||||
|
||||
|
@ -112,5 +161,5 @@ public abstract class XSLFShape {
|
|||
graphics.translate(-anchor.getX(), -anchor.getY());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -21,9 +21,9 @@ 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.drawingml.x2006.main.CTTextListStyle;
|
||||
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
|
||||
|
@ -34,22 +34,25 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
|
|||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import java.awt.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Beta
|
||||
public abstract class XSLFSheet extends POIXMLDocumentPart {
|
||||
public abstract class XSLFSheet extends POIXMLDocumentPart implements Iterable<XSLFShape> {
|
||||
private XSLFCommonSlideData _commonSlideData;
|
||||
private XSLFDrawing _drawing;
|
||||
private List<XSLFShape> _shapes;
|
||||
private CTGroupShape _spTree;
|
||||
|
||||
private List<XSLFTextShape>_placeholders;
|
||||
private Map<Integer, XSLFSimpleShape> _placeholderByIdMap;
|
||||
private Map<Integer, XSLFSimpleShape> _placeholderByTypeMap;
|
||||
|
||||
|
@ -61,6 +64,10 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
|
|||
super(part, rel);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the XMLSlideShow this sheet belongs to
|
||||
*/
|
||||
public XMLSlideShow getSlideShow() {
|
||||
POIXMLDocumentPart p = getParent();
|
||||
while(p != null) {
|
||||
|
@ -69,7 +76,7 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
|
|||
}
|
||||
p = p.getParent();
|
||||
}
|
||||
return null;
|
||||
throw new IllegalStateException("SlideShow was not found");
|
||||
}
|
||||
|
||||
protected List<XSLFShape> buildShapes(CTGroupShape spTree){
|
||||
|
@ -92,11 +99,16 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
|
|||
return shapes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return top-level Xml bean representing this sheet
|
||||
*/
|
||||
public abstract XmlObject getXmlObject();
|
||||
|
||||
@Internal
|
||||
public XSLFCommonSlideData getCommonSlideData() {
|
||||
return _commonSlideData;
|
||||
}
|
||||
|
||||
protected void setCommonSlideData(CTCommonSlideData data) {
|
||||
if(data == null) {
|
||||
_commonSlideData = null;
|
||||
|
@ -180,10 +192,34 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
|
|||
return sh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the shapes in this sheet
|
||||
*
|
||||
* @return an array of all shapes in this sheet
|
||||
*/
|
||||
public XSLFShape[] getShapes(){
|
||||
return getShapeList().toArray(new XSLFShape[_shapes.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the shapes in this sheet
|
||||
*
|
||||
* @return an iterator over the shapes in this sheet
|
||||
*/
|
||||
public Iterator<XSLFShape> iterator(){
|
||||
return getShapeList().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified shape from this sheet, if it is present
|
||||
* (optional operation). If this sheet does not contain the element,
|
||||
* it is unchanged.
|
||||
*
|
||||
* @param xShape shape to be removed from this sheet, if present
|
||||
* @return <tt>true</tt> if this sheet contained the specified element
|
||||
* @throws IllegalArgumentException if the type of the specified shape
|
||||
* is incompatible with this sheet (optional)
|
||||
*/
|
||||
public boolean removeShape(XSLFShape xShape) {
|
||||
XmlObject obj = xShape.getXmlObject();
|
||||
CTGroupShape spTree = getSpTree();
|
||||
|
@ -199,10 +235,6 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
|
|||
return getShapeList().remove(xShape);
|
||||
}
|
||||
|
||||
public XSLFBackground getBackground(){
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract String getRootElementName();
|
||||
|
||||
protected CTGroupShape getSpTree(){
|
||||
|
@ -248,22 +280,22 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
|
|||
getXmlObject().set(src.getXmlObject());
|
||||
}
|
||||
|
||||
public XSLFTheme getTheme(){
|
||||
/**
|
||||
* @return theme (shared styles) associated with this theme.
|
||||
* By default returns <code>null</code> which means that this sheet is theme-less.
|
||||
* Sheets that support the notion of themes (slides, masters, layouts, etc.) should override this
|
||||
* method and return the corresposnding package part.
|
||||
*/
|
||||
XSLFTheme getTheme(){
|
||||
return null;
|
||||
}
|
||||
|
||||
public XSLFSlideMaster getSlideMaster(){
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @return master of this sheet.
|
||||
*/
|
||||
public abstract XSLFSheet getMasterSheet();
|
||||
|
||||
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) {
|
||||
|
@ -286,72 +318,107 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
|
|||
return shape;
|
||||
}
|
||||
|
||||
XSLFSimpleShape getPlaceholderById(int id) {
|
||||
if(_placeholderByIdMap == null) {
|
||||
void initPlaceholders() {
|
||||
if(_placeholders == null) {
|
||||
_placeholders = new ArrayList<XSLFTextShape>();
|
||||
_placeholderByIdMap = new HashMap<Integer, XSLFSimpleShape>();
|
||||
_placeholderByTypeMap = new HashMap<Integer, XSLFSimpleShape>();
|
||||
|
||||
for(XSLFShape sh : getShapes()){
|
||||
if(sh instanceof XSLFSimpleShape){
|
||||
XSLFSimpleShape sShape = (XSLFSimpleShape)sh;
|
||||
if(sh instanceof XSLFTextShape){
|
||||
XSLFTextShape sShape = (XSLFTextShape)sh;
|
||||
CTPlaceholder ph = sShape.getCTPlaceholder();
|
||||
if(ph != null && ph.isSetIdx()){
|
||||
int idx = (int)ph.getIdx();
|
||||
_placeholderByIdMap.put(idx, sShape);
|
||||
if(ph != null) {
|
||||
_placeholders.add(sShape);
|
||||
if(ph.isSetIdx()) {
|
||||
int idx = (int)ph.getIdx();
|
||||
_placeholderByIdMap.put(idx, sShape);
|
||||
}
|
||||
if(ph.isSetType()){
|
||||
_placeholderByTypeMap.put(ph.getType().intValue(), sShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XSLFSimpleShape getPlaceholderById(int id) {
|
||||
initPlaceholders();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
initPlaceholders();
|
||||
return _placeholderByTypeMap.get(ordinal);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param idx 0-based index of a placeholder in the sheet
|
||||
* @return placeholder
|
||||
*/
|
||||
public XSLFTextShape getPlaceholder(int idx) {
|
||||
initPlaceholders();
|
||||
return _placeholders.get(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return all placeholder shapes in this sheet
|
||||
*/
|
||||
public XSLFTextShape[] getPlaceholders() {
|
||||
initPlaceholders();
|
||||
return _placeholders.toArray(new XSLFTextShape[_placeholders.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this <code>sheet</code> displays the specified shape.
|
||||
*
|
||||
* Subclasses can override it and skip certain shapes from drawings.
|
||||
* Subclasses can override it and skip certain shapes from drawings,
|
||||
* for instance, slide masters and layouts don't display placeholders
|
||||
*/
|
||||
protected boolean canDraw(XSLFShape shape){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return whether shapes on the master sheet should be shown. By default master graphics is turned off.
|
||||
* Sheets that support the notion of master (slide, slideLayout) should override it and
|
||||
* check this setting in the sheet XML
|
||||
*/
|
||||
public boolean getFollowMasterGraphics(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this sheet into the supplied graphics object
|
||||
*
|
||||
* @param graphics
|
||||
*/
|
||||
public void draw(Graphics2D graphics){
|
||||
XSLFBackground bg = getBackground();
|
||||
if(bg != null) bg.draw(graphics);
|
||||
XSLFSheet master = getMasterSheet();
|
||||
if(getFollowMasterGraphics() && master != null) master.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();
|
||||
AffineTransform at = graphics.getTransform();
|
||||
|
||||
// concrete implementations can make sense of this hint,
|
||||
// for example PSGraphics2D or PDFGraphics2D would call gsave() / grestore
|
||||
graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true);
|
||||
|
||||
// apply rotation and flipping
|
||||
shape.applyTransform(graphics);
|
||||
|
||||
// draw stuff
|
||||
shape.draw(graphics);
|
||||
|
||||
// restore the coordinate system
|
||||
graphics.setTransform(at0);
|
||||
graphics.setTransform(at);
|
||||
|
||||
graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true);
|
||||
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
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.Beta;
|
||||
import org.apache.poi.util.Units;
|
||||
import org.apache.poi.xslf.model.PropertyFetcher;
|
||||
|
@ -28,36 +26,50 @@ import org.apache.poi.xslf.model.geom.Context;
|
|||
import org.apache.poi.xslf.model.geom.CustomGeometry;
|
||||
import org.apache.poi.xslf.model.geom.Guide;
|
||||
import org.apache.poi.xslf.model.geom.IAdjustableShape;
|
||||
import org.apache.poi.xslf.model.geom.Outline;
|
||||
import org.apache.poi.xslf.model.geom.Path;
|
||||
import org.apache.poi.xslf.model.geom.PresetGeometries;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.*;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;
|
||||
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.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.presentationml.x2006.main.CTPlaceholder;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Color;
|
||||
import java.awt.TexturePaint;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Stroke;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a single (non-group) shape in a .pptx slide show
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
@Beta
|
||||
public abstract class XSLFSimpleShape extends XSLFShape {
|
||||
|
||||
private final XmlObject _shape;
|
||||
private final XSLFSheet _sheet;
|
||||
private CTShapeProperties _spPr;
|
||||
|
@ -70,10 +82,15 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
_sheet = sheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlObject getXmlObject() {
|
||||
return _shape;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the sheet this shape belongs to
|
||||
*/
|
||||
public XSLFSheet getSheet() {
|
||||
return _sheet;
|
||||
}
|
||||
|
@ -88,10 +105,12 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
return stEnum == null ? 0 : stEnum.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShapeName() {
|
||||
return getNvPr().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShapeId() {
|
||||
return (int) getNvPr().getId();
|
||||
}
|
||||
|
@ -132,22 +151,22 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
return _spStyle;
|
||||
}
|
||||
|
||||
protected CTPlaceholder getCTPlaceholder(){
|
||||
if(_ph == null){
|
||||
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];
|
||||
if (obj.length == 1) {
|
||||
_ph = (CTPlaceholder) obj[0];
|
||||
}
|
||||
}
|
||||
return _ph;
|
||||
}
|
||||
|
||||
private CTTransform2D getXfrm(){
|
||||
PropertyFetcher<CTTransform2D> fetcher = new PropertyFetcher<CTTransform2D>(){
|
||||
public boolean fetch(XSLFSimpleShape shape){
|
||||
private CTTransform2D getXfrm() {
|
||||
PropertyFetcher<CTTransform2D> fetcher = new PropertyFetcher<CTTransform2D>() {
|
||||
public boolean fetch(XSLFSimpleShape shape) {
|
||||
CTShapeProperties pr = shape.getSpPr();
|
||||
if(pr.isSetXfrm()){
|
||||
if (pr.isSetXfrm()) {
|
||||
setValue(pr.getXfrm());
|
||||
return true;
|
||||
}
|
||||
|
@ -158,10 +177,11 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
return fetcher.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle2D getAnchor() {
|
||||
|
||||
CTTransform2D xfrm = getXfrm();
|
||||
|
||||
|
||||
CTPoint2D off = xfrm.getOff();
|
||||
long x = off.getX();
|
||||
long y = off.getY();
|
||||
|
@ -173,6 +193,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
Units.toPoints(cx), Units.toPoints(cy));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnchor(Rectangle2D anchor) {
|
||||
CTShapeProperties spPr = getSpPr();
|
||||
CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
|
||||
|
@ -189,64 +210,46 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
ext.setCy(cy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
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).
|
||||
* </p>
|
||||
*
|
||||
* @return rotation angle in degrees
|
||||
*/
|
||||
@Override
|
||||
public double getRotation() {
|
||||
CTTransform2D xfrm = getXfrm();
|
||||
return (double) xfrm.getRot() / 60000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlipHorizontal(boolean flip) {
|
||||
CTShapeProperties spPr = getSpPr();
|
||||
CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm();
|
||||
xfrm.setFlipH(flip);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
public boolean getFlipHorizontal() {
|
||||
return getXfrm().getFlipH();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFlipVertical() {
|
||||
return getXfrm().getFlipV();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get line properties defined in the theme (if any)
|
||||
* Get default line properties defined in the theme (if any).
|
||||
* Used internally to resolve shape properties.
|
||||
*
|
||||
* @return line propeties from the theme of null
|
||||
*/
|
||||
|
@ -262,6 +265,10 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
return ln;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param color the color to paint the shape outline.
|
||||
* A <code>null</code> value turns off the shape outline.
|
||||
*/
|
||||
public void setLineColor(Color color) {
|
||||
CTShapeProperties spPr = getSpPr();
|
||||
if (color == null) {
|
||||
|
@ -281,48 +288,24 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the color of the shape outline or <code>null</code>
|
||||
* if outline is turned off
|
||||
*/
|
||||
public Color getLineColor() {
|
||||
Paint paint = getLinePaint(null);
|
||||
if(paint instanceof Color){
|
||||
return (Color)paint;
|
||||
RenderableShape rShape = new RenderableShape(this);
|
||||
Paint paint = rShape.getLinePaint(null);
|
||||
if (paint instanceof Color) {
|
||||
return (Color) paint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Paint getLinePaint(final Graphics2D graphics) {
|
||||
final XSLFTheme theme = _sheet.getTheme();
|
||||
final Color nofill = new Color(0,0,0,0);
|
||||
PropertyFetcher<Paint> fetcher = new PropertyFetcher<Paint>(){
|
||||
public boolean fetch(XSLFSimpleShape shape){
|
||||
CTLineProperties spPr = shape.getSpPr().getLn();
|
||||
if (spPr != null) {
|
||||
if (spPr.isSetNoFill()) {
|
||||
setValue(nofill); // use it as 'nofill' value
|
||||
return true;
|
||||
}
|
||||
Paint paint = getPaint(graphics, spPr);
|
||||
if (paint != null) {
|
||||
setValue( paint );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
};
|
||||
fetchShapeProperty(fetcher);
|
||||
|
||||
Paint 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) {
|
||||
color = new XSLFColor(style.getLnRef(), theme).getColor();
|
||||
}
|
||||
}
|
||||
return color == nofill ? null : color;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param width line width in points. <code>0</code> means no line
|
||||
*/
|
||||
public void setLineWidth(double width) {
|
||||
CTShapeProperties spPr = getSpPr();
|
||||
if (width == 0.) {
|
||||
|
@ -335,9 +318,13 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return line width in points. <code>0</code> means no line.
|
||||
*/
|
||||
public double getLineWidth() {
|
||||
PropertyFetcher<Double> fetcher = new PropertyFetcher<Double>(){
|
||||
public boolean fetch(XSLFSimpleShape shape){
|
||||
PropertyFetcher<Double> fetcher = new PropertyFetcher<Double>() {
|
||||
public boolean fetch(XSLFSimpleShape shape) {
|
||||
CTShapeProperties spPr = shape.getSpPr();
|
||||
CTLineProperties ln = spPr.getLn();
|
||||
if (ln != null) {
|
||||
|
@ -347,7 +334,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
}
|
||||
|
||||
if (ln.isSetW()) {
|
||||
setValue( Units.toPoints(ln.getW()) );
|
||||
setValue(Units.toPoints(ln.getW()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -357,7 +344,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
fetchShapeProperty(fetcher);
|
||||
|
||||
double lineWidth = 0;
|
||||
if(fetcher.getValue() == null) {
|
||||
if (fetcher.getValue() == null) {
|
||||
CTLineProperties defaultLn = getDefaultLineProperties();
|
||||
if (defaultLn != null) {
|
||||
if (defaultLn.isSetW()) lineWidth = Units.toPoints(defaultLn.getW());
|
||||
|
@ -369,6 +356,10 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
return lineWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dash a preset line dashing scheme to stroke thr shape outline
|
||||
*/
|
||||
public void setLineDash(LineDash dash) {
|
||||
CTShapeProperties spPr = getSpPr();
|
||||
if (dash == null) {
|
||||
|
@ -384,16 +375,19 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a preset line dashing scheme to stroke thr shape outline
|
||||
*/
|
||||
public LineDash getLineDash() {
|
||||
|
||||
PropertyFetcher<LineDash> fetcher = new PropertyFetcher<LineDash>(){
|
||||
public boolean fetch(XSLFSimpleShape shape){
|
||||
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] );
|
||||
setValue(LineDash.values()[ctDash.getVal().intValue() - 1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -403,7 +397,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
fetchShapeProperty(fetcher);
|
||||
|
||||
LineDash dash = fetcher.getValue();
|
||||
if(dash == null){
|
||||
if (dash == null) {
|
||||
CTLineProperties defaultLn = getDefaultLineProperties();
|
||||
if (defaultLn != null) {
|
||||
CTPresetLineDashProperties ctDash = defaultLn.getPrstDash();
|
||||
|
@ -415,6 +409,10 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
return dash;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cap the line end cap style
|
||||
*/
|
||||
public void setLineCap(LineCap cap) {
|
||||
CTShapeProperties spPr = getSpPr();
|
||||
if (cap == null) {
|
||||
|
@ -427,15 +425,19 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the line end cap style
|
||||
*/
|
||||
public LineCap getLineCap() {
|
||||
PropertyFetcher<LineCap> fetcher = new PropertyFetcher<LineCap>(){
|
||||
public boolean fetch(XSLFSimpleShape shape){
|
||||
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] );
|
||||
setValue(LineCap.values()[stCap.intValue() - 1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -445,7 +447,7 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
fetchShapeProperty(fetcher);
|
||||
|
||||
LineCap cap = fetcher.getValue();
|
||||
if(cap == null){
|
||||
if (cap == null) {
|
||||
CTLineProperties defaultLn = getDefaultLineProperties();
|
||||
if (defaultLn != null) {
|
||||
STLineCap.Enum stCap = defaultLn.getCap();
|
||||
|
@ -469,10 +471,10 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
if (color == null) {
|
||||
if (spPr.isSetSolidFill()) spPr.unsetSolidFill();
|
||||
|
||||
if(!spPr.isSetNoFill()) spPr.addNewNoFill();
|
||||
if (!spPr.isSetNoFill()) spPr.addNewNoFill();
|
||||
} else {
|
||||
if(spPr.isSetNoFill()) spPr.unsetNoFill();
|
||||
|
||||
if (spPr.isSetNoFill()) spPr.unsetNoFill();
|
||||
|
||||
CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr
|
||||
.getSolidFill() : spPr.addNewSolidFill();
|
||||
|
||||
|
@ -485,55 +487,24 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return solid fill color of null if not set
|
||||
* @return solid fill color of null if not set or fill color
|
||||
* is not solid (pattern or gradient)
|
||||
*/
|
||||
public Color getFillColor() {
|
||||
Paint paint = getFill(null);
|
||||
if(paint instanceof Color){
|
||||
return (Color)paint;
|
||||
RenderableShape rShape = new RenderableShape(this);
|
||||
Paint paint = rShape.getFillPaint(null);
|
||||
if (paint instanceof Color) {
|
||||
return (Color) paint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch shape fill as a java.awt.Paint
|
||||
*
|
||||
* @return either Color or GradientPaint or TexturePaint or null
|
||||
* @return shadow of this shape or null if shadow is disabled
|
||||
*/
|
||||
Paint getFill(final Graphics2D graphics) {
|
||||
final XSLFTheme theme = _sheet.getTheme();
|
||||
final Color nofill = new Color(0xFF,0xFF,0xFF, 0);
|
||||
PropertyFetcher<Paint> fetcher = new PropertyFetcher<Paint>(){
|
||||
public boolean fetch(XSLFSimpleShape shape){
|
||||
CTShapeProperties spPr = shape.getSpPr();
|
||||
if (spPr.isSetNoFill()) {
|
||||
setValue(nofill); // use it as 'nofill' value
|
||||
return true;
|
||||
}
|
||||
Paint paint = getPaint(graphics, spPr);
|
||||
if (paint != null) {
|
||||
setValue( paint );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
fetchShapeProperty(fetcher);
|
||||
|
||||
Paint paint = fetcher.getValue();
|
||||
if(paint == null){
|
||||
// fill color was not found, check if it is defined in the theme
|
||||
CTShapeStyle style = getSpStyle();
|
||||
if (style != null) {
|
||||
paint = new XSLFColor(style.getFillRef(), theme).getColor();
|
||||
}
|
||||
}
|
||||
return paint == nofill ? null : paint;
|
||||
}
|
||||
|
||||
public XSLFShadow getShadow(){
|
||||
PropertyFetcher<CTOuterShadowEffect> fetcher = new PropertyFetcher<CTOuterShadowEffect>(){
|
||||
public boolean fetch(XSLFSimpleShape shape){
|
||||
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();
|
||||
|
@ -546,233 +517,48 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
fetchShapeProperty(fetcher);
|
||||
|
||||
CTOuterShadowEffect obj = fetcher.getValue();
|
||||
if(obj == null){
|
||||
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();
|
||||
if(idx != 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D graphics) {
|
||||
|
||||
RenderableShape rShape = new RenderableShape(this);
|
||||
rShape.render(graphics);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // getXYZArray() array accessors are deprecated
|
||||
protected Paint getPaint(Graphics2D graphics, XmlObject spPr) {
|
||||
XSLFTheme theme = getSheet().getTheme();
|
||||
Rectangle2D anchor = getAnchor();
|
||||
|
||||
Paint paint = null;
|
||||
for(XmlObject obj : spPr.selectPath("*")){
|
||||
if(obj instanceof CTNoFillProperties){
|
||||
paint = null;
|
||||
break;
|
||||
}
|
||||
if(obj instanceof CTSolidColorFillProperties){
|
||||
CTSolidColorFillProperties solidFill = (CTSolidColorFillProperties)obj;
|
||||
XSLFColor c = new XSLFColor(solidFill, theme);
|
||||
paint = c.getColor();
|
||||
}
|
||||
if(obj instanceof CTBlipFillProperties){
|
||||
CTBlipFillProperties blipFill = (CTBlipFillProperties)obj;
|
||||
CTBlip blip = blipFill.getBlip();
|
||||
String blipId = blip.getEmbed();
|
||||
PackagePart p = getSheet().getPackagePart();
|
||||
PackageRelationship rel = p.getRelationship(blipId);
|
||||
if (rel != null) {
|
||||
XSLFImageRendener renderer = null;
|
||||
if(graphics != null) renderer = (XSLFImageRendener)graphics.getRenderingHint(XSLFRenderingHint.IMAGE_RENDERER);
|
||||
if(renderer == null) renderer = new XSLFImageRendener();
|
||||
|
||||
try {
|
||||
BufferedImage img = renderer.readImage(p.getRelatedPart(rel).getInputStream());
|
||||
if(blip.sizeOfAlphaModFixArray() > 0){
|
||||
float alpha = blip.getAlphaModFixArray(0).getAmt()/100000.f;
|
||||
AlphaComposite ac = AlphaComposite.getInstance(
|
||||
AlphaComposite.SRC_OVER, alpha);
|
||||
if(graphics != null) graphics.setComposite(ac);
|
||||
}
|
||||
|
||||
paint = new TexturePaint(
|
||||
img, new Rectangle2D.Double(0, 0, img.getWidth(), img.getHeight()));
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(obj instanceof CTGradientFillProperties){
|
||||
CTGradientFillProperties gradFill = (CTGradientFillProperties)obj;
|
||||
double angle;
|
||||
if(gradFill.isSetLin()) {
|
||||
angle = gradFill.getLin().getAng() / 60000;
|
||||
} else {
|
||||
// XSLF only supports linear gradient fills. Other types are filled as liner with angle=90 degrees
|
||||
angle = 90;
|
||||
}
|
||||
CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
|
||||
|
||||
Arrays.sort(gs, new Comparator<CTGradientStop>(){
|
||||
public int compare(CTGradientStop o1, CTGradientStop o2){
|
||||
Integer pos1 = o1.getPos();
|
||||
Integer pos2 = o2.getPos();
|
||||
return pos1.compareTo(pos2);
|
||||
}
|
||||
});
|
||||
|
||||
Color[] colors = new Color[gs.length];
|
||||
float[] fractions = new float[gs.length];
|
||||
|
||||
AffineTransform at = AffineTransform.getRotateInstance(
|
||||
Math.toRadians(angle),
|
||||
anchor.getX() + anchor.getWidth()/2,
|
||||
anchor.getY() + anchor.getHeight()/2);
|
||||
|
||||
double diagonal = Math.sqrt(anchor.getHeight()*anchor.getHeight() + anchor.getWidth()*anchor.getWidth());
|
||||
Point2D p1 = new Point2D.Double(anchor.getX() + anchor.getWidth()/2 - diagonal/2,
|
||||
anchor.getY() + anchor.getHeight()/2);
|
||||
p1 = at.transform(p1, null);
|
||||
|
||||
Point2D p2 = new Point2D.Double(anchor.getX() + anchor.getWidth(), anchor.getY() + anchor.getHeight()/2);
|
||||
p2 = at.transform(p2, null);
|
||||
|
||||
norm(p1, anchor);
|
||||
norm(p2, anchor);
|
||||
|
||||
for(int i = 0; i < gs.length; i++){
|
||||
CTGradientStop stop = gs[i];
|
||||
colors[i] = new XSLFColor(stop, theme).getColor();
|
||||
fractions[i] = stop.getPos() / 100000.f;
|
||||
}
|
||||
|
||||
paint = createGradientPaint(p1, p2, fractions, colors);
|
||||
}
|
||||
}
|
||||
return paint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trick to return GradientPaint on JDK 1.5 and LinearGradientPaint on JDK 1.6+
|
||||
*/
|
||||
private Paint createGradientPaint(Point2D p1, Point2D p2, float[] fractions, Color[] colors){
|
||||
Paint paint;
|
||||
try {
|
||||
Class clz = Class.forName("java.awt.LinearGradientPaint");
|
||||
Constructor c =
|
||||
clz.getConstructor(Point2D.class, Point2D.class, float[].class, Color[].class);
|
||||
paint = (Paint)c.newInstance(p1, p2, fractions, colors);
|
||||
} catch (ClassNotFoundException e){
|
||||
paint = new GradientPaint(p1, colors[0], p2, colors[colors.length - 1]);
|
||||
} catch (Exception e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return paint;
|
||||
}
|
||||
|
||||
void norm(Point2D p, Rectangle2D anchor){
|
||||
if(p.getX() < anchor.getX()){
|
||||
p.setLocation(anchor.getX(), p.getY());
|
||||
} else if(p.getX() > (anchor.getX() + anchor.getWidth())){
|
||||
p.setLocation(anchor.getX() + anchor.getWidth(), p.getY());
|
||||
}
|
||||
|
||||
if(p.getY() < anchor.getY()){
|
||||
p.setLocation(p.getX(), anchor.getY());
|
||||
} else if (p.getY() > (anchor.getY() + anchor.getHeight())){
|
||||
p.setLocation(p.getX(), anchor.getY() + anchor.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
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, Math.max(1, lineWidth), dash,
|
||||
dash_phase);
|
||||
graphics.setStroke(stroke);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk up the inheritance tree and fetch properties.
|
||||
* Walk up the inheritance tree and fetch shape properties.
|
||||
*
|
||||
* slide <-- slideLayout <-- slideMaster
|
||||
* The following order of inheritance is assumed:
|
||||
* <p>
|
||||
* slide <-- slideLayout <-- slideMaster <-- default styles in the slideMaster
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @param visitor the object that collects the desired property
|
||||
* @param visitor the object that collects the desired property
|
||||
* @return true if the property was fetched
|
||||
*/
|
||||
boolean fetchShapeProperty(PropertyFetcher visitor){
|
||||
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) {
|
||||
XSLFSheet layout = getSheet().getMasterSheet();
|
||||
if (layout != null) {
|
||||
if (!ok) {
|
||||
// first try to fetch from the slide layout
|
||||
CTPlaceholder ph = getCTPlaceholder();
|
||||
if (ph != null) {
|
||||
masterShape = layout.getPlaceholder(ph);
|
||||
|
@ -781,96 +567,77 @@ public abstract class XSLFSimpleShape extends XSLFShape {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
// 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);
|
||||
XSLFSheet master = layout.getMasterSheet();
|
||||
if (master != null) {
|
||||
masterShape = master.getPlaceholderByType(textType);
|
||||
if (masterShape != null) {
|
||||
ok = visitor.fetch(masterShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected java.awt.Shape getOutline(){
|
||||
PresetGeometries dict = PresetGeometries.getInstance();
|
||||
/**
|
||||
*
|
||||
* @return definition of the shape geometry
|
||||
*/
|
||||
CustomGeometry getGeometry(){
|
||||
CTShapeProperties spPr = getSpPr();
|
||||
String name;
|
||||
if(spPr.isSetPrstGeom()) {
|
||||
name = spPr.getPrstGeom().getPrst().toString();
|
||||
} else {
|
||||
name = "rect";
|
||||
}
|
||||
CustomGeometry geom = dict.get(name);
|
||||
Rectangle2D anchor = getAnchor();
|
||||
if(geom != null) {
|
||||
// the guides in the shape definitions are all defined relative to each other,
|
||||
// so we build the path starting from (0,0).
|
||||
final Rectangle2D anchorEmu = new Rectangle2D.Double(
|
||||
0,
|
||||
0,
|
||||
Units.toEMU(anchor.getWidth()),
|
||||
Units.toEMU(anchor.getHeight())
|
||||
);
|
||||
|
||||
GeneralPath path = new GeneralPath();
|
||||
Context ctx = new Context(geom, new IAdjustableShape() {
|
||||
public Rectangle2D getAnchor() {
|
||||
return anchorEmu;
|
||||
}
|
||||
|
||||
public Guide getAdjustValue(String name) {
|
||||
CTPresetGeometry2D prst = getSpPr().getPrstGeom();
|
||||
if(prst.isSetAvLst()) {
|
||||
for(CTGeomGuide g : prst.getAvLst().getGdList()){
|
||||
if(g.getName().equals(name)) {
|
||||
return new Guide(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
for(Path p : geom){
|
||||
path.append( p.getPath(ctx) , false);
|
||||
CustomGeometry geom;
|
||||
PresetGeometries dict = PresetGeometries.getInstance();
|
||||
if(spPr.isSetPrstGeom()){
|
||||
String name = spPr.getPrstGeom().getPrst().toString();
|
||||
geom = dict.get(name);
|
||||
if(geom == null) {
|
||||
throw new IllegalStateException("Unknown shape geometry: " + name);
|
||||
}
|
||||
|
||||
// translate the result to the canvas coordinates in points
|
||||
AffineTransform at = new AffineTransform();
|
||||
at.scale(
|
||||
1.0/Units.EMU_PER_POINT, 1.0/Units.EMU_PER_POINT);
|
||||
at.translate(Units.toEMU(anchor.getX()), Units.toEMU(anchor.getY()));
|
||||
return at.createTransformedShape(path);
|
||||
} else if (spPr.isSetCustGeom()){
|
||||
geom = new CustomGeometry(spPr.getCustGeom());
|
||||
} else {
|
||||
return anchor;
|
||||
geom = dict.get("rect");
|
||||
}
|
||||
}
|
||||
return geom;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return any shape-specific geometry that is not included in presetShapeDefinitions.xml
|
||||
* (line decorations, etc)
|
||||
*/
|
||||
List<Outline> getCustomOutlines(){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* draw any content within this shape (image, text, etc.).
|
||||
*
|
||||
* @param graphics the graphics to draw into
|
||||
*/
|
||||
public void drawContent(Graphics2D graphics){
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisua
|
|||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.io.IOException;
|
||||
|
||||
@Beta
|
||||
|
@ -109,11 +109,11 @@ public final class XSLFSlide extends XSLFSheet {
|
|||
return "sld";
|
||||
}
|
||||
|
||||
public XSLFSlideMaster getMasterSheet(){
|
||||
return getSlideLayout().getSlideMaster();
|
||||
@Override
|
||||
public XSLFSlideLayout getMasterSheet(){
|
||||
return getSlideLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSLFSlideLayout getSlideLayout(){
|
||||
if(_layout == null){
|
||||
for (POIXMLDocumentPart p : getRelations()) {
|
||||
|
@ -128,7 +128,6 @@ public final class XSLFSlide extends XSLFSheet {
|
|||
return _layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSLFSlideMaster getSlideMaster(){
|
||||
return getSlideLayout().getSlideMaster();
|
||||
}
|
||||
|
@ -159,20 +158,12 @@ public final class XSLFSlide extends XSLFSheet {
|
|||
}
|
||||
if(_notes == null) {
|
||||
// This slide lacks notes
|
||||
// Not al have them, sorry...
|
||||
// Not all have them, sorry...
|
||||
return null;
|
||||
}
|
||||
return _notes;
|
||||
}
|
||||
|
||||
public void setFollowMasterBackground(boolean value){
|
||||
_slide.setShowMasterSp(value);
|
||||
}
|
||||
|
||||
public boolean getFollowMasterBackground(){
|
||||
return !_slide.isSetShowMasterSp() || _slide.getShowMasterSp();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return title of this slide or empty string if title is not set
|
||||
|
@ -182,27 +173,59 @@ public final class XSLFSlide extends XSLFSheet {
|
|||
return txt == null ? "" : txt.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSLFTheme getTheme(){
|
||||
return getSlideLayout().getSlideMaster().getTheme();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D graphics){
|
||||
/**
|
||||
*
|
||||
* @return the information about background appearance of this slide
|
||||
*/
|
||||
public XSLFBackground getBackground() {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
XSLFSlideLayout layout = getMasterSheet();
|
||||
if(layout.getXmlObject().getCSld().isSetBg()) {
|
||||
return new XSLFBackground(layout.getXmlObject().getCSld().getBg(), this);
|
||||
}
|
||||
|
||||
XSLFSlideMaster master = layout.getMasterSheet();
|
||||
if(master.getXmlObject().getCSld().isSetBg()) {
|
||||
return new XSLFBackground(master.getXmlObject().getCSld().getBg(), this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return whether shapes on the master slide should be shown or not.
|
||||
*/
|
||||
public boolean getFollowMasterGraphics(){
|
||||
return !_slide.isSetShowMasterSp() || _slide.getShowMasterSp();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value whether shapes on the master slide should be shown or not.
|
||||
*/
|
||||
public void setFollowMasterGraphics(boolean value){
|
||||
_slide.setShowMasterSp(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D graphics){
|
||||
|
||||
XSLFBackground bg = getBackground();
|
||||
if(bg != null) bg.draw(graphics);
|
||||
|
||||
super.draw(graphics);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ 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.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideLayout;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldLayoutDocument;
|
||||
|
@ -42,13 +41,13 @@ public class XSLFSlideLayout extends XSLFSheet {
|
|||
public XSLFSlideLayout(PackagePart part, PackageRelationship rel) throws IOException, XmlException {
|
||||
super(part, rel);
|
||||
SldLayoutDocument doc =
|
||||
SldLayoutDocument.Factory.parse(getPackagePart().getInputStream());
|
||||
SldLayoutDocument.Factory.parse(getPackagePart().getInputStream());
|
||||
_layout = doc.getSldLayout();
|
||||
setCommonSlideData(_layout.getCSld());
|
||||
}
|
||||
|
||||
|
||||
public String getName(){
|
||||
public String getName() {
|
||||
return _layout.getCSld().getName();
|
||||
}
|
||||
|
||||
|
@ -61,79 +60,92 @@ public class XSLFSlideLayout extends XSLFSheet {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String getRootElementName(){
|
||||
protected String getRootElementName() {
|
||||
return "sldLayout";
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide master object associated with this layout.
|
||||
* <p>
|
||||
* Within a slide master slide are contained all elements
|
||||
* that describe the objects and their corresponding formatting
|
||||
* for within a presentation slide.
|
||||
* </p>
|
||||
* <p>
|
||||
* Within a slide master slide are two main elements.
|
||||
* The cSld element specifies the common slide elements such as shapes and
|
||||
* their attached text bodies. Then the txStyles element specifies the
|
||||
* formatting for the text within each of these shapes. The other properties
|
||||
* within a slide master slide specify other properties for within a presentation slide
|
||||
* such as color information, headers and footers, as well as timing and
|
||||
* transition information for all corresponding presentation slides.
|
||||
* </p>
|
||||
*
|
||||
* @return slide master. Never null.
|
||||
* @throws IllegalStateException if slide master was not found
|
||||
*/
|
||||
@Override
|
||||
public XSLFSlideMaster getSlideMaster(){
|
||||
if(_master == null){
|
||||
public XSLFSlideMaster getSlideMaster() {
|
||||
if (_master == null) {
|
||||
for (POIXMLDocumentPart p : getRelations()) {
|
||||
if (p instanceof XSLFSlideMaster){
|
||||
_master = (XSLFSlideMaster)p;
|
||||
}
|
||||
}
|
||||
if (p instanceof XSLFSlideMaster) {
|
||||
_master = (XSLFSlideMaster) p;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(_master == null) {
|
||||
if (_master == null) {
|
||||
throw new IllegalStateException("SlideMaster was not found for " + this.toString());
|
||||
}
|
||||
return _master;
|
||||
}
|
||||
|
||||
|
||||
public XSLFTheme getTheme(){
|
||||
return getSlideMaster().getTheme();
|
||||
}
|
||||
@Override
|
||||
public XSLFSlideMaster getMasterSheet() {
|
||||
return getSlideMaster();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSLFTheme getTheme() {
|
||||
return getSlideMaster().getTheme();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CTTextListStyle getTextProperties(Placeholder textType) {
|
||||
XSLFTextShape lp = getTextShapeByType(textType);
|
||||
CTTextListStyle props = lp.getTextBody(false).getLstStyle();
|
||||
return props;
|
||||
public boolean getFollowMasterGraphics() {
|
||||
return !_layout.isSetShowMasterSp() || _layout.getShowMasterSp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this sheet into the supplied graphics object
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected boolean canDraw(XSLFShape shape){
|
||||
if(shape instanceof XSLFSimpleShape){
|
||||
XSLFSimpleShape txt = (XSLFSimpleShape)shape;
|
||||
protected boolean canDraw(XSLFShape shape) {
|
||||
if (shape instanceof XSLFSimpleShape) {
|
||||
XSLFSimpleShape txt = (XSLFSimpleShape) shape;
|
||||
CTPlaceholder ph = txt.getCTPlaceholder();
|
||||
if(ph != null) {
|
||||
if (ph != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSLFBackground getBackground(){
|
||||
if(_layout.getCSld().isSetBg()) {
|
||||
return new XSLFBackground(_layout.getCSld().getBg(), this);
|
||||
/**
|
||||
* Copy placeholders from this layout to the destination slide
|
||||
*
|
||||
* @param slide destination slide
|
||||
*/
|
||||
public void copyLayout(XSLFSlide slide) {
|
||||
for (XSLFShape sh : getShapes()) {
|
||||
if (sh instanceof XSLFTextShape) {
|
||||
XSLFTextShape tsh = (XSLFTextShape) sh;
|
||||
Placeholder ph = tsh.getTextType();
|
||||
if (ph == null) continue;
|
||||
|
||||
switch (ph) {
|
||||
// these are special and not copied by default
|
||||
case DATETIME:
|
||||
case SLIDE_NUMBER:
|
||||
case FOOTER:
|
||||
break;
|
||||
default:
|
||||
slide.getSpTree().addNewSp().set(tsh.getXmlObject().copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
return getSlideMaster().getBackground();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return type of this layout
|
||||
*/
|
||||
public SlideLayout getType(){
|
||||
int ordinal = _layout.getType().intValue() - 1;
|
||||
return SlideLayout.values()[ordinal];
|
||||
}
|
||||
}
|
|
@ -21,7 +21,9 @@ 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.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterTextStyles;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument;
|
||||
|
@ -78,7 +80,12 @@ import java.util.Map;
|
|||
return "sldMaster";
|
||||
}
|
||||
|
||||
public XSLFSlideLayout getLayout(String name){
|
||||
@Override
|
||||
public XSLFSheet getMasterSheet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Map<String, XSLFSlideLayout> getLayouts(){
|
||||
if(_layouts == null){
|
||||
_layouts = new HashMap<String, XSLFSlideLayout>();
|
||||
for (POIXMLDocumentPart p : getRelations()) {
|
||||
|
@ -88,14 +95,36 @@ import java.util.Map;
|
|||
}
|
||||
}
|
||||
}
|
||||
return _layouts.get(name);
|
||||
return _layouts;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return all slide layouts referencing this master
|
||||
*/
|
||||
public XSLFSlideLayout[] getSlideLayouts() {
|
||||
return getLayouts().values().toArray(new XSLFSlideLayout[_layouts.size()]);
|
||||
}
|
||||
|
||||
public XSLFSlideLayout getLayout(SlideLayout type){
|
||||
for(XSLFSlideLayout layout : getLayouts().values()){
|
||||
if(layout.getType() == type) {
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XSLFTheme getTheme(){
|
||||
if(_theme == null){
|
||||
for (POIXMLDocumentPart p : getRelations()) {
|
||||
if (p instanceof XSLFTheme){
|
||||
_theme = (XSLFTheme)p;
|
||||
CTColorMapping cmap = _slide.getClrMap();
|
||||
if(cmap != null){
|
||||
_theme.initColorMap(cmap);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -122,11 +151,20 @@ import java.util.Map;
|
|||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this sheet into the supplied graphics object
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public XSLFBackground getBackground(){
|
||||
if(_slide.getCSld().isSetBg()) {
|
||||
return new XSLFBackground(_slide.getCSld().getBg(), this);
|
||||
protected boolean canDraw(XSLFShape shape){
|
||||
if(shape instanceof XSLFSimpleShape){
|
||||
XSLFSimpleShape txt = (XSLFSimpleShape)shape;
|
||||
CTPlaceholder ph = txt.getCTPlaceholder();
|
||||
if(ph != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -35,7 +35,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth;
|
|||
import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Represents a cell of a table in a .pptx presentation
|
||||
|
@ -77,7 +77,7 @@ public class XSLFTableCell extends XSLFTextShape {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setMarginLeft(double margin){
|
||||
public void setLeftInset(double margin){
|
||||
CTTableCellProperties pr = getXmlObject().getTcPr();
|
||||
if(pr == null) pr = getXmlObject().addNewTcPr();
|
||||
|
||||
|
@ -85,7 +85,7 @@ public class XSLFTableCell extends XSLFTextShape {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setMarginRight(double margin){
|
||||
public void setRightInset(double margin){
|
||||
CTTableCellProperties pr = getXmlObject().getTcPr();
|
||||
if(pr == null) pr = getXmlObject().addNewTcPr();
|
||||
|
||||
|
@ -93,7 +93,7 @@ public class XSLFTableCell extends XSLFTextShape {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setMarginTop(double margin){
|
||||
public void setTopInset(double margin){
|
||||
CTTableCellProperties pr = getXmlObject().getTcPr();
|
||||
if(pr == null) pr = getXmlObject().addNewTcPr();
|
||||
|
||||
|
@ -101,7 +101,7 @@ public class XSLFTableCell extends XSLFTextShape {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setMarginBottom(double margin){
|
||||
public void setBottomInset(double margin){
|
||||
CTTableCellProperties pr = getXmlObject().getTcPr();
|
||||
if(pr == null) pr = getXmlObject().addNewTcPr();
|
||||
|
||||
|
|
|
@ -63,23 +63,4 @@ public class XSLFTextBox extends XSLFAutoShape {
|
|||
|
||||
return ct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that the corresponding shape should be represented by the generating application
|
||||
* as a placeholder. When a shape is considered a placeholder by the generating application
|
||||
* it can have special properties to alert the user that they may enter content into the shape.
|
||||
* Different types of placeholders are allowed and can be specified by using the placeholder
|
||||
* type attribute for this element
|
||||
*
|
||||
* @param placeholder
|
||||
*/
|
||||
public void setPlaceholder(Placeholder placeholder){
|
||||
CTShape sh = (CTShape)getXmlObject();
|
||||
CTApplicationNonVisualDrawingProps nv = sh.getNvSpPr().getNvPr();
|
||||
if(placeholder == null) {
|
||||
if(nv.isSetPh()) nv.unsetPh();
|
||||
} else {
|
||||
nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ordinal() + 1));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,7 +30,8 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
|
|||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.font.LineBreakMeasurer;
|
||||
import java.awt.font.TextAttribute;
|
||||
import java.awt.font.TextLayout;
|
||||
|
@ -80,6 +81,23 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
return out.toString();
|
||||
}
|
||||
|
||||
private String getVisibleText(){
|
||||
StringBuilder out = new StringBuilder();
|
||||
for (XSLFTextRun r : _runs) {
|
||||
String txt = r.getText();
|
||||
switch (r.getTextCap()){
|
||||
case ALL:
|
||||
txt = txt.toUpperCase();
|
||||
break;
|
||||
case SMALL:
|
||||
txt = txt.toLowerCase();
|
||||
break;
|
||||
}
|
||||
out.append(txt);
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Internal
|
||||
public CTTextParagraph getXmlObject(){
|
||||
return _p;
|
||||
|
@ -89,6 +107,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
return _shape;
|
||||
|
||||
}
|
||||
|
||||
public List<XSLFTextRun> getTextRuns(){
|
||||
return _runs;
|
||||
}
|
||||
|
@ -186,7 +205,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getLevel()){
|
||||
public boolean fetch(CTTextParagraphProperties props){
|
||||
if(props.isSetBuClr()){
|
||||
XSLFColor c = new XSLFColor(props.getBuClr(), theme);
|
||||
XSLFColor c = new XSLFColor(props.getBuClr(), theme, null);
|
||||
setValue(c.getColor());
|
||||
return true;
|
||||
}
|
||||
|
@ -496,17 +515,18 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
return "[" + getClass() + "]" + getText();
|
||||
}
|
||||
|
||||
public List<TextFragment> getTextLines(){
|
||||
List<TextFragment> getTextLines(){
|
||||
return _lines;
|
||||
}
|
||||
|
||||
public double draw(Graphics2D graphics, double x, double y){
|
||||
double marginLeft = _shape.getMarginLeft();
|
||||
double marginRight = _shape.getMarginRight();
|
||||
double marginLeft = _shape.getLeftInset();
|
||||
double marginRight = _shape.getRightInset();
|
||||
Rectangle2D anchor = _shape.getAnchor();
|
||||
double penY = y;
|
||||
|
||||
double textOffset = getLeftMargin();
|
||||
boolean firstLine = true;
|
||||
for(TextFragment line : _lines){
|
||||
double penX = x;
|
||||
switch (getTextAlign()) {
|
||||
|
@ -521,7 +541,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
break;
|
||||
}
|
||||
|
||||
if(_bullet != null){
|
||||
if(_bullet != null && firstLine){
|
||||
_bullet.draw(graphics, penX + getIndent(), penY);
|
||||
}
|
||||
line.draw(graphics, penX, penY);
|
||||
|
@ -535,6 +555,8 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
// positive value means absolute spacing in points
|
||||
penY += -spacing;
|
||||
}
|
||||
|
||||
firstLine = false;
|
||||
}
|
||||
return penY - y;
|
||||
}
|
||||
|
@ -551,8 +573,12 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
void draw(Graphics2D graphics, double x, double y){
|
||||
double yBaseline = y + _layout.getAscent();
|
||||
|
||||
graphics.drawString(_str.getIterator(), (float)x, (float)yBaseline );
|
||||
|
||||
Integer textMode = (Integer)graphics.getRenderingHint(XSLFRenderingHint.TEXT_RENDERING_MODE);
|
||||
if(textMode != null && textMode == XSLFRenderingHint.TEXT_MODE_GLYPHS){
|
||||
_layout.draw(graphics, (float)x, (float)yBaseline);
|
||||
} else {
|
||||
graphics.drawString(_str.getIterator(), (float)x, (float)yBaseline );
|
||||
}
|
||||
}
|
||||
|
||||
public float getHeight(){
|
||||
|
@ -564,8 +590,8 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
|
||||
}
|
||||
|
||||
public AttributedString getAttributedString(){
|
||||
String text = getText();
|
||||
AttributedString getAttributedString(Graphics2D graphics){
|
||||
String text = getVisibleText();
|
||||
|
||||
AttributedString string = new AttributedString(text);
|
||||
|
||||
|
@ -579,7 +605,10 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
int endIndex = startIndex + length;
|
||||
|
||||
string.addAttribute(TextAttribute.FOREGROUND, run.getFontColor(), startIndex, endIndex);
|
||||
|
||||
// user can pass an object to convert fonts via a rendering hint
|
||||
string.addAttribute(TextAttribute.FAMILY, run.getFontFamily(), startIndex, endIndex);
|
||||
|
||||
string.addAttribute(TextAttribute.SIZE, (float)run.getFontSize(), startIndex, endIndex);
|
||||
if(run.isBold()) {
|
||||
string.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIndex, endIndex);
|
||||
|
@ -601,6 +630,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
string.addAttribute(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, startIndex, endIndex);
|
||||
}
|
||||
|
||||
|
||||
startIndex = endIndex;
|
||||
}
|
||||
|
||||
|
@ -610,7 +640,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
void breakText(Graphics2D graphics){
|
||||
_lines = new ArrayList<TextFragment>();
|
||||
|
||||
AttributedString at = getAttributedString();
|
||||
AttributedString at = getAttributedString(graphics);
|
||||
AttributedCharacterIterator it = at.getIterator();
|
||||
if(it.getBeginIndex() == it.getEndIndex()) {
|
||||
return;
|
||||
|
@ -628,7 +658,8 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
|
||||
int endIndex = measurer.getPosition();
|
||||
|
||||
if(getTextAlign() == TextAlign.JUSTIFY) {
|
||||
TextAlign hAlign = getTextAlign();
|
||||
if(hAlign == TextAlign.JUSTIFY || hAlign == TextAlign.JUSTIFY_LOW) {
|
||||
layout = layout.getJustifiedLayout((float)wrappingWidth);
|
||||
}
|
||||
|
||||
|
@ -673,7 +704,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
width = _shape.getSheet().getSlideShow().getPageSize().getWidth();
|
||||
} else {
|
||||
width = _shape.getAnchor().getWidth() -
|
||||
_shape.getMarginLeft() - _shape.getMarginRight() - getLeftMargin();
|
||||
_shape.getLeftInset() - _shape.getRightInset() - getLeftMargin();
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
@ -700,7 +731,13 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||
}
|
||||
|
||||
int level = getLevel();
|
||||
XmlObject[] o = _shape.getSheet().getSlideMaster().getXmlObject().selectPath(
|
||||
|
||||
XSLFSheet masterSheet = _shape.getSheet();
|
||||
while (masterSheet.getMasterSheet() != null){
|
||||
masterSheet = masterSheet.getMasterSheet();
|
||||
}
|
||||
|
||||
XmlObject[] o = masterSheet.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");
|
||||
|
|
|
@ -20,14 +20,17 @@ import org.apache.poi.util.Beta;
|
|||
import org.apache.poi.xslf.model.CharacterPropertyFetcher;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Represents a run of text within the containing text body. The run element is the
|
||||
|
@ -70,12 +73,14 @@ public class XSLFTextRun {
|
|||
|
||||
public Color getFontColor(){
|
||||
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
|
||||
CTShapeStyle style = _p.getParentShape().getSpStyle();
|
||||
final CTSchemeColor shapeStyle = style == null ? null : style.getFontRef().getSchemeClr();
|
||||
|
||||
CharacterPropertyFetcher<Color> fetcher = new CharacterPropertyFetcher<Color>(_p.getLevel()){
|
||||
public boolean fetch(CTTextCharacterProperties props){
|
||||
CTSolidColorFillProperties solidFill = props.getSolidFill();
|
||||
if(solidFill != null){
|
||||
Color c = new XSLFColor(solidFill, theme).getColor();
|
||||
if(solidFill != null) {
|
||||
Color c = new XSLFColor(solidFill, theme, shapeStyle).getColor();
|
||||
setValue(c);
|
||||
return true;
|
||||
}
|
||||
|
@ -104,6 +109,10 @@ public class XSLFTextRun {
|
|||
* @return font size in points or -1 if font size is not set.
|
||||
*/
|
||||
public double getFontSize(){
|
||||
double scale = 1;
|
||||
CTTextNormalAutofit afit = getParentParagraph().getParentShape().getTextBodyPr().getNormAutofit();
|
||||
if(afit != null) scale = (double)afit.getFontScale() / 100000;
|
||||
|
||||
CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getLevel()){
|
||||
public boolean fetch(CTTextCharacterProperties props){
|
||||
if(props.isSetSz()){
|
||||
|
@ -114,7 +123,27 @@ public class XSLFTextRun {
|
|||
}
|
||||
};
|
||||
fetchCharacterProperty(fetcher);
|
||||
return fetcher.getValue() == null ? -1 : fetcher.getValue();
|
||||
return fetcher.getValue() == null ? -1 : fetcher.getValue()*scale;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the spacing between characters within a text run,
|
||||
* If this attribute is omitted than a value of 0 or no adjustment is assumed.
|
||||
*/
|
||||
public double getCharacterSpacing(){
|
||||
|
||||
CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getLevel()){
|
||||
public boolean fetch(CTTextCharacterProperties props){
|
||||
if(props.isSetSpc()){
|
||||
setValue(props.getSpc()*0.01);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
fetchCharacterProperty(fetcher);
|
||||
return fetcher.getValue() == null ? 0 : fetcher.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -234,6 +263,24 @@ public class XSLFTextRun {
|
|||
return fetcher.getValue() == null ? false : fetcher.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether a run of text will be formatted as a superscript text. Default is false.
|
||||
*/
|
||||
public TextCap getTextCap() {
|
||||
CharacterPropertyFetcher<TextCap> fetcher = new CharacterPropertyFetcher<TextCap>(_p.getLevel()){
|
||||
public boolean fetch(CTTextCharacterProperties props){
|
||||
if(props.isSetCap()){
|
||||
int idx = props.getCap().intValue() - 1;
|
||||
setValue(TextCap.values()[idx]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
fetchCharacterProperty(fetcher);
|
||||
return fetcher.getValue() == null ? TextCap.NONE : fetcher.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether this run of text will be formatted as bold text
|
||||
*
|
||||
|
|
|
@ -30,12 +30,16 @@ 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.CTApplicationNonVisualDrawingProps;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -44,7 +48,7 @@ import java.util.List;
|
|||
* @author Yegor Kozlov
|
||||
*/
|
||||
@Beta
|
||||
public abstract class XSLFTextShape extends XSLFSimpleShape {
|
||||
public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable<XSLFTextParagraph>{
|
||||
private final List<XSLFTextParagraph> _paragraphs;
|
||||
|
||||
/*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) {
|
||||
|
@ -59,7 +63,14 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
}
|
||||
}
|
||||
|
||||
// textual properties
|
||||
public Iterator<XSLFTextParagraph> iterator(){
|
||||
return _paragraphs.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return text contained within this shape or empty string
|
||||
*/
|
||||
public String getText() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
for (XSLFTextParagraph p : _paragraphs) {
|
||||
|
@ -69,10 +80,34 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
return out.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* unset text from this shape
|
||||
*/
|
||||
public void clearText(){
|
||||
_paragraphs.clear();
|
||||
CTTextBody txBody = getTextBody(true);
|
||||
txBody.setPArray(null); // remove any existing paragraphs
|
||||
}
|
||||
|
||||
public void setText(String text){
|
||||
clearText();
|
||||
|
||||
addNewTextParagraph().addNewTextRun().setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return text paragraphs in this shape
|
||||
*/
|
||||
public List<XSLFTextParagraph> getTextParagraphs() {
|
||||
return _paragraphs;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a new paragraph run to this shape
|
||||
*
|
||||
* @return created paragraph run
|
||||
*/
|
||||
public XSLFTextParagraph addNewTextParagraph() {
|
||||
CTTextBody txBody = getTextBody(true);
|
||||
CTTextParagraph p = txBody.addNewP();
|
||||
|
@ -84,9 +119,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
|
||||
/**
|
||||
* Sets the type of vertical alignment for the text.
|
||||
* One of the <code>Anchor*</code> constants defined in this class.
|
||||
*
|
||||
* @param anchor - the type of alignment. Default is {@link org.apache.poi.xslf.usermodel.VerticalAlignment#TOP}
|
||||
* @param anchor - the type of alignment.
|
||||
* A <code>null</code> values unsets this property.
|
||||
*/
|
||||
public void setVerticalAlignment(VerticalAlignment anchor){
|
||||
CTTextBodyProperties bodyPr = getTextBodyPr();
|
||||
|
@ -102,7 +137,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
/**
|
||||
* Returns the type of vertical alignment for the text.
|
||||
*
|
||||
* @return the type of alignment
|
||||
* @return the type of vertical alignment
|
||||
*/
|
||||
public VerticalAlignment getVerticalAlignment(){
|
||||
PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){
|
||||
|
@ -147,13 +182,15 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
}
|
||||
return TextDirection.HORIZONTAL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the distance (in points) between the bottom of the text frame
|
||||
* and the bottom of the inscribed rectangle of the shape that contains the text.
|
||||
*
|
||||
* @return the bottom margin or -1 if not set
|
||||
* @return the bottom inset in points
|
||||
*/
|
||||
public double getMarginBottom(){
|
||||
public double getBottomInset(){
|
||||
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
|
||||
public boolean fetch(CTTextBodyProperties props){
|
||||
if(props.isSetBIns()){
|
||||
|
@ -173,9 +210,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
* and the left edge of the inscribed rectangle of the shape that contains
|
||||
* the text.
|
||||
*
|
||||
* @return the left margin
|
||||
* @return the left inset in points
|
||||
*/
|
||||
public double getMarginLeft(){
|
||||
public double getLeftInset(){
|
||||
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
|
||||
public boolean fetch(CTTextBodyProperties props){
|
||||
if(props.isSetLIns()){
|
||||
|
@ -195,9 +232,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
* text frame and the right edge of the inscribed rectangle of the shape
|
||||
* that contains the text.
|
||||
*
|
||||
* @return the right margin
|
||||
* @return the right inset in points
|
||||
*/
|
||||
public double getMarginRight(){
|
||||
public double getRightInset(){
|
||||
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
|
||||
public boolean fetch(CTTextBodyProperties props){
|
||||
if(props.isSetRIns()){
|
||||
|
@ -216,9 +253,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
* Returns the distance (in points) between the top of the text frame
|
||||
* and the top of the inscribed rectangle of the shape that contains the text.
|
||||
*
|
||||
* @return the top margin
|
||||
* @return the top inset in points
|
||||
*/
|
||||
public double getMarginTop(){
|
||||
public double getTopInset(){
|
||||
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
|
||||
public boolean fetch(CTTextBodyProperties props){
|
||||
if(props.isSetTIns()){
|
||||
|
@ -235,11 +272,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
|
||||
/**
|
||||
* Sets the botom margin.
|
||||
* @see #getMarginBottom()
|
||||
* @see #getBottomInset()
|
||||
*
|
||||
* @param margin the bottom margin
|
||||
*/
|
||||
public void setMarginBottom(double margin){
|
||||
public void setBottomInset(double margin){
|
||||
CTTextBodyProperties bodyPr = getTextBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(margin == -1) bodyPr.unsetBIns();
|
||||
|
@ -249,11 +286,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
|
||||
/**
|
||||
* Sets the left margin.
|
||||
* @see #getMarginLeft()
|
||||
* @see #getLeftInset()
|
||||
*
|
||||
* @param margin the left margin
|
||||
*/
|
||||
public void setMarginLeft(double margin){
|
||||
public void setLeftInset(double margin){
|
||||
CTTextBodyProperties bodyPr = getTextBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(margin == -1) bodyPr.unsetLIns();
|
||||
|
@ -263,11 +300,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
|
||||
/**
|
||||
* Sets the right margin.
|
||||
* @see #getMarginRight()
|
||||
* @see #getRightInset()
|
||||
*
|
||||
* @param margin the right margin
|
||||
*/
|
||||
public void setMarginRight(double margin){
|
||||
public void setRightInset(double margin){
|
||||
CTTextBodyProperties bodyPr = getTextBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(margin == -1) bodyPr.unsetRIns();
|
||||
|
@ -277,11 +314,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
|
||||
/**
|
||||
* Sets the top margin.
|
||||
* @see #getMarginTop()
|
||||
* @see #getTopInset()
|
||||
*
|
||||
* @param margin the top margin
|
||||
*/
|
||||
public void setMarginTop(double margin){
|
||||
public void setTopInset(double margin){
|
||||
CTTextBodyProperties bodyPr = getTextBodyPr();
|
||||
if (bodyPr != null) {
|
||||
if(margin == -1) bodyPr.unsetTIns();
|
||||
|
@ -291,10 +328,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
|
||||
|
||||
/**
|
||||
* Returns the value indicating word wrap.
|
||||
* One of the <code>Wrap*</code> constants defined in this class.
|
||||
*
|
||||
* @return the value indicating word wrap
|
||||
* @return whether to wrap words within the bounding rectangle
|
||||
*/
|
||||
public boolean getWordWrap(){
|
||||
PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
|
||||
|
@ -311,9 +345,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
}
|
||||
|
||||
/**
|
||||
* Specifies how the text should be wrapped
|
||||
*
|
||||
* @param wrap the value indicating how the text should be wrapped
|
||||
* @param wrap whether to wrap words within the bounding rectangle
|
||||
*/
|
||||
public void setWordWrap(boolean wrap){
|
||||
CTTextBodyProperties bodyPr = getTextBodyPr();
|
||||
|
@ -381,33 +414,25 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D graphics){
|
||||
java.awt.Shape outline = getOutline();
|
||||
|
||||
// shadow
|
||||
XSLFShadow shadow = getShadow();
|
||||
|
||||
Paint fill = getFill(graphics);
|
||||
Paint line = getLinePaint(graphics);
|
||||
if(shadow != null) {
|
||||
shadow.draw(graphics);
|
||||
/**
|
||||
* Specifies that the corresponding shape should be represented by the generating application
|
||||
* as a placeholder. When a shape is considered a placeholder by the generating application
|
||||
* it can have special properties to alert the user that they may enter content into the shape.
|
||||
* Different types of placeholders are allowed and can be specified by using the placeholder
|
||||
* type attribute for this element
|
||||
*
|
||||
* @param placeholder
|
||||
*/
|
||||
public void setPlaceholder(Placeholder placeholder){
|
||||
CTShape sh = (CTShape)getXmlObject();
|
||||
CTApplicationNonVisualDrawingProps nv = sh.getNvSpPr().getNvPr();
|
||||
if(placeholder == null) {
|
||||
if(nv.isSetPh()) nv.unsetPh();
|
||||
} else {
|
||||
nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ordinal() + 1));
|
||||
}
|
||||
|
||||
if(fill != null) {
|
||||
graphics.setPaint(fill);
|
||||
graphics.fill(outline);
|
||||
}
|
||||
|
||||
if (line != null){
|
||||
graphics.setPaint(line);
|
||||
applyStroke(graphics);
|
||||
graphics.draw(outline);
|
||||
}
|
||||
|
||||
// text
|
||||
if(getText().length() > 0) drawText(graphics);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the cumulative height occupied by the text
|
||||
|
@ -418,15 +443,19 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
return drawParagraphs(img.createGraphics(), 0, 0);
|
||||
}
|
||||
|
||||
void breakText(Graphics2D graphics){
|
||||
/**
|
||||
* break the contained text into lines
|
||||
*/
|
||||
private void breakText(Graphics2D graphics){
|
||||
for(XSLFTextParagraph p : _paragraphs) p.breakText(graphics);
|
||||
}
|
||||
|
||||
public void drawText(Graphics2D graphics) {
|
||||
@Override
|
||||
public void drawContent(Graphics2D graphics) {
|
||||
breakText(graphics);
|
||||
|
||||
Rectangle2D anchor = getAnchor();
|
||||
double x = anchor.getX() + getMarginLeft();
|
||||
double x = anchor.getX() + getLeftInset();
|
||||
double y = anchor.getY();
|
||||
|
||||
// first dry-run to calculate the total height of the text
|
||||
|
@ -434,21 +463,20 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
|
||||
switch (getVerticalAlignment()){
|
||||
case TOP:
|
||||
y += getMarginTop();
|
||||
y += getTopInset();
|
||||
break;
|
||||
case BOTTOM:
|
||||
y += anchor.getHeight() - textHeight - getMarginBottom();
|
||||
y += anchor.getHeight() - textHeight - getBottomInset();
|
||||
break;
|
||||
default:
|
||||
case MIDDLE:
|
||||
double delta = anchor.getHeight() - textHeight -
|
||||
getMarginTop() - getMarginBottom();
|
||||
y += getMarginTop() + delta/2;
|
||||
getTopInset() - getBottomInset();
|
||||
y += getTopInset() + delta/2;
|
||||
break;
|
||||
}
|
||||
|
||||
drawParagraphs(graphics, x, y);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -461,7 +489,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape {
|
|||
double y0 = y;
|
||||
for(int i = 0; i < _paragraphs.size(); i++){
|
||||
XSLFTextParagraph p = _paragraphs.get(i);
|
||||
java.util.List<XSLFTextParagraph.TextFragment> lines = p.getTextLines();
|
||||
List<XSLFTextParagraph.TextFragment> lines = p.getTextLines();
|
||||
|
||||
if(i > 0 && lines.size() > 0) {
|
||||
// the amount of vertical white space before the paragraph
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.apache.xmlbeans.XmlObject;
|
|||
import org.apache.xmlbeans.XmlOptions;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColorScheme;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeStyleSheet;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument;
|
||||
|
@ -36,6 +37,11 @@ import java.io.OutputStream;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A shared style sheet in a .pptx slide show
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
@Beta
|
||||
public class XSLFTheme extends POIXMLDocumentPart {
|
||||
private CTOfficeStyleSheet _theme;
|
||||
|
@ -64,17 +70,33 @@ public class XSLFTheme extends POIXMLDocumentPart {
|
|||
String name = c.getDomNode().getLocalName();
|
||||
_schemeColors.put(name, 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"));
|
||||
/**
|
||||
* re-map colors
|
||||
*
|
||||
* @param cmap color map defined in the master slide referencing this theme
|
||||
*/
|
||||
void initColorMap(CTColorMapping cmap) {
|
||||
_schemeColors.put("bg1", _schemeColors.get(cmap.getBg1().toString()));
|
||||
_schemeColors.put("bg2", _schemeColors.get(cmap.getBg2().toString()));
|
||||
_schemeColors.put("tx1", _schemeColors.get(cmap.getTx1().toString()));
|
||||
_schemeColors.put("tx2", _schemeColors.get(cmap.getTx2().toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return name of this theme, e.g. "Office Theme"
|
||||
*/
|
||||
public String getName(){
|
||||
return _theme.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name of this theme
|
||||
*
|
||||
* @param name name of this theme
|
||||
*/
|
||||
public void setName(String name){
|
||||
_theme.setName(name);
|
||||
}
|
||||
|
@ -111,10 +133,20 @@ public class XSLFTheme extends POIXMLDocumentPart {
|
|||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return typeface of the major font to use in a document.
|
||||
* Typically the major font is used for heading areas of a document.
|
||||
*
|
||||
*/
|
||||
public String getMajorFont(){
|
||||
return _theme.getThemeElements().getFontScheme().getMajorFont().getLatin().getTypeface();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return typeface of the minor font to use in a document.
|
||||
* Typically the monor font is used for normal text or paragraph areas.
|
||||
*
|
||||
*/
|
||||
public String getMinorFont(){
|
||||
return _theme.getThemeElements().getFontScheme().getMinorFont().getLatin().getTypeface();
|
||||
}
|
||||
|
|
|
@ -28,21 +28,26 @@ 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
|
||||
* An utulity to convert slides of a .pptx slide show to a PNG image
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class PPTX2PNG {
|
||||
|
||||
static void usage(){
|
||||
System.out.println("Usage: PPTX2PNG [options] <pptx file>");
|
||||
System.out.println("Options:");
|
||||
System.out.println(" -scale <float> scale factor");
|
||||
System.out.println(" -slide <integer> 1-based index of a slide to render");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
System.out.println("Usage: PPTX2PNG [options] <pptx file>");
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -62,6 +67,11 @@ public class PPTX2PNG {
|
|||
}
|
||||
}
|
||||
|
||||
if(file == null){
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Processing " + file);
|
||||
XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file));
|
||||
|
||||
|
@ -79,19 +89,23 @@ public class PPTX2PNG {
|
|||
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D graphics = img.createGraphics();
|
||||
|
||||
// default rendering options
|
||||
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.setColor(Color.white);
|
||||
graphics.clearRect(0, 0, width, height);
|
||||
|
||||
graphics.scale((double) width / pgsize.width, (double) height / pgsize.height);
|
||||
graphics.scale(scale, scale);
|
||||
|
||||
// draw stuff
|
||||
slide[i].draw(graphics);
|
||||
|
||||
String fname = file.replaceAll("\\.pptx", "-" + (i + 1) + ".png");
|
||||
// save the result
|
||||
int sep = file.lastIndexOf(".");
|
||||
String fname = file.substring(0, sep == -1 ? file.length() : sep) + "-" + (i + 1) +".png";
|
||||
FileOutputStream out = new FileOutputStream(fname);
|
||||
ImageIO.write(img, "png", out);
|
||||
out.close();
|
||||
|
|
|
@ -24,7 +24,7 @@ public class TestFormulaParser extends TestCase {
|
|||
};
|
||||
|
||||
CustomGeometry geom = new CustomGeometry(CTCustomGeometry2D.Factory.newInstance());
|
||||
Context ctx = new Context(geom, null);
|
||||
Context ctx = new Context(geom, null, null);
|
||||
for(Formula fmla : ops) {
|
||||
ctx.evaluate(fmla);
|
||||
}
|
||||
|
|
|
@ -21,11 +21,7 @@ public class TestPresetGeometries extends TestCase {
|
|||
|
||||
for(String name : shapes.keySet()) {
|
||||
CustomGeometry geom = shapes.get(name);
|
||||
Context ctx = new Context(geom, new IAdjustableShape() {
|
||||
public Rectangle2D getAnchor() {
|
||||
return new Rectangle2D.Double(0, 0, 100, 100);
|
||||
}
|
||||
|
||||
Context ctx = new Context(geom, new Rectangle2D.Double(0, 0, 100, 100), new IAdjustableShape() {
|
||||
public Guide getAdjustValue(String name) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ import java.awt.image.BufferedImage;
|
|||
public class TestPPTX2PNG extends TestCase {
|
||||
public void testRender(){
|
||||
String[] testFiles = {"layouts.pptx", "sample.pptx", "shapes.pptx",
|
||||
"45541_Header.pptx", "backgrounds.pptx"};
|
||||
"themes.pptx", "backgrounds.pptx"};
|
||||
for(String sampleFile : testFiles){
|
||||
XMLSlideShow pptx = XSLFTestDataSamples.openSampleDocument(sampleFile);
|
||||
Dimension pg = pptx.getPageSize();
|
||||
|
|
|
@ -34,38 +34,38 @@ public class TestXSLFAutoShape extends TestCase {
|
|||
shape.addNewTextParagraph().addNewTextRun().setText("POI");
|
||||
|
||||
// default margins from slide master
|
||||
assertEquals(3.6, shape.getMarginBottom());
|
||||
assertEquals(3.6, shape.getMarginTop());
|
||||
assertEquals(7.2, shape.getMarginLeft());
|
||||
assertEquals(7.2, shape.getMarginRight());
|
||||
assertEquals(3.6, shape.getBottomInset());
|
||||
assertEquals(3.6, shape.getTopInset());
|
||||
assertEquals(7.2, shape.getLeftInset());
|
||||
assertEquals(7.2, shape.getRightInset());
|
||||
|
||||
shape.setMarginBottom(1.0);
|
||||
assertEquals(1.0, shape.getMarginBottom());
|
||||
shape.setMarginTop(2.0);
|
||||
assertEquals(2.0, shape.getMarginTop());
|
||||
shape.setMarginLeft(3.0);
|
||||
assertEquals(3.0, shape.getMarginLeft());
|
||||
shape.setMarginRight(4.0);
|
||||
assertEquals(4.0, shape.getMarginRight());
|
||||
shape.setBottomInset(1.0);
|
||||
assertEquals(1.0, shape.getBottomInset());
|
||||
shape.setTopInset(2.0);
|
||||
assertEquals(2.0, shape.getTopInset());
|
||||
shape.setLeftInset(3.0);
|
||||
assertEquals(3.0, shape.getLeftInset());
|
||||
shape.setRightInset(4.0);
|
||||
assertEquals(4.0, shape.getRightInset());
|
||||
|
||||
shape.setMarginBottom(0.0);
|
||||
assertEquals(0.0, shape.getMarginBottom());
|
||||
shape.setMarginTop(0.0);
|
||||
assertEquals(0.0, shape.getMarginTop());
|
||||
shape.setMarginLeft(0.0);
|
||||
assertEquals(0.0, shape.getMarginLeft());
|
||||
shape.setMarginRight(0.0);
|
||||
assertEquals(0.0, shape.getMarginRight());
|
||||
shape.setBottomInset(0.0);
|
||||
assertEquals(0.0, shape.getBottomInset());
|
||||
shape.setTopInset(0.0);
|
||||
assertEquals(0.0, shape.getTopInset());
|
||||
shape.setLeftInset(0.0);
|
||||
assertEquals(0.0, shape.getLeftInset());
|
||||
shape.setRightInset(0.0);
|
||||
assertEquals(0.0, shape.getRightInset());
|
||||
|
||||
// unset to defauls
|
||||
shape.setMarginBottom(-1);
|
||||
assertEquals(3.6, shape.getMarginBottom());
|
||||
shape.setMarginTop(-1);
|
||||
assertEquals(3.6, shape.getMarginTop());
|
||||
shape.setMarginLeft(-1);
|
||||
assertEquals(7.2, shape.getMarginLeft());
|
||||
shape.setMarginRight(-1);
|
||||
assertEquals(7.2, shape.getMarginRight());
|
||||
shape.setBottomInset(-1);
|
||||
assertEquals(3.6, shape.getBottomInset());
|
||||
shape.setTopInset(-1);
|
||||
assertEquals(3.6, shape.getTopInset());
|
||||
shape.setLeftInset(-1);
|
||||
assertEquals(7.2, shape.getLeftInset());
|
||||
shape.setRightInset(-1);
|
||||
assertEquals(7.2, shape.getRightInset());
|
||||
|
||||
// shape
|
||||
assertTrue(shape.getWordWrap());
|
||||
|
|
|
@ -37,7 +37,7 @@ public class TestXSLFColor extends TestCase {
|
|||
CTSRgbColor c = xml.addNewSrgbClr();
|
||||
c.setVal(new byte[]{(byte)0xFF, 0, 0});
|
||||
|
||||
XSLFColor color = new XSLFColor(xml, null);
|
||||
XSLFColor color = new XSLFColor(xml, null, null);
|
||||
|
||||
assertEquals(-1, color.getAlpha());
|
||||
c.addNewAlpha().setVal(50000);
|
||||
|
@ -99,7 +99,7 @@ public class TestXSLFColor extends TestCase {
|
|||
c.setSat2(100000);
|
||||
c.setLum2(50000);
|
||||
|
||||
XSLFColor color = new XSLFColor(xml, null);
|
||||
XSLFColor color = new XSLFColor(xml, null, null);
|
||||
assertEquals(new Color(128, 00, 00), color.getColor());
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ public class TestXSLFColor extends TestCase {
|
|||
CTColor xml = CTColor.Factory.newInstance();
|
||||
xml.addNewSrgbClr().setVal(new byte[]{ (byte)0xFF, (byte)0xFF, 0});
|
||||
|
||||
XSLFColor color = new XSLFColor(xml, null);
|
||||
XSLFColor color = new XSLFColor(xml, null, null);
|
||||
assertEquals(new Color(0xFF, 0xFF, 0), color.getColor());
|
||||
}
|
||||
|
||||
|
@ -118,19 +118,19 @@ public class TestXSLFColor extends TestCase {
|
|||
CTColor xml = CTColor.Factory.newInstance();
|
||||
xml.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_2);
|
||||
|
||||
XSLFColor color = new XSLFColor(xml, theme);
|
||||
XSLFColor color = new XSLFColor(xml, theme, null);
|
||||
// accent2 is theme1.xml is <a:srgbClr val="C0504D"/>
|
||||
assertEquals(Color.decode("0xC0504D"), color.getColor());
|
||||
|
||||
xml = CTColor.Factory.newInstance();
|
||||
xml.addNewSchemeClr().setVal(STSchemeColorVal.LT_1);
|
||||
color = new XSLFColor(xml, theme);
|
||||
color = new XSLFColor(xml, theme, null);
|
||||
// <a:sysClr val="window" lastClr="FFFFFF"/>
|
||||
assertEquals(Color.decode("0xFFFFFF"), color.getColor());
|
||||
|
||||
xml = CTColor.Factory.newInstance();
|
||||
xml.addNewSchemeClr().setVal(STSchemeColorVal.DK_1);
|
||||
color = new XSLFColor(xml, theme);
|
||||
color = new XSLFColor(xml, theme, null);
|
||||
// <a:sysClr val="windowText" lastClr="000000"/>
|
||||
assertEquals(Color.decode("0x000000"), color.getColor());
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ public class TestXSLFColor extends TestCase {
|
|||
public void testPresetColor() {
|
||||
CTColor xml = CTColor.Factory.newInstance();
|
||||
xml.addNewPrstClr().setVal(STPresetColorVal.AQUAMARINE);
|
||||
XSLFColor color = new XSLFColor(xml, null);
|
||||
XSLFColor color = new XSLFColor(xml, null, null);
|
||||
assertEquals(new Color(127, 255, 212), color.getColor());
|
||||
|
||||
|
||||
|
@ -147,7 +147,7 @@ public class TestXSLFColor extends TestCase {
|
|||
STPresetColorVal.Enum val = STPresetColorVal.Enum.forString(colorName);
|
||||
assertNotNull(colorName, val);
|
||||
xml.addNewPrstClr().setVal(val);
|
||||
color = new XSLFColor(xml, null);
|
||||
color = new XSLFColor(xml, null, null);
|
||||
assertEquals(XSLFColor.presetColors.get(colorName), color.getColor());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,6 @@ package org.apache.poi.xslf.usermodel;
|
|||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.xslf.XSLFTestDataSamples;
|
||||
import org.apache.poi.POIXMLDocumentPart;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Yegor Kozlov
|
||||
|
@ -99,11 +96,11 @@ public class TestXSLFSlide extends TestCase {
|
|||
assertEquals(0, ppt.getSlides().length);
|
||||
|
||||
XSLFSlide slide = ppt.createSlide();
|
||||
assertTrue(slide.getFollowMasterBackground());
|
||||
slide.setFollowMasterBackground(false);
|
||||
assertFalse(slide.getFollowMasterBackground());
|
||||
slide.setFollowMasterBackground(true);
|
||||
assertTrue(slide.getFollowMasterBackground());
|
||||
assertTrue(slide.getFollowMasterGraphics());
|
||||
slide.setFollowMasterGraphics(false);
|
||||
assertFalse(slide.getFollowMasterGraphics());
|
||||
slide.setFollowMasterGraphics(true);
|
||||
assertTrue(slide.getFollowMasterGraphics());
|
||||
}
|
||||
|
||||
}
|
|
@ -38,7 +38,7 @@ public class TestXSLFSlideShow extends TestCase {
|
|||
|
||||
List<POIXMLDocumentPart> rels = slide1.getRelations();
|
||||
assertEquals(1, rels.size());
|
||||
assertEquals(slide1.getMasterSheet().getLayout("blank"), rels.get(0));
|
||||
assertEquals(slide1.getSlideMaster().getLayout(SlideLayout.BLANK), rels.get(0));
|
||||
|
||||
XSLFSlide slide2 = ppt.createSlide();
|
||||
assertEquals(2, ppt.getSlides().length);
|
||||
|
@ -91,7 +91,7 @@ public class TestXSLFSlideShow extends TestCase {
|
|||
assertEquals(1, masters.length);
|
||||
|
||||
XSLFSlide slide = ppt.createSlide();
|
||||
assertSame(masters[0], slide.getMasterSheet());
|
||||
assertSame(masters[0], slide.getSlideMaster());
|
||||
}
|
||||
|
||||
public void testSlideLayout(){
|
||||
|
|
|
@ -65,10 +65,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() &&
|
||||
!bodyPr1.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape1.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape1.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape1.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape1.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape1.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape1.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape1.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape1.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment());
|
||||
|
||||
// now check text properties
|
||||
|
@ -95,10 +95,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() &&
|
||||
!bodyPr2.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape2.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape2.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape2.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape2.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape2.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape2.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape2.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape2.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment());
|
||||
|
||||
assertEquals("subtitle", shape2.getText());
|
||||
|
@ -134,10 +134,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() &&
|
||||
!bodyPr1.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape1.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape1.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape1.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape1.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape1.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape1.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape1.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape1.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment());
|
||||
|
||||
// now check text properties
|
||||
|
@ -169,10 +169,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() &&
|
||||
!bodyPr2.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape2.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape2.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape2.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape2.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape2.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape2.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape2.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape2.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment());
|
||||
|
||||
XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
|
@ -244,10 +244,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() &&
|
||||
!bodyPr1.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape1.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape1.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape1.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape1.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape1.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape1.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape1.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape1.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.TOP, shape1.getVerticalAlignment());
|
||||
|
||||
// now check text properties
|
||||
|
@ -278,10 +278,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() &&
|
||||
!bodyPr2.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape2.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape2.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape2.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape2.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape2.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape2.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape2.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape2.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.BOTTOM, shape2.getVerticalAlignment());
|
||||
|
||||
assertEquals("Section Header", shape2.getText());
|
||||
|
@ -318,10 +318,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() &&
|
||||
!bodyPr1.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape1.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape1.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape1.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape1.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape1.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape1.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape1.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape1.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment());
|
||||
|
||||
// now check text properties
|
||||
|
@ -351,10 +351,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() &&
|
||||
!bodyPr2.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape2.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape2.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape2.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape2.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape2.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape2.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape2.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape2.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment());
|
||||
|
||||
XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
|
@ -425,10 +425,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() &&
|
||||
!bodyPr1.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape1.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape1.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape1.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape1.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape1.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape1.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape1.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape1.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment());
|
||||
|
||||
// now check text properties
|
||||
|
@ -449,10 +449,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() &&
|
||||
!bodyPr2.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape2.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape2.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape2.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape2.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape2.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape2.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape2.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape2.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment());
|
||||
|
||||
XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
|
@ -498,10 +498,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() &&
|
||||
!bodyPr1.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape1.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape1.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape1.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape1.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape1.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape1.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape1.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape1.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.BOTTOM, shape1.getVerticalAlignment());
|
||||
|
||||
// now check text properties
|
||||
|
@ -532,10 +532,10 @@ public class TestXSLFTextShape extends TestCase {
|
|||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() &&
|
||||
!bodyPr2.isSetAnchor()
|
||||
);
|
||||
assertEquals(7.2, shape2.getMarginLeft()); // 0.1"
|
||||
assertEquals(7.2, shape2.getMarginRight()); // 0.1"
|
||||
assertEquals(3.6, shape2.getMarginTop()); // 0.05"
|
||||
assertEquals(3.6, shape2.getMarginBottom()); // 0.05"
|
||||
assertEquals(7.2, shape2.getLeftInset()); // 0.1"
|
||||
assertEquals(7.2, shape2.getRightInset()); // 0.1"
|
||||
assertEquals(3.6, shape2.getTopInset()); // 0.05"
|
||||
assertEquals(3.6, shape2.getBottomInset()); // 0.05"
|
||||
assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment());
|
||||
|
||||
XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
|
|
|
@ -18,22 +18,141 @@ package org.apache.poi.xslf.usermodel;
|
|||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
||||
import org.apache.poi.xslf.XSLFTestDataSamples;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.TexturePaint;
|
||||
|
||||
/**
|
||||
* test common properties for sheets (slides, masters, layouts, etc.)
|
||||
* test reading properties from a multi-theme and multi-master document
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public class TestXSLFTheme extends TestCase {
|
||||
public void testRead(){
|
||||
XMLSlideShow ppt = new XMLSlideShow();
|
||||
XSLFSlide slide = ppt.createSlide();
|
||||
XSLFTheme theme = slide.getSlideLayout().getSlideMaster().getTheme();
|
||||
assertNotNull(theme);
|
||||
|
||||
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("themes.pptx");
|
||||
XSLFSlide[] slides = ppt.getSlides();
|
||||
|
||||
slide1(slides[0]);
|
||||
slide2(slides[1]);
|
||||
slide3(slides[2]);
|
||||
slide4(slides[3]);
|
||||
slide5(slides[4]);
|
||||
slide6(slides[5]);
|
||||
slide7(slides[6]);
|
||||
slide8(slides[7]);
|
||||
slide9(slides[8]);
|
||||
slide10(slides[9]);
|
||||
}
|
||||
|
||||
private XSLFShape getShape(XSLFSheet sheet, String name){
|
||||
for(XSLFShape sh : sheet.getShapes()){
|
||||
if(sh.getShapeName().equals(name)) return sh;
|
||||
}
|
||||
throw new IllegalArgumentException("Shape not found: " + name);
|
||||
}
|
||||
|
||||
void slide1(XSLFSlide slide){
|
||||
assertEquals(Color.white, slide.getBackground().getFillColor());
|
||||
|
||||
XSLFTheme theme = slide.getTheme();
|
||||
assertEquals("Office Theme", theme.getName());
|
||||
//XSLFColor accent1 = theme.getColor("accent1");
|
||||
//assertNotNull(accent1);
|
||||
|
||||
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 3");
|
||||
RenderableShape rsh1 = new RenderableShape(sh1);
|
||||
XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
assertEquals(Color.white, run1.getFontColor());
|
||||
assertEquals(new Color(79, 129, 189), sh1.getFillColor());
|
||||
assertTrue(rsh1.getFillPaint(null) instanceof Color) ; // solid fill
|
||||
|
||||
}
|
||||
|
||||
void slide2(XSLFSlide slide){
|
||||
// Background 2, darker 10%
|
||||
// YK: PPT shows slightly different color: new Color(221, 217, 195)
|
||||
assertEquals(new Color(214, 212, 203), slide.getBackground().getFillColor());
|
||||
}
|
||||
|
||||
void slide3(XSLFSlide slide){
|
||||
assertNull(slide.getBackground().getFillColor());
|
||||
assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0);
|
||||
}
|
||||
|
||||
void slide4(XSLFSlide slide){
|
||||
assertNull(slide.getBackground().getFillColor());
|
||||
assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0);
|
||||
|
||||
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 4");
|
||||
RenderableShape rsh1 = new RenderableShape(sh1);
|
||||
XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
assertEquals(Color.white, run1.getFontColor());
|
||||
assertEquals(new Color(148, 198, 0), sh1.getFillColor());
|
||||
assertTrue(rsh1.getFillPaint(null) instanceof Color) ; // solid fill
|
||||
|
||||
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 3");
|
||||
XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
assertEquals(new Color(148, 198, 0), run2.getFontColor());
|
||||
assertNull(sh2.getFillColor()); // no fill
|
||||
|
||||
assertTrue(slide.getSlideLayout().getFollowMasterGraphics());
|
||||
}
|
||||
|
||||
void slide5(XSLFSlide slide){
|
||||
assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint);
|
||||
|
||||
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 1");
|
||||
XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
assertEquals(new Color(148, 198, 0), run2.getFontColor());
|
||||
assertNull(sh2.getFillColor()); // no fill
|
||||
// font size is 40pt and scale factor is 90%
|
||||
assertEquals(36.0, run2.getFontSize());
|
||||
|
||||
assertTrue(slide.getSlideLayout().getFollowMasterGraphics());
|
||||
}
|
||||
|
||||
void slide6(XSLFSlide slide){
|
||||
|
||||
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Subtitle 3");
|
||||
XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
assertEquals(new Color(66, 66, 66), run1.getFontColor());
|
||||
assertNull(sh1.getFillColor()); // no fill
|
||||
|
||||
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 2");
|
||||
XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
assertEquals(new Color(148, 198, 0), run2.getFontColor());
|
||||
assertNull(sh2.getFillColor()); // no fill
|
||||
|
||||
assertFalse(slide.getSlideLayout().getFollowMasterGraphics());
|
||||
}
|
||||
|
||||
void slide7(XSLFSlide slide){
|
||||
|
||||
//YK: PPT reports a slightly different color: r=189,g=239,b=87
|
||||
assertEquals(new Color(182, 218, 108), slide.getBackground().getFillColor());
|
||||
|
||||
assertFalse(slide.getFollowMasterGraphics());
|
||||
}
|
||||
|
||||
void slide8(XSLFSlide slide){
|
||||
assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint);
|
||||
}
|
||||
|
||||
void slide9(XSLFSlide slide){
|
||||
assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint);
|
||||
}
|
||||
|
||||
void slide10(XSLFSlide slide){
|
||||
assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0);
|
||||
|
||||
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Title 3");
|
||||
XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
assertEquals(Color.white, run1.getFontColor());
|
||||
assertNull(sh1.getFillColor()); // no fill
|
||||
|
||||
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Subtitle 4");
|
||||
XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||
assertEquals(Color.white, run2.getFontColor());
|
||||
assertNull(sh2.getFillColor()); // no fill
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
Loading…
Reference in New Issue