git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1198658 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_8_BETA5
<!-- OOXML support: --> | <!-- OOXML support: --> | ||||
<property name="ooxml.src" location="src/ooxml/java"/> | <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.src.test" location="src/ooxml/testcases"/> | ||||
<property name="ooxml.reports.test" location="build/ooxml-test-results"/> | <property name="ooxml.reports.test" location="build/ooxml-test-results"/> | ||||
<property name="ooxml.output.dir" location="build/ooxml-classes"/> | <property name="ooxml.output.dir" location="build/ooxml-classes"/> | ||||
<pathelement path="${main.output.test.dir}"/> | <pathelement path="${main.output.test.dir}"/> | ||||
</classpath> | </classpath> | ||||
</javac> | </javac> | ||||
<copy todir="${ooxml.output.dir}"> | |||||
<fileset dir="${ooxml.resource1.dir}"/> | |||||
</copy> | |||||
</target> | </target> | ||||
<target name="compile-excelant" depends="compile-main,compile-ooxml"> | <target name="compile-excelant" depends="compile-main,compile-ooxml"> |
/* | |||||
* ==================================================================== | |||||
* 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()); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
/* | |||||
* ==================================================================== | |||||
* 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(); | |||||
} | |||||
} |
XSLFNotes notes = slide.getNotes(); | XSLFNotes notes = slide.getNotes(); | ||||
XSLFComments comments = slide.getComments(); | XSLFComments comments = slide.getComments(); | ||||
XSLFSlideLayout layout = slide.getSlideLayout(); | XSLFSlideLayout layout = slide.getSlideLayout(); | ||||
XSLFSlideMaster master = slide.getMasterSheet(); | |||||
XSLFSlideMaster master = layout.getSlideMaster(); | |||||
// TODO Do the slide's name | // TODO Do the slide's name | ||||
// (Stored in docProps/app.xml) | // (Stored in docProps/app.xml) |
double x0 = pt.getX() - rx - rx * Math.cos(Math.toRadians(start)); | double x0 = pt.getX() - rx - rx * Math.cos(Math.toRadians(start)); | ||||
double y0 = pt.getY() - ry - ry * Math.sin(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( | Arc2D arc = new Arc2D.Double( | ||||
x0, | x0, | ||||
y0, | y0, | ||||
2 * rx, 2 * ry, | 2 * rx, 2 * ry, | ||||
-start, -extent, // negate angles because DrawingML rotates counter-clockwise | |||||
-start, -extent, | |||||
Arc2D.OPEN); | Arc2D.OPEN); | ||||
path.append(arc, true); | path.append(arc, true); | ||||
} | } |
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
*/ | */ | ||||
public class Context { | 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; | _props = props; | ||||
_anchor = anchor; | |||||
for(Guide gd : geom.adjusts) evaluate(gd); | for(Guide gd : geom.adjusts) evaluate(gd); | ||||
for(Guide gd : geom.guides) evaluate(gd); | for(Guide gd : geom.guides) evaluate(gd); | ||||
} | } | ||||
public Rectangle2D getShapeAnchor(){ | public Rectangle2D getShapeAnchor(){ | ||||
return _props.getAnchor(); | |||||
return _anchor; | |||||
} | } | ||||
public Guide getAdjustValue(String name){ | public Guide getAdjustValue(String name){ |
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | ||||
import java.awt.geom.Rectangle2D; | |||||
/** | /** | ||||
* Definition of a custom geometric shape | * Definition of a custom geometric shape | ||||
List<Guide> adjusts = new ArrayList<Guide>(); | List<Guide> adjusts = new ArrayList<Guide>(); | ||||
List<Guide> guides = new ArrayList<Guide>(); | List<Guide> guides = new ArrayList<Guide>(); | ||||
List<Path> paths = new ArrayList<Path>(); | List<Path> paths = new ArrayList<Path>(); | ||||
Path textBounds; | |||||
public CustomGeometry(CTCustomGeometry2D geom){ | |||||
public CustomGeometry(CTCustomGeometry2D geom) { | |||||
CTGeomGuideList avLst = geom.getAvLst(); | CTGeomGuideList avLst = geom.getAvLst(); | ||||
if(avLst != null) for(CTGeomGuide gd : avLst.getGdList()){ | if(avLst != null) for(CTGeomGuide gd : avLst.getGdList()){ | ||||
adjusts.add(new AdjustValue(gd)); | adjusts.add(new AdjustValue(gd)); | ||||
if(pathLst != null) for(CTPath2D spPath : pathLst.getPathList()){ | if(pathLst != null) for(CTPath2D spPath : pathLst.getPathList()){ | ||||
paths.add(new Path(spPath)); | 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()); | |||||
} | |||||
} | } | ||||
return paths.iterator(); | return paths.iterator(); | ||||
} | } | ||||
public Path getTextBounds(){ | |||||
return textBounds; | |||||
} | |||||
} | } |
package org.apache.poi.xslf.model.geom; | package org.apache.poi.xslf.model.geom; | ||||
import java.awt.geom.Rectangle2D; | |||||
/** | /** | ||||
* A bridge to the consumer application. | * A bridge to the consumer application. | ||||
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
*/ | */ | ||||
public interface IAdjustableShape { | public interface IAdjustableShape { | ||||
/** | |||||
* | |||||
* @return bounds of the shape | |||||
*/ | |||||
Rectangle2D getAnchor(); | |||||
/** | /** | ||||
* | * | ||||
* @param name name of a adjust value, e.g. adj1 | * @param name name of a adjust value, e.g. adj1 |
arg2 = pt.getY().toString(); | arg2 = pt.getY().toString(); | ||||
} | } | ||||
LineToCommand(String s1, String s2){ | |||||
arg1 = s1; | |||||
arg2 = s2; | |||||
} | |||||
public void execute(GeneralPath path, Context ctx){ | public void execute(GeneralPath path, Context ctx){ | ||||
double x = ctx.getValue(arg1); | double x = ctx.getValue(arg1); | ||||
double y = ctx.getValue(arg2); | double y = ctx.getValue(arg2); |
arg2 = pt.getY().toString(); | arg2 = pt.getY().toString(); | ||||
} | } | ||||
MoveToCommand(String s1, String s2){ | |||||
arg1 = s1; | |||||
arg2 = s2; | |||||
} | |||||
public void execute(GeneralPath path, Context ctx){ | public void execute(GeneralPath path, Context ctx){ | ||||
double x = ctx.getValue(arg1); | double x = ctx.getValue(arg1); | ||||
double y = ctx.getValue(arg2); | double y = ctx.getValue(arg2); |
/* | |||||
* ==================================================================== | |||||
* 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; | |||||
} | |||||
} |
public class Path { | public class Path { | ||||
private final List<PathCommand> commands; | private final List<PathCommand> commands; | ||||
boolean _fill, _stroke; | 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){ | public Path(CTPath2D spPath){ | ||||
_fill = spPath.getFill() != STPathFillMode.NONE; | _fill = spPath.getFill() != STPathFillMode.NONE; | ||||
_stroke = spPath.getStroke(); | _stroke = spPath.getStroke(); | ||||
_w = spPath.isSetW() ? spPath.getW() : -1; | |||||
_h = spPath.isSetH() ? spPath.getH() : -1; | |||||
commands = new ArrayList<PathCommand>(); | commands = new ArrayList<PathCommand>(); | ||||
for(XmlObject ch : spPath.selectPath("*")){ | for(XmlObject ch : spPath.selectPath("*")){ | ||||
if(ch instanceof CTPath2DMoveTo){ | if(ch instanceof CTPath2DMoveTo){ | ||||
} | } | ||||
} | } | ||||
public void addCommand(PathCommand cmd){ | |||||
commands.add(cmd); | |||||
} | |||||
/** | |||||
* Convert the internal represenation to java.awt.GeneralPath | |||||
*/ | |||||
public GeneralPath getPath(Context ctx) { | public GeneralPath getPath(Context ctx) { | ||||
GeneralPath path = new GeneralPath(); | GeneralPath path = new GeneralPath(); | ||||
for(PathCommand cmd : commands) | for(PathCommand cmd : commands) | ||||
public boolean isFilled(){ | public boolean isFilled(){ | ||||
return _fill; | return _fill; | ||||
} | } | ||||
public long getW(){ | |||||
return _w; | |||||
} | |||||
public long getH(){ | |||||
return _h; | |||||
} | |||||
} | } |
SLIDE_NUMBER, | SLIDE_NUMBER, | ||||
FOOTER, | FOOTER, | ||||
HEADER, | HEADER, | ||||
OBJECT, | |||||
CONTENT, | |||||
CHART, | CHART, | ||||
TABLE, | TABLE, | ||||
CLIP_ART, | CLIP_ART, | ||||
MEDIA, | MEDIA, | ||||
SLIDE_IMAGE, | SLIDE_IMAGE, | ||||
PICTURE | PICTURE | ||||
} | } |
/* | |||||
* ==================================================================== | |||||
* 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; | 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 { | 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; | |||||
} | |||||
} | } |
/* | |||||
* ==================================================================== | |||||
* 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, | |||||
} |
* is smart in the sense that it will not justify sentences | * is smart in the sense that it will not justify sentences | ||||
* which are short | * which are short | ||||
*/ | */ | ||||
JUSTIFY | |||||
JUSTIFY, | |||||
JUSTIFY_LOW, | |||||
DIST, | |||||
THAI_DIST | |||||
} | } |
/* | |||||
* ==================================================================== | |||||
* 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 | |||||
} |
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideSize; | import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideSize; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.PresentationDocument; | import org.openxmlformats.schemas.presentationml.x2006.main.PresentationDocument; | ||||
import java.awt.*; | |||||
import java.awt.Dimension; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
return Collections.unmodifiableList(_pictures); | 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; | int slideNumber = 256, cnt = 1; | ||||
CTSlideIdList slideList; | CTSlideIdList slideList; | ||||
if (!_presentation.isSetSldIdLst()) slideList = _presentation.addNewSldIdLst(); | if (!_presentation.isSetSldIdLst()) slideList = _presentation.addNewSldIdLst(); | ||||
slideId.setId(slideNumber); | slideId.setId(slideNumber); | ||||
slideId.setId2(slide.getPackageRelationship().getId()); | 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); | slide.addRelation(layout.getPackageRelationship().getId(), layout); | ||||
PackagePartName ppName = layout.getPackagePart().getPartName(); | PackagePartName ppName = layout.getPackagePart().getPartName(); | ||||
_slides.add(slide); | _slides.add(slide); | ||||
return 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. | * Return the Notes Master, if there is one. | ||||
* (May not be present if no notes exist) | * (May not be present if no notes exist) |
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual; | 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 | * @author Yegor Kozlov | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
public class XSLFAutoShape extends XSLFTextShape { | public class XSLFAutoShape extends XSLFTextShape { | ||||
private static final Pattern adjPtrn = Pattern.compile("val\\s+(\\d+)"); | |||||
/*package*/ XSLFAutoShape(CTShape shape, XSLFSheet sheet) { | /*package*/ XSLFAutoShape(CTShape shape, XSLFSheet sheet) { | ||||
super(shape, sheet); | super(shape, sheet); |
package org.apache.poi.xslf.usermodel; | 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.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; | import java.awt.geom.Rectangle2D; | ||||
/** | /** | ||||
public void draw(Graphics2D graphics) { | public void draw(Graphics2D graphics) { | ||||
Rectangle2D anchor = getAnchor(); | Rectangle2D anchor = getAnchor(); | ||||
XmlObject spPr = null; | |||||
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(); | CTBackground bg = (CTBackground)getXmlObject(); | ||||
if(bg.isSetBgPr()){ | if(bg.isSetBgPr()){ | ||||
spPr = bg.getBgPr(); | |||||
XmlObject spPr = bg.getBgPr(); | |||||
fill = rShape.getPaint(graphics, spPr, null); | |||||
} else if (bg.isSetBgRef()){ | } else if (bg.isSetBgRef()){ | ||||
CTStyleMatrixReference bgRef= bg.getBgRef(); | CTStyleMatrixReference bgRef= bg.getBgRef(); | ||||
int idx = (int)bgRef.getIdx() - 1000; | |||||
CTSchemeColor phClr = bgRef.getSchemeClr(); | |||||
int idx = (int)bgRef.getIdx() - 1001; | |||||
XSLFTheme theme = getSheet().getTheme(); | XSLFTheme theme = getSheet().getTheme(); | ||||
CTBackgroundFillStyleList bgStyles = | CTBackgroundFillStyleList bgStyles = | ||||
theme.getXmlObject().getThemeElements().getFmtScheme().getBgFillStyleLst(); | theme.getXmlObject().getThemeElements().getFmtScheme().getBgFillStyleLst(); | ||||
// TODO pass this to getPaint | |||||
XmlObject bgStyle = bgStyles.selectPath("*")[idx]; | XmlObject bgStyle = bgStyles.selectPath("*")[idx]; | ||||
fill = rShape.selectPaint(graphics, bgStyle, phClr, theme.getPackagePart()); | |||||
} | } | ||||
if(spPr == null){ | |||||
return; | |||||
} | |||||
return fill; | |||||
} | |||||
Paint fill = getPaint(graphics, spPr); | |||||
if(fill != null) { | |||||
graphics.setPaint(fill); | |||||
graphics.fill(anchor); | |||||
@Override | |||||
public Color getFillColor(){ | |||||
Paint p = getPaint(null); | |||||
if(p instanceof Color){ | |||||
return (Color)p; | |||||
} | } | ||||
return null; | |||||
} | } | ||||
} | } |
import org.openxmlformats.schemas.drawingml.x2006.main.CTSystemColor; | import org.openxmlformats.schemas.drawingml.x2006.main.CTSystemColor; | ||||
import org.w3c.dom.Node; | import org.w3c.dom.Node; | ||||
import java.awt.*; | |||||
import java.awt.Color; | |||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
@Internal | |||||
public class XSLFColor { | public class XSLFColor { | ||||
private XmlObject _xmlObject; | private XmlObject _xmlObject; | ||||
private Color _color; | private Color _color; | ||||
private CTSchemeColor _phClr; | |||||
XSLFColor(XmlObject obj, XSLFTheme theme) { | |||||
public XSLFColor(XmlObject obj, XSLFTheme theme, CTSchemeColor phClr) { | |||||
_xmlObject = obj; | _xmlObject = obj; | ||||
_phClr = phClr; | |||||
_color = toColor(obj, theme); | _color = toColor(obj, theme); | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
static Color toColor(XmlObject obj, XSLFTheme theme) { | |||||
Color toColor(XmlObject obj, XSLFTheme theme) { | |||||
Color color = null; | Color color = null; | ||||
for (XmlObject ch : obj.selectPath("*")) { | for (XmlObject ch : obj.selectPath("*")) { | ||||
if (ch instanceof CTHslColor) { | if (ch instanceof CTHslColor) { | ||||
int h = hsl.getHue2(); | int h = hsl.getHue2(); | ||||
int s = hsl.getSat2(); | int s = hsl.getSat2(); | ||||
int l = hsl.getLum2(); | 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); | color = Color.getHSBColor(h / 60000f, s / 100000f, l / 100000f); | ||||
} else if (ch instanceof CTPresetColor) { | } else if (ch instanceof CTPresetColor) { | ||||
CTPresetColor prst = (CTPresetColor)ch; | CTPresetColor prst = (CTPresetColor)ch; | ||||
} else if (ch instanceof CTSchemeColor) { | } else if (ch instanceof CTSchemeColor) { | ||||
CTSchemeColor schemeColor = (CTSchemeColor)ch; | CTSchemeColor schemeColor = (CTSchemeColor)ch; | ||||
String colorRef = schemeColor.getVal().toString(); | 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 | // find referenced CTColor in the theme and convert it to java.awt.Color via a recursive call | ||||
CTColor ctColor = theme.getCTColor(colorRef); | CTColor ctColor = theme.getCTColor(colorRef); | ||||
if(ctColor != null) color = toColor(ctColor, null); | if(ctColor != null) color = toColor(ctColor, null); | ||||
else { | |||||
color = Color.black; | |||||
} | |||||
} else if (ch instanceof CTScRgbColor) { | } else if (ch instanceof CTScRgbColor) { | ||||
// same as CTSRgbColor but with values expressed in percents | // same as CTSRgbColor but with values expressed in percents | ||||
CTScRgbColor scrgb = (CTScRgbColor)ch; | CTScRgbColor scrgb = (CTScRgbColor)ch; | ||||
return color; | 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){ | 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){ | if(obj.length == 1){ | ||||
Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); | Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); | ||||
if(attr != null) { | if(attr != null) { | ||||
return Integer.parseInt(attr.getNodeValue()) / 1000; | return Integer.parseInt(attr.getNodeValue()) / 1000; | ||||
} | } | ||||
} | } | ||||
return -1; | return -1; | ||||
} | } | ||||
private int getAngleValue(String elem){ | 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){ | if(obj.length == 1){ | ||||
Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); | Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); | ||||
if(attr != null) { | if(attr != null) { | ||||
* A 10% shade is 10% of the input color combined with 90% black. | * A 10% shade is 10% of the input color combined with 90% black. | ||||
* | * | ||||
* @return the value of the shade specified as a | * @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 | * or -1 if the value is not set | ||||
*/ | */ | ||||
int getShade(){ | int getShade(){ | ||||
* A 10% tint is 10% of the input color combined with 90% white. | * A 10% tint is 10% of the input color combined with 90% white. | ||||
* | * | ||||
* @return the value of the tint specified as a | * @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 | * or -1 if the value is not set | ||||
*/ | */ | ||||
int getTint(){ | int getTint(){ | ||||
return color; | return color; | ||||
} | } | ||||
/** | |||||
* This algorithm returns result different from PowerPoint. | |||||
* TODO: revisit and improve | |||||
*/ | |||||
private static Color shade(Color c, int shade) { | private static Color shade(Color c, int shade) { | ||||
return new Color( | return new Color( | ||||
(int)(c.getRed() * shade * 0.01), | (int)(c.getRed() * shade * 0.01), | ||||
c.getAlpha()); | c.getAlpha()); | ||||
} | } | ||||
/** | |||||
* This algorithm returns result different from PowerPoint. | |||||
* TODO: revisit and improve | |||||
*/ | |||||
private static Color tint(Color c, int tint) { | private static Color tint(Color c, int tint) { | ||||
int r = c.getRed(); | int r = c.getRed(); | ||||
int g = c.getGreen(); | int g = c.getGreen(); | ||||
/** | /** | ||||
* Preset colors defined in DrawingML | * Preset colors defined in DrawingML | ||||
*/ | */ | ||||
static Map<String, Color> presetColors; | |||||
static final Map<String, Color> presetColors; | |||||
static { | static { | ||||
presetColors = new HashMap<String, Color>(); | presetColors = new HashMap<String, Color>(); |
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import org.apache.poi.util.Beta; | 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.CTLineEndProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; | import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; | import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnectorNonVisual; | import org.openxmlformats.schemas.presentationml.x2006.main.CTConnectorNonVisual; | ||||
import java.awt.*; | |||||
import java.awt.Shape; | |||||
import java.awt.geom.AffineTransform; | import java.awt.geom.AffineTransform; | ||||
import java.awt.geom.Ellipse2D; | import java.awt.geom.Ellipse2D; | ||||
import java.awt.geom.GeneralPath; | import java.awt.geom.GeneralPath; | ||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
/** | /** | ||||
* Specifies a connection shape. | * Specifies a connection shape. | ||||
return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1]; | 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(); | LineEndLength tailLength = getLineTailLength(); | ||||
LineEndWidth tailWidth = getLineTailWidth(); | LineEndWidth tailWidth = getLineTailWidth(); | ||||
AffineTransform at = new AffineTransform(); | AffineTransform at = new AffineTransform(); | ||||
Shape shape = null; | Shape shape = null; | ||||
Path p = null; | |||||
Rectangle2D bounds; | Rectangle2D bounds; | ||||
double scaleY = Math.pow(2, tailWidth.ordinal()); | double scaleY = Math.pow(2, tailWidth.ordinal()); | ||||
double scaleX = Math.pow(2, tailLength.ordinal()); | double scaleX = Math.pow(2, tailLength.ordinal()); | ||||
switch (getLineHeadDecoration()) { | |||||
switch (getLineTailDecoration()) { | |||||
case OVAL: | case OVAL: | ||||
p = new Path(); | |||||
shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY); | shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY); | ||||
bounds = shape.getBounds2D(); | bounds = shape.getBounds2D(); | ||||
at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2); | at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2); | ||||
at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2); | at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2); | ||||
break; | break; | ||||
case ARROW: | case ARROW: | ||||
p = new Path(); | |||||
GeneralPath arrow = new GeneralPath(); | GeneralPath arrow = new GeneralPath(); | ||||
arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2)); | arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2)); | ||||
arrow.lineTo(0, 0); | arrow.lineTo(0, 0); | ||||
at.rotate(alpha); | at.rotate(alpha); | ||||
break; | break; | ||||
case TRIANGLE: | case TRIANGLE: | ||||
p = new Path(); | |||||
scaleY = tailWidth.ordinal() + 1; | scaleY = tailWidth.ordinal() + 1; | ||||
scaleX = tailLength.ordinal() + 1; | scaleX = tailLength.ordinal() + 1; | ||||
GeneralPath triangle = new GeneralPath(); | GeneralPath triangle = new GeneralPath(); | ||||
if (shape != null) { | if (shape != null) { | ||||
shape = at.createTransformedShape(shape); | shape = at.createTransformedShape(shape); | ||||
} | } | ||||
return shape; | |||||
return shape == null ? null : new Outline(shape, p); | |||||
} | } | ||||
Shape getHeadDecoration() { | |||||
Outline getHeadDecoration() { | |||||
LineEndLength headLength = getLineHeadLength(); | LineEndLength headLength = getLineHeadLength(); | ||||
LineEndWidth headWidth = getLineHeadWidth(); | LineEndWidth headWidth = getLineHeadWidth(); | ||||
AffineTransform at = new AffineTransform(); | AffineTransform at = new AffineTransform(); | ||||
Shape shape = null; | Shape shape = null; | ||||
Path p = null; | |||||
Rectangle2D bounds; | Rectangle2D bounds; | ||||
double scaleY = 1; | double scaleY = 1; | ||||
double scaleX = 1; | double scaleX = 1; | ||||
switch (getLineHeadDecoration()) { | switch (getLineHeadDecoration()) { | ||||
case OVAL: | case OVAL: | ||||
p = new Path(); | |||||
shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY); | shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY); | ||||
bounds = shape.getBounds2D(); | bounds = shape.getBounds2D(); | ||||
at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2); | at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2); | ||||
break; | break; | ||||
case STEALTH: | case STEALTH: | ||||
case ARROW: | case ARROW: | ||||
p = new Path(); | |||||
GeneralPath arrow = new GeneralPath(); | GeneralPath arrow = new GeneralPath(); | ||||
arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2)); | arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2)); | ||||
arrow.lineTo(0, 0); | arrow.lineTo(0, 0); | ||||
at.rotate(alpha); | at.rotate(alpha); | ||||
break; | break; | ||||
case TRIANGLE: | case TRIANGLE: | ||||
p = new Path(); | |||||
scaleY = headWidth.ordinal() + 1; | scaleY = headWidth.ordinal() + 1; | ||||
scaleX = headLength.ordinal() + 1; | scaleX = headLength.ordinal() + 1; | ||||
GeneralPath triangle = new GeneralPath(); | GeneralPath triangle = new GeneralPath(); | ||||
if (shape != null) { | if (shape != null) { | ||||
shape = at.createTransformedShape(shape); | 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; | |||||
} | } | ||||
} | } |
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; | import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | ||||
import java.awt.*; | |||||
import java.awt.Color; | |||||
import java.awt.Rectangle; | |||||
/** | /** |
geom.addNewPathLst(); | geom.addNewPathLst(); | ||||
return ct; | return ct; | ||||
} | } | ||||
@Override | |||||
protected java.awt.Shape getOutline(){ | |||||
return getPath(); | |||||
} | |||||
} | } |
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; | import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; | ||||
import java.awt.*; | |||||
import java.awt.Graphics2D; | |||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
/** | /** |
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual; | import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | ||||
import java.awt.*; | |||||
import java.awt.Graphics2D; | |||||
import java.awt.geom.AffineTransform; | import java.awt.geom.AffineTransform; | ||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.util.List; | import java.util.List; | ||||
_spPr = shape.getGrpSpPr(); | _spPr = shape.getGrpSpPr(); | ||||
} | } | ||||
@Override | |||||
public CTGroupShape getXmlObject(){ | public CTGroupShape getXmlObject(){ | ||||
return _shape; | return _shape; | ||||
} | } | ||||
@Override | |||||
public Rectangle2D getAnchor(){ | public Rectangle2D getAnchor(){ | ||||
CTGroupTransform2D xfrm = _spPr.getXfrm(); | CTGroupTransform2D xfrm = _spPr.getXfrm(); | ||||
CTPoint2D off = xfrm.getOff(); | CTPoint2D off = xfrm.getOff(); | ||||
Units.toPoints(cx), Units.toPoints(cy)); | Units.toPoints(cx), Units.toPoints(cy)); | ||||
} | } | ||||
@Override | |||||
public void setAnchor(Rectangle2D anchor){ | public void setAnchor(Rectangle2D anchor){ | ||||
CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm(); | CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm(); | ||||
CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff(); | CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff(); | ||||
ext.setCy(cy); | 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(){ | public Rectangle2D getInteriorAnchor(){ | ||||
CTGroupTransform2D xfrm = _spPr.getXfrm(); | CTGroupTransform2D xfrm = _spPr.getXfrm(); | ||||
CTPoint2D off = xfrm.getChOff(); | CTPoint2D off = xfrm.getChOff(); | ||||
Units.toPoints(cx), Units.toPoints(cy)); | 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){ | public void setInteriorAnchor(Rectangle2D anchor){ | ||||
CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm(); | CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm(); | ||||
CTPoint2D off = xfrm.isSetChOff() ? xfrm.getChOff() : xfrm.addNewChOff(); | CTPoint2D off = xfrm.isSetChOff() ? xfrm.getChOff() : xfrm.addNewChOff(); | ||||
ext.setCy(cy); | ext.setCy(cy); | ||||
} | } | ||||
/** | |||||
* | |||||
* @return child shapes contained witin this group | |||||
*/ | |||||
public XSLFShape[] getShapes(){ | public XSLFShape[] getShapes(){ | ||||
return _shapes.toArray(new XSLFShape[_shapes.size()]); | return _shapes.toArray(new XSLFShape[_shapes.size()]); | ||||
} | } | ||||
/** | |||||
* Remove the specified shape from this group | |||||
*/ | |||||
public boolean removeShape(XSLFShape xShape) { | public boolean removeShape(XSLFShape xShape) { | ||||
XmlObject obj = xShape.getXmlObject(); | XmlObject obj = xShape.getXmlObject(); | ||||
if(obj instanceof CTShape){ | if(obj instanceof CTShape){ | ||||
return _shapes.remove(xShape); | return _shapes.remove(xShape); | ||||
} | } | ||||
@Override | |||||
public String getShapeName(){ | public String getShapeName(){ | ||||
return _shape.getNvGrpSpPr().getCNvPr().getName(); | return _shape.getNvGrpSpPr().getCNvPr().getName(); | ||||
} | } | ||||
@Override | |||||
public int getShapeId(){ | public int getShapeId(){ | ||||
return (int)_shape.getNvGrpSpPr().getCNvPr().getId(); | return (int)_shape.getNvGrpSpPr().getCNvPr().getId(); | ||||
} | } | ||||
return sh; | return sh; | ||||
} | } | ||||
@Override | |||||
public void setFlipHorizontal(boolean flip){ | public void setFlipHorizontal(boolean flip){ | ||||
_spPr.getXfrm().setFlipH(flip); | _spPr.getXfrm().setFlipH(flip); | ||||
} | } | ||||
@Override | |||||
public void setFlipVertical(boolean flip){ | public void setFlipVertical(boolean flip){ | ||||
_spPr.getXfrm().setFlipV(flip); | _spPr.getXfrm().setFlipV(flip); | ||||
} | } | ||||
/** | |||||
* Whether the shape is horizontally flipped | |||||
* | |||||
* @return whether the shape is horizontally flipped | |||||
*/ | |||||
@Override | |||||
public boolean getFlipHorizontal(){ | public boolean getFlipHorizontal(){ | ||||
return _spPr.getXfrm().getFlipH(); | return _spPr.getXfrm().getFlipH(); | ||||
} | } | ||||
@Override | |||||
public boolean getFlipVertical(){ | public boolean getFlipVertical(){ | ||||
return _spPr.getXfrm().getFlipV(); | 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){ | public void setRotation(double theta){ | ||||
_spPr.getXfrm().setRot((int)(theta*60000)); | _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(){ | public double getRotation(){ | ||||
return (double)_spPr.getXfrm().getRot()/60000; | return (double)_spPr.getXfrm().getRot()/60000; | ||||
} | } | ||||
@Override | |||||
public void draw(Graphics2D graphics){ | public void draw(Graphics2D graphics){ | ||||
// the coordinate system of this group of shape | // the coordinate system of this group of shape | ||||
for (XSLFShape shape : getShapes()) { | for (XSLFShape shape : getShapes()) { | ||||
// remember the initial transform and restore it after we are done with the drawing | // 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); | graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true); | ||||
// apply rotation and flipping | |||||
shape.applyTransform(graphics); | |||||
shape.applyTransform(graphics); | |||||
shape.draw(graphics); | shape.draw(graphics); | ||||
// restore the coordinate system | // restore the coordinate system | ||||
graphics.setTransform(at0); | |||||
graphics.setTransform(at); | |||||
graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true); | graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true); | ||||
} | } | ||||
} | } |
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import org.apache.poi.openxml4j.opc.PackagePart; | |||||
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import javax.imageio.ImageIO; | import javax.imageio.ImageIO; | ||||
import java.awt.*; | |||||
import java.awt.Graphics2D; | |||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.awt.image.BufferedImage; | import java.awt.image.BufferedImage; | ||||
import java.io.ByteArrayInputStream; | import java.io.ByteArrayInputStream; | ||||
public boolean drawImage(Graphics2D graphics, XSLFPictureData data, | public boolean drawImage(Graphics2D graphics, XSLFPictureData data, | ||||
Rectangle2D anchor) { | Rectangle2D anchor) { | ||||
try { | 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; | return true; | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
return false; | return false; | ||||
} | } | ||||
/** | /** | ||||
* 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 | * @return a <code>BufferedImage</code> containing the decoded | ||||
* contents of the input, or <code>null</code>. | * 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()); | |||||
} | } | ||||
} | } |
protected String getRootElementName(){ | protected String getRootElementName(){ | ||||
return "notes"; | return "notes"; | ||||
} | } | ||||
@Override | |||||
public XSLFSheet getMasterSheet() { | |||||
return null; | |||||
} | |||||
} | } |
import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument; | import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.util.Map; | |||||
/** | /** | ||||
* Notes master object associated with this layout. | * Notes master object associated with this layout. | ||||
@Beta | @Beta | ||||
public class XSLFNotesMaster extends XSLFSheet { | public class XSLFNotesMaster extends XSLFSheet { | ||||
private CTNotesMaster _slide; | private CTNotesMaster _slide; | ||||
private Map<String, XSLFSlideLayout> _layouts; | |||||
private XSLFTheme _theme; | |||||
XSLFNotesMaster() { | XSLFNotesMaster() { | ||||
super(); | super(); | ||||
protected String getRootElementName(){ | protected String getRootElementName(){ | ||||
return "notesMaster"; | return "notesMaster"; | ||||
} | } | ||||
@Override | |||||
public XSLFSheet getMasterSheet() { | |||||
return null; | |||||
} | |||||
} | } |
import org.openxmlformats.schemas.presentationml.x2006.main.CTPictureNonVisual; | import org.openxmlformats.schemas.presentationml.x2006.main.CTPictureNonVisual; | ||||
import javax.imageio.ImageIO; | import javax.imageio.ImageIO; | ||||
import java.awt.*; | |||||
import java.awt.Graphics2D; | |||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.awt.image.BufferedImage; | import java.awt.image.BufferedImage; | ||||
import java.io.ByteArrayInputStream; | import java.io.ByteArrayInputStream; | ||||
/** | /** | ||||
* Represents a picture shape | |||||
* | |||||
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
} | } | ||||
@Override | @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(); | XSLFPictureData data = getPictureData(); | ||||
if(data == null) return; | if(data == null) return; | ||||
XSLFImageRendener renderer = (XSLFImageRendener)graphics.getRenderingHint(XSLFRenderingHint.IMAGE_RENDERER); | XSLFImageRendener renderer = (XSLFImageRendener)graphics.getRenderingHint(XSLFRenderingHint.IMAGE_RENDERER); | ||||
if(renderer == null) renderer = new XSLFImageRendener(); | if(renderer == null) renderer = new XSLFImageRendener(); | ||||
renderer.drawImage(graphics, data, getAnchor()); | renderer.drawImage(graphics, data, getAnchor()); | ||||
if (line != null){ | |||||
graphics.setPaint(line); | |||||
applyStroke(graphics); | |||||
graphics.draw(outline); | |||||
} | |||||
} | } | ||||
} | } |
package org.apache.poi.xslf.usermodel; | package org.apache.poi.xslf.usermodel; | ||||
import java.awt.*; | |||||
import java.awt.RenderingHints; | |||||
/** | /** | ||||
* | * | ||||
public static final XSLFRenderingHint GSAVE = new XSLFRenderingHint(1); | public static final XSLFRenderingHint GSAVE = new XSLFRenderingHint(1); | ||||
public static final XSLFRenderingHint GRESTORE = new XSLFRenderingHint(2); | public static final XSLFRenderingHint GRESTORE = new XSLFRenderingHint(2); | ||||
/** | |||||
* Use a custom image rendener | |||||
* | |||||
* @see XSLFImageRendener | |||||
*/ | |||||
public static final XSLFRenderingHint IMAGE_RENDERER = new XSLFRenderingHint(3); | 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; | |||||
} | } |
import org.apache.poi.util.Units; | import org.apache.poi.util.Units; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect; | 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; | import java.awt.geom.Rectangle2D; | ||||
/** | /** | ||||
_parent = parentShape; | _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 angle = getAngle(); | ||||
double dist = getDistance(); | 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); | graphics.translate(dx, dy); | ||||
Color fillColor = getFillColor(); | Color fillColor = getFillColor(); | ||||
if (fillColor != null) { | if (fillColor != null) { | ||||
graphics.setColor(fillColor); | graphics.setColor(fillColor); | ||||
graphics.fill(outline); | |||||
} | } | ||||
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); | graphics.translate(-dx, -dy); | ||||
} | } | ||||
@Override | @Override | ||||
public Rectangle2D getAnchor(){ | public Rectangle2D getAnchor(){ | ||||
return _parent.getAnchor(); | return _parent.getAnchor(); | ||||
public Color getFillColor() { | public Color getFillColor() { | ||||
XSLFTheme theme = getSheet().getTheme(); | XSLFTheme theme = getSheet().getTheme(); | ||||
CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject(); | 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(); | |||||
} | |||||
} | } | ||||
} | } |
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
import java.awt.*; | |||||
import java.awt.Graphics2D; | |||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
/** | /** | ||||
* Base super-class class for all shapes in PresentationML | |||||
* | |||||
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
public abstract class XSLFShape { | public abstract class XSLFShape { | ||||
/** | |||||
* | |||||
* @return the position of this shape within the drawing canvas. | |||||
* The coordinates are expressed in points | |||||
*/ | |||||
public abstract Rectangle2D getAnchor(); | 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); | public abstract void setAnchor(Rectangle2D anchor); | ||||
/** | |||||
* | |||||
* @return the xml bean holding this shape's data | |||||
*/ | |||||
public abstract XmlObject getXmlObject(); | public abstract XmlObject getXmlObject(); | ||||
/** | |||||
* | |||||
* @return human-readable name of this shape, e.g. "Rectange 3" | |||||
*/ | |||||
public abstract String getShapeName(); | 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(); | public abstract int getShapeId(); | ||||
/** | /** | ||||
*/ | */ | ||||
public abstract double getRotation(); | public abstract double getRotation(); | ||||
/** | |||||
* @param flip whether the shape is horizontally flipped | |||||
*/ | |||||
public abstract void setFlipHorizontal(boolean flip); | 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); | public abstract void setFlipVertical(boolean flip); | ||||
/** | /** | ||||
*/ | */ | ||||
public abstract boolean getFlipHorizontal(); | public abstract boolean getFlipHorizontal(); | ||||
/** | |||||
* Whether the shape is vertically flipped | |||||
* | |||||
* @return whether the shape is vertically flipped | |||||
*/ | |||||
public abstract boolean getFlipVertical(); | public abstract boolean getFlipVertical(); | ||||
/** | |||||
* Draw this shape into the supplied canvas | |||||
* | |||||
* @param graphics the graphics to draw into | |||||
*/ | |||||
public abstract void draw(Graphics2D graphics); | 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){ | protected void applyTransform(Graphics2D graphics){ | ||||
Rectangle2D anchor = getAnchor(); | Rectangle2D anchor = getAnchor(); | ||||
graphics.translate(-anchor.getX(), -anchor.getY()); | graphics.translate(-anchor.getX(), -anchor.getY()); | ||||
} | } | ||||
} | } | ||||
} | } |
import org.apache.poi.openxml4j.opc.PackageRelationship; | import org.apache.poi.openxml4j.opc.PackageRelationship; | ||||
import org.apache.poi.openxml4j.opc.TargetMode; | import org.apache.poi.openxml4j.opc.TargetMode; | ||||
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.apache.poi.util.Internal; | |||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
import org.apache.xmlbeans.XmlOptions; | 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.officeDocument.x2006.relationships.STRelationshipId; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData; | import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; | import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | ||||
import javax.xml.namespace.QName; | import javax.xml.namespace.QName; | ||||
import java.awt.*; | |||||
import java.awt.Graphics2D; | |||||
import java.awt.geom.AffineTransform; | import java.awt.geom.AffineTransform; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Iterator; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||
@Beta | @Beta | ||||
public abstract class XSLFSheet extends POIXMLDocumentPart { | |||||
public abstract class XSLFSheet extends POIXMLDocumentPart implements Iterable<XSLFShape> { | |||||
private XSLFCommonSlideData _commonSlideData; | private XSLFCommonSlideData _commonSlideData; | ||||
private XSLFDrawing _drawing; | private XSLFDrawing _drawing; | ||||
private List<XSLFShape> _shapes; | private List<XSLFShape> _shapes; | ||||
private CTGroupShape _spTree; | private CTGroupShape _spTree; | ||||
private List<XSLFTextShape>_placeholders; | |||||
private Map<Integer, XSLFSimpleShape> _placeholderByIdMap; | private Map<Integer, XSLFSimpleShape> _placeholderByIdMap; | ||||
private Map<Integer, XSLFSimpleShape> _placeholderByTypeMap; | private Map<Integer, XSLFSimpleShape> _placeholderByTypeMap; | ||||
super(part, rel); | super(part, rel); | ||||
} | } | ||||
/** | |||||
* | |||||
* @return the XMLSlideShow this sheet belongs to | |||||
*/ | |||||
public XMLSlideShow getSlideShow() { | public XMLSlideShow getSlideShow() { | ||||
POIXMLDocumentPart p = getParent(); | POIXMLDocumentPart p = getParent(); | ||||
while(p != null) { | while(p != null) { | ||||
} | } | ||||
p = p.getParent(); | p = p.getParent(); | ||||
} | } | ||||
return null; | |||||
throw new IllegalStateException("SlideShow was not found"); | |||||
} | } | ||||
protected List<XSLFShape> buildShapes(CTGroupShape spTree){ | protected List<XSLFShape> buildShapes(CTGroupShape spTree){ | ||||
return shapes; | return shapes; | ||||
} | } | ||||
/** | |||||
* @return top-level Xml bean representing this sheet | |||||
*/ | |||||
public abstract XmlObject getXmlObject(); | public abstract XmlObject getXmlObject(); | ||||
@Internal | |||||
public XSLFCommonSlideData getCommonSlideData() { | public XSLFCommonSlideData getCommonSlideData() { | ||||
return _commonSlideData; | return _commonSlideData; | ||||
} | } | ||||
protected void setCommonSlideData(CTCommonSlideData data) { | protected void setCommonSlideData(CTCommonSlideData data) { | ||||
if(data == null) { | if(data == null) { | ||||
_commonSlideData = null; | _commonSlideData = null; | ||||
return sh; | 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(){ | public XSLFShape[] getShapes(){ | ||||
return getShapeList().toArray(new XSLFShape[_shapes.size()]); | 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) { | public boolean removeShape(XSLFShape xShape) { | ||||
XmlObject obj = xShape.getXmlObject(); | XmlObject obj = xShape.getXmlObject(); | ||||
CTGroupShape spTree = getSpTree(); | CTGroupShape spTree = getSpTree(); | ||||
return getShapeList().remove(xShape); | return getShapeList().remove(xShape); | ||||
} | } | ||||
public XSLFBackground getBackground(){ | |||||
return null; | |||||
} | |||||
protected abstract String getRootElementName(); | protected abstract String getRootElementName(); | ||||
protected CTGroupShape getSpTree(){ | protected CTGroupShape getSpTree(){ | ||||
getXmlObject().set(src.getXmlObject()); | getXmlObject().set(src.getXmlObject()); | ||||
} | } | ||||
public XSLFTheme getTheme(){ | |||||
return null; | |||||
} | |||||
public XSLFSlideMaster getSlideMaster(){ | |||||
/** | |||||
* @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; | return null; | ||||
} | } | ||||
public XSLFSlideLayout getSlideLayout(){ | |||||
return null; | |||||
} | |||||
/** | |||||
* | |||||
* @return master of this sheet. | |||||
*/ | |||||
public abstract XSLFSheet getMasterSheet(); | |||||
protected CTTextListStyle getTextProperties(Placeholder textType) { | |||||
return null; | |||||
} | |||||
protected XSLFTextShape getTextShapeByType(Placeholder type){ | protected XSLFTextShape getTextShapeByType(Placeholder type){ | ||||
for(XSLFShape shape : this.getShapes()){ | for(XSLFShape shape : this.getShapes()){ | ||||
if(shape instanceof XSLFTextShape) { | if(shape instanceof XSLFTextShape) { | ||||
return shape; | return shape; | ||||
} | } | ||||
XSLFSimpleShape getPlaceholderById(int id) { | |||||
if(_placeholderByIdMap == null) { | |||||
void initPlaceholders() { | |||||
if(_placeholders == null) { | |||||
_placeholders = new ArrayList<XSLFTextShape>(); | |||||
_placeholderByIdMap = new HashMap<Integer, XSLFSimpleShape>(); | _placeholderByIdMap = new HashMap<Integer, XSLFSimpleShape>(); | ||||
_placeholderByTypeMap = new HashMap<Integer, XSLFSimpleShape>(); | |||||
for(XSLFShape sh : getShapes()){ | for(XSLFShape sh : getShapes()){ | ||||
if(sh instanceof XSLFSimpleShape){ | |||||
XSLFSimpleShape sShape = (XSLFSimpleShape)sh; | |||||
if(sh instanceof XSLFTextShape){ | |||||
XSLFTextShape sShape = (XSLFTextShape)sh; | |||||
CTPlaceholder ph = sShape.getCTPlaceholder(); | 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); | return _placeholderByIdMap.get(id); | ||||
} | } | ||||
XSLFSimpleShape getPlaceholderByType(int ordinal) { | 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); | 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. | * 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){ | protected boolean canDraw(XSLFShape shape){ | ||||
return true; | 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 | * Render this sheet into the supplied graphics object | ||||
* | * | ||||
* @param graphics | * @param graphics | ||||
*/ | */ | ||||
public void draw(Graphics2D 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()) { | for(XSLFShape shape : getShapeList()) { | ||||
if(!canDraw(shape)) continue; | if(!canDraw(shape)) continue; | ||||
// remember the initial transform and restore it after we are done with drawing | // 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); | graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true); | ||||
// apply rotation and flipping | // apply rotation and flipping | ||||
shape.applyTransform(graphics); | shape.applyTransform(graphics); | ||||
// draw stuff | |||||
shape.draw(graphics); | shape.draw(graphics); | ||||
// restore the coordinate system | // restore the coordinate system | ||||
graphics.setTransform(at0); | |||||
graphics.setTransform(at); | |||||
graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true); | graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true); | ||||
} | } |
package org.apache.poi.xslf.usermodel; | 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.Beta; | ||||
import org.apache.poi.util.Units; | import org.apache.poi.util.Units; | ||||
import org.apache.poi.xslf.model.PropertyFetcher; | import org.apache.poi.xslf.model.PropertyFetcher; | ||||
import org.apache.poi.xslf.model.geom.CustomGeometry; | import org.apache.poi.xslf.model.geom.CustomGeometry; | ||||
import org.apache.poi.xslf.model.geom.Guide; | import org.apache.poi.xslf.model.geom.Guide; | ||||
import org.apache.poi.xslf.model.geom.IAdjustableShape; | 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.Path; | ||||
import org.apache.poi.xslf.model.geom.PresetGeometries; | import org.apache.poi.xslf.model.geom.PresetGeometries; | ||||
import org.apache.xmlbeans.XmlObject; | 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.CTPlaceholder; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | 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.AffineTransform; | ||||
import java.awt.geom.GeneralPath; | import java.awt.geom.GeneralPath; | ||||
import java.awt.geom.Point2D; | |||||
import java.awt.geom.Rectangle2D; | 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 | * @author Yegor Kozlov | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
public abstract class XSLFSimpleShape extends XSLFShape { | public abstract class XSLFSimpleShape extends XSLFShape { | ||||
private final XmlObject _shape; | private final XmlObject _shape; | ||||
private final XSLFSheet _sheet; | private final XSLFSheet _sheet; | ||||
private CTShapeProperties _spPr; | private CTShapeProperties _spPr; | ||||
_sheet = sheet; | _sheet = sheet; | ||||
} | } | ||||
@Override | |||||
public XmlObject getXmlObject() { | public XmlObject getXmlObject() { | ||||
return _shape; | return _shape; | ||||
} | } | ||||
/** | |||||
* | |||||
* @return the sheet this shape belongs to | |||||
*/ | |||||
public XSLFSheet getSheet() { | public XSLFSheet getSheet() { | ||||
return _sheet; | return _sheet; | ||||
} | } | ||||
return stEnum == null ? 0 : stEnum.intValue(); | return stEnum == null ? 0 : stEnum.intValue(); | ||||
} | } | ||||
@Override | |||||
public String getShapeName() { | public String getShapeName() { | ||||
return getNvPr().getName(); | return getNvPr().getName(); | ||||
} | } | ||||
@Override | |||||
public int getShapeId() { | public int getShapeId() { | ||||
return (int) getNvPr().getId(); | return (int) getNvPr().getId(); | ||||
} | } | ||||
return _spStyle; | return _spStyle; | ||||
} | } | ||||
protected CTPlaceholder getCTPlaceholder(){ | |||||
if(_ph == null){ | |||||
protected CTPlaceholder getCTPlaceholder() { | |||||
if (_ph == null) { | |||||
XmlObject[] obj = _shape.selectPath( | XmlObject[] obj = _shape.selectPath( | ||||
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:nvPr/p:ph"); | "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; | 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(); | CTShapeProperties pr = shape.getSpPr(); | ||||
if(pr.isSetXfrm()){ | |||||
if (pr.isSetXfrm()) { | |||||
setValue(pr.getXfrm()); | setValue(pr.getXfrm()); | ||||
return true; | return true; | ||||
} | } | ||||
return fetcher.getValue(); | return fetcher.getValue(); | ||||
} | } | ||||
@Override | |||||
public Rectangle2D getAnchor() { | public Rectangle2D getAnchor() { | ||||
CTTransform2D xfrm = getXfrm(); | CTTransform2D xfrm = getXfrm(); | ||||
CTPoint2D off = xfrm.getOff(); | CTPoint2D off = xfrm.getOff(); | ||||
long x = off.getX(); | long x = off.getX(); | ||||
long y = off.getY(); | long y = off.getY(); | ||||
Units.toPoints(cx), Units.toPoints(cy)); | Units.toPoints(cx), Units.toPoints(cy)); | ||||
} | } | ||||
@Override | |||||
public void setAnchor(Rectangle2D anchor) { | public void setAnchor(Rectangle2D anchor) { | ||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); | CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); | ||||
ext.setCy(cy); | 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) { | public void setRotation(double theta) { | ||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); | CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); | ||||
xfrm.setRot((int) (theta * 60000)); | 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() { | public double getRotation() { | ||||
CTTransform2D xfrm = getXfrm(); | CTTransform2D xfrm = getXfrm(); | ||||
return (double) xfrm.getRot() / 60000; | return (double) xfrm.getRot() / 60000; | ||||
} | } | ||||
@Override | |||||
public void setFlipHorizontal(boolean flip) { | public void setFlipHorizontal(boolean flip) { | ||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); | CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); | ||||
xfrm.setFlipH(flip); | xfrm.setFlipH(flip); | ||||
} | } | ||||
@Override | |||||
public void setFlipVertical(boolean flip) { | public void setFlipVertical(boolean flip) { | ||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); | CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); | ||||
xfrm.setFlipV(flip); | xfrm.setFlipV(flip); | ||||
} | } | ||||
/** | |||||
* Whether the shape is horizontally flipped | |||||
* | |||||
* @return whether the shape is horizontally flipped | |||||
*/ | |||||
@Override | |||||
public boolean getFlipHorizontal() { | public boolean getFlipHorizontal() { | ||||
return getXfrm().getFlipH(); | return getXfrm().getFlipH(); | ||||
} | } | ||||
@Override | |||||
public boolean getFlipVertical() { | public boolean getFlipVertical() { | ||||
return getXfrm().getFlipV(); | 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 | * @return line propeties from the theme of null | ||||
*/ | */ | ||||
return ln; | 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) { | public void setLineColor(Color color) { | ||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
if (color == null) { | if (color == null) { | ||||
} | } | ||||
} | } | ||||
/** | |||||
* | |||||
* @return the color of the shape outline or <code>null</code> | |||||
* if outline is turned off | |||||
*/ | |||||
public Color getLineColor() { | 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; | 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) { | public void setLineWidth(double width) { | ||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
if (width == 0.) { | if (width == 0.) { | ||||
} | } | ||||
} | } | ||||
/** | |||||
* | |||||
* @return line width in points. <code>0</code> means no line. | |||||
*/ | |||||
public double getLineWidth() { | 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(); | CTShapeProperties spPr = shape.getSpPr(); | ||||
CTLineProperties ln = spPr.getLn(); | CTLineProperties ln = spPr.getLn(); | ||||
if (ln != null) { | if (ln != null) { | ||||
} | } | ||||
if (ln.isSetW()) { | if (ln.isSetW()) { | ||||
setValue( Units.toPoints(ln.getW()) ); | |||||
setValue(Units.toPoints(ln.getW())); | |||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
double lineWidth = 0; | double lineWidth = 0; | ||||
if(fetcher.getValue() == null) { | |||||
if (fetcher.getValue() == null) { | |||||
CTLineProperties defaultLn = getDefaultLineProperties(); | CTLineProperties defaultLn = getDefaultLineProperties(); | ||||
if (defaultLn != null) { | if (defaultLn != null) { | ||||
if (defaultLn.isSetW()) lineWidth = Units.toPoints(defaultLn.getW()); | if (defaultLn.isSetW()) lineWidth = Units.toPoints(defaultLn.getW()); | ||||
return lineWidth; | return lineWidth; | ||||
} | } | ||||
/** | |||||
* | |||||
* @param dash a preset line dashing scheme to stroke thr shape outline | |||||
*/ | |||||
public void setLineDash(LineDash dash) { | public void setLineDash(LineDash dash) { | ||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
if (dash == null) { | if (dash == null) { | ||||
} | } | ||||
} | } | ||||
/** | |||||
* @return a preset line dashing scheme to stroke thr shape outline | |||||
*/ | |||||
public LineDash getLineDash() { | 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(); | CTShapeProperties spPr = shape.getSpPr(); | ||||
CTLineProperties ln = spPr.getLn(); | CTLineProperties ln = spPr.getLn(); | ||||
if (ln != null) { | if (ln != null) { | ||||
CTPresetLineDashProperties ctDash = ln.getPrstDash(); | CTPresetLineDashProperties ctDash = ln.getPrstDash(); | ||||
if (ctDash != null) { | if (ctDash != null) { | ||||
setValue( LineDash.values()[ctDash.getVal().intValue() - 1] ); | |||||
setValue(LineDash.values()[ctDash.getVal().intValue() - 1]); | |||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
LineDash dash = fetcher.getValue(); | LineDash dash = fetcher.getValue(); | ||||
if(dash == null){ | |||||
if (dash == null) { | |||||
CTLineProperties defaultLn = getDefaultLineProperties(); | CTLineProperties defaultLn = getDefaultLineProperties(); | ||||
if (defaultLn != null) { | if (defaultLn != null) { | ||||
CTPresetLineDashProperties ctDash = defaultLn.getPrstDash(); | CTPresetLineDashProperties ctDash = defaultLn.getPrstDash(); | ||||
return dash; | return dash; | ||||
} | } | ||||
/** | |||||
* | |||||
* @param cap the line end cap style | |||||
*/ | |||||
public void setLineCap(LineCap cap) { | public void setLineCap(LineCap cap) { | ||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
if (cap == null) { | if (cap == null) { | ||||
} | } | ||||
} | } | ||||
/** | |||||
* | |||||
* @return the line end cap style | |||||
*/ | |||||
public LineCap getLineCap() { | 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(); | CTShapeProperties spPr = shape.getSpPr(); | ||||
CTLineProperties ln = spPr.getLn(); | CTLineProperties ln = spPr.getLn(); | ||||
if (ln != null) { | if (ln != null) { | ||||
STLineCap.Enum stCap = ln.getCap(); | STLineCap.Enum stCap = ln.getCap(); | ||||
if (stCap != null) { | if (stCap != null) { | ||||
setValue( LineCap.values()[stCap.intValue() - 1] ); | |||||
setValue(LineCap.values()[stCap.intValue() - 1]); | |||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
LineCap cap = fetcher.getValue(); | LineCap cap = fetcher.getValue(); | ||||
if(cap == null){ | |||||
if (cap == null) { | |||||
CTLineProperties defaultLn = getDefaultLineProperties(); | CTLineProperties defaultLn = getDefaultLineProperties(); | ||||
if (defaultLn != null) { | if (defaultLn != null) { | ||||
STLineCap.Enum stCap = defaultLn.getCap(); | STLineCap.Enum stCap = defaultLn.getCap(); | ||||
if (color == null) { | if (color == null) { | ||||
if (spPr.isSetSolidFill()) spPr.unsetSolidFill(); | if (spPr.isSetSolidFill()) spPr.unsetSolidFill(); | ||||
if(!spPr.isSetNoFill()) spPr.addNewNoFill(); | |||||
if (!spPr.isSetNoFill()) spPr.addNewNoFill(); | |||||
} else { | } else { | ||||
if(spPr.isSetNoFill()) spPr.unsetNoFill(); | |||||
if (spPr.isSetNoFill()) spPr.unsetNoFill(); | |||||
CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr | CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr | ||||
.getSolidFill() : spPr.addNewSolidFill(); | .getSolidFill() : spPr.addNewSolidFill(); | ||||
} | } | ||||
/** | /** | ||||
* @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() { | 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; | 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(); | CTShapeProperties spPr = shape.getSpPr(); | ||||
if (spPr.isSetEffectLst()) { | if (spPr.isSetEffectLst()) { | ||||
CTOuterShadowEffect obj = spPr.getEffectLst().getOuterShdw(); | CTOuterShadowEffect obj = spPr.getEffectLst().getOuterShdw(); | ||||
fetchShapeProperty(fetcher); | fetchShapeProperty(fetcher); | ||||
CTOuterShadowEffect obj = fetcher.getValue(); | CTOuterShadowEffect obj = fetcher.getValue(); | ||||
if(obj == null){ | |||||
if (obj == null) { | |||||
// fill color was not found, check if it is defined in the theme | // fill color was not found, check if it is defined in the theme | ||||
CTShapeStyle style = getSpStyle(); | CTShapeStyle style = getSpStyle(); | ||||
if (style != null) { | if (style != null) { | ||||
// 1-based index of a shadow style within the style matrix | // 1-based index of a shadow style within the style matrix | ||||
int idx = (int) style.getEffectRef().getIdx(); | 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); | return obj == null ? null : new XSLFShadow(obj, this); | ||||
} | } | ||||
@Override | |||||
public void draw(Graphics2D graphics) { | public void draw(Graphics2D 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; | |||||
RenderableShape rShape = new RenderableShape(this); | |||||
rShape.render(graphics); | |||||
} | } | ||||
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. | |||||
* | |||||
* slide <-- slideLayout <-- slideMaster | |||||
* Walk up the inheritance tree and fetch shape properties. | |||||
* | * | ||||
* 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 | * @return true if the property was fetched | ||||
*/ | */ | ||||
boolean fetchShapeProperty(PropertyFetcher visitor){ | |||||
boolean fetchShapeProperty(PropertyFetcher visitor) { | |||||
boolean ok = visitor.fetch(this); | boolean ok = visitor.fetch(this); | ||||
XSLFSimpleShape masterShape; | 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(); | CTPlaceholder ph = getCTPlaceholder(); | ||||
if (ph != null) { | if (ph != null) { | ||||
masterShape = layout.getPlaceholder(ph); | masterShape = layout.getPlaceholder(ph); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
// 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; | return ok; | ||||
} | } | ||||
@Override | |||||
protected java.awt.Shape getOutline(){ | |||||
PresetGeometries dict = PresetGeometries.getInstance(); | |||||
/** | |||||
* | |||||
* @return definition of the shape geometry | |||||
*/ | |||||
CustomGeometry getGeometry(){ | |||||
CTShapeProperties spPr = getSpPr(); | CTShapeProperties spPr = getSpPr(); | ||||
String name; | |||||
if(spPr.isSetPrstGeom()) { | |||||
name = spPr.getPrstGeom().getPrst().toString(); | |||||
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); | |||||
} | |||||
} else if (spPr.isSetCustGeom()){ | |||||
geom = new CustomGeometry(spPr.getCustGeom()); | |||||
} else { | } else { | ||||
name = "rect"; | |||||
geom = dict.get("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; | |||||
} | |||||
return geom; | |||||
} | |||||
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); | |||||
} | |||||
/** | |||||
* @return any shape-specific geometry that is not included in presetShapeDefinitions.xml | |||||
* (line decorations, etc) | |||||
*/ | |||||
List<Outline> getCustomOutlines(){ | |||||
return Collections.emptyList(); | |||||
} | |||||
// 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 { | |||||
return anchor; | |||||
} | |||||
} | |||||
/** | |||||
* draw any content within this shape (image, text, etc.). | |||||
* | |||||
* @param graphics the graphics to draw into | |||||
*/ | |||||
public void drawContent(Graphics2D graphics){ | |||||
} | |||||
} | } |
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide; | import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument; | import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument; | ||||
import java.awt.*; | |||||
import java.awt.Graphics2D; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
@Beta | @Beta | ||||
return "sld"; | return "sld"; | ||||
} | } | ||||
public XSLFSlideMaster getMasterSheet(){ | |||||
return getSlideLayout().getSlideMaster(); | |||||
@Override | |||||
public XSLFSlideLayout getMasterSheet(){ | |||||
return getSlideLayout(); | |||||
} | } | ||||
@Override | |||||
public XSLFSlideLayout getSlideLayout(){ | public XSLFSlideLayout getSlideLayout(){ | ||||
if(_layout == null){ | if(_layout == null){ | ||||
for (POIXMLDocumentPart p : getRelations()) { | for (POIXMLDocumentPart p : getRelations()) { | ||||
return _layout; | return _layout; | ||||
} | } | ||||
@Override | |||||
public XSLFSlideMaster getSlideMaster(){ | public XSLFSlideMaster getSlideMaster(){ | ||||
return getSlideLayout().getSlideMaster(); | return getSlideLayout().getSlideMaster(); | ||||
} | } | ||||
} | } | ||||
if(_notes == null) { | if(_notes == null) { | ||||
// This slide lacks notes | // This slide lacks notes | ||||
// Not al have them, sorry... | |||||
// Not all have them, sorry... | |||||
return null; | return null; | ||||
} | } | ||||
return _notes; | 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 | * @return title of this slide or empty string if title is not set | ||||
return txt == null ? "" : txt.getText(); | return txt == null ? "" : txt.getText(); | ||||
} | } | ||||
@Override | |||||
public XSLFTheme getTheme(){ | public XSLFTheme getTheme(){ | ||||
return getSlideLayout().getSlideMaster().getTheme(); | return getSlideLayout().getSlideMaster().getTheme(); | ||||
} | } | ||||
@Override | |||||
public void draw(Graphics2D graphics){ | |||||
if (getFollowMasterBackground()){ | |||||
XSLFSlideLayout layout = getSlideLayout(); | |||||
layout.draw(graphics); | |||||
} | |||||
/** | |||||
* | |||||
* @return the information about background appearance of this slide | |||||
*/ | |||||
public XSLFBackground getBackground() { | |||||
super.draw(graphics); | |||||
} | |||||
@Override | |||||
public XSLFBackground getBackground(){ | |||||
if(_slide.getCSld().isSetBg()) { | if(_slide.getCSld().isSetBg()) { | ||||
return new XSLFBackground(_slide.getCSld().getBg(), this); | 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 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); | |||||
} | |||||
} | } |
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.apache.poi.util.Internal; | import org.apache.poi.util.Internal; | ||||
import org.apache.xmlbeans.XmlException; | 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.CTPlaceholder; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideLayout; | import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideLayout; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldLayoutDocument; | import org.openxmlformats.schemas.presentationml.x2006.main.SldLayoutDocument; | ||||
public XSLFSlideLayout(PackagePart part, PackageRelationship rel) throws IOException, XmlException { | public XSLFSlideLayout(PackagePart part, PackageRelationship rel) throws IOException, XmlException { | ||||
super(part, rel); | super(part, rel); | ||||
SldLayoutDocument doc = | SldLayoutDocument doc = | ||||
SldLayoutDocument.Factory.parse(getPackagePart().getInputStream()); | |||||
SldLayoutDocument.Factory.parse(getPackagePart().getInputStream()); | |||||
_layout = doc.getSldLayout(); | _layout = doc.getSldLayout(); | ||||
setCommonSlideData(_layout.getCSld()); | setCommonSlideData(_layout.getCSld()); | ||||
} | } | ||||
public String getName(){ | |||||
public String getName() { | |||||
return _layout.getCSld().getName(); | return _layout.getCSld().getName(); | ||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
protected String getRootElementName(){ | |||||
protected String getRootElementName() { | |||||
return "sldLayout"; | return "sldLayout"; | ||||
} | } | ||||
/** | /** | ||||
* Slide master object associated with this layout. | * 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. | * @return slide master. Never null. | ||||
* @throws IllegalStateException if slide master was not found | * @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()) { | 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()); | throw new IllegalStateException("SlideMaster was not found for " + this.toString()); | ||||
} | } | ||||
return _master; | return _master; | ||||
} | } | ||||
public XSLFTheme getTheme(){ | |||||
return getSlideMaster().getTheme(); | |||||
} | |||||
@Override | |||||
public XSLFSlideMaster getMasterSheet() { | |||||
return getSlideMaster(); | |||||
} | |||||
@Override | |||||
public XSLFTheme getTheme() { | |||||
return getSlideMaster().getTheme(); | |||||
} | |||||
@Override | @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 | * Render this sheet into the supplied graphics object | ||||
* | |||||
*/ | */ | ||||
@Override | @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(); | CTPlaceholder ph = txt.getCTPlaceholder(); | ||||
if(ph != null) { | |||||
if (ph != null) { | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | 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]; | |||||
} | } | ||||
} | } |
import org.apache.poi.openxml4j.opc.PackageRelationship; | import org.apache.poi.openxml4j.opc.PackageRelationship; | ||||
import org.apache.poi.util.Beta; | import org.apache.poi.util.Beta; | ||||
import org.apache.xmlbeans.XmlException; | 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.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.CTSlideMaster; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterTextStyles; | import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterTextStyles; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument; | import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument; | ||||
return "sldMaster"; | return "sldMaster"; | ||||
} | } | ||||
public XSLFSlideLayout getLayout(String name){ | |||||
@Override | |||||
public XSLFSheet getMasterSheet() { | |||||
return null; | |||||
} | |||||
private Map<String, XSLFSlideLayout> getLayouts(){ | |||||
if(_layouts == null){ | if(_layouts == null){ | ||||
_layouts = new HashMap<String, XSLFSlideLayout>(); | _layouts = new HashMap<String, XSLFSlideLayout>(); | ||||
for (POIXMLDocumentPart p : getRelations()) { | for (POIXMLDocumentPart p : getRelations()) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
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(){ | public XSLFTheme getTheme(){ | ||||
if(_theme == null){ | if(_theme == null){ | ||||
for (POIXMLDocumentPart p : getRelations()) { | for (POIXMLDocumentPart p : getRelations()) { | ||||
if (p instanceof XSLFTheme){ | if (p instanceof XSLFTheme){ | ||||
_theme = (XSLFTheme)p; | _theme = (XSLFTheme)p; | ||||
CTColorMapping cmap = _slide.getClrMap(); | |||||
if(cmap != null){ | |||||
_theme.initColorMap(cmap); | |||||
} | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return props; | return props; | ||||
} | } | ||||
/** | |||||
* Render this sheet into the supplied graphics object | |||||
* | |||||
*/ | |||||
@Override | @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; | |||||
} | } | ||||
} | } |
import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment; | import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; | 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 | * Represents a cell of a table in a .pptx presentation | ||||
} | } | ||||
@Override | @Override | ||||
public void setMarginLeft(double margin){ | |||||
public void setLeftInset(double margin){ | |||||
CTTableCellProperties pr = getXmlObject().getTcPr(); | CTTableCellProperties pr = getXmlObject().getTcPr(); | ||||
if(pr == null) pr = getXmlObject().addNewTcPr(); | if(pr == null) pr = getXmlObject().addNewTcPr(); | ||||
} | } | ||||
@Override | @Override | ||||
public void setMarginRight(double margin){ | |||||
public void setRightInset(double margin){ | |||||
CTTableCellProperties pr = getXmlObject().getTcPr(); | CTTableCellProperties pr = getXmlObject().getTcPr(); | ||||
if(pr == null) pr = getXmlObject().addNewTcPr(); | if(pr == null) pr = getXmlObject().addNewTcPr(); | ||||
} | } | ||||
@Override | @Override | ||||
public void setMarginTop(double margin){ | |||||
public void setTopInset(double margin){ | |||||
CTTableCellProperties pr = getXmlObject().getTcPr(); | CTTableCellProperties pr = getXmlObject().getTcPr(); | ||||
if(pr == null) pr = getXmlObject().addNewTcPr(); | if(pr == null) pr = getXmlObject().addNewTcPr(); | ||||
} | } | ||||
@Override | @Override | ||||
public void setMarginBottom(double margin){ | |||||
public void setBottomInset(double margin){ | |||||
CTTableCellProperties pr = getXmlObject().getTcPr(); | CTTableCellProperties pr = getXmlObject().getTcPr(); | ||||
if(pr == null) pr = getXmlObject().addNewTcPr(); | if(pr == null) pr = getXmlObject().addNewTcPr(); | ||||
return ct; | 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)); | |||||
} | |||||
} | |||||
} | } |
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; | ||||
import java.awt.*; | |||||
import java.awt.Color; | |||||
import java.awt.Graphics2D; | |||||
import java.awt.font.LineBreakMeasurer; | import java.awt.font.LineBreakMeasurer; | ||||
import java.awt.font.TextAttribute; | import java.awt.font.TextAttribute; | ||||
import java.awt.font.TextLayout; | import java.awt.font.TextLayout; | ||||
return out.toString(); | 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 | @Internal | ||||
public CTTextParagraph getXmlObject(){ | public CTTextParagraph getXmlObject(){ | ||||
return _p; | return _p; | ||||
return _shape; | return _shape; | ||||
} | } | ||||
public List<XSLFTextRun> getTextRuns(){ | public List<XSLFTextRun> getTextRuns(){ | ||||
return _runs; | return _runs; | ||||
} | } | ||||
ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getLevel()){ | ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getLevel()){ | ||||
public boolean fetch(CTTextParagraphProperties props){ | public boolean fetch(CTTextParagraphProperties props){ | ||||
if(props.isSetBuClr()){ | if(props.isSetBuClr()){ | ||||
XSLFColor c = new XSLFColor(props.getBuClr(), theme); | |||||
XSLFColor c = new XSLFColor(props.getBuClr(), theme, null); | |||||
setValue(c.getColor()); | setValue(c.getColor()); | ||||
return true; | return true; | ||||
} | } | ||||
return "[" + getClass() + "]" + getText(); | return "[" + getClass() + "]" + getText(); | ||||
} | } | ||||
public List<TextFragment> getTextLines(){ | |||||
List<TextFragment> getTextLines(){ | |||||
return _lines; | return _lines; | ||||
} | } | ||||
public double draw(Graphics2D graphics, double x, double y){ | 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(); | Rectangle2D anchor = _shape.getAnchor(); | ||||
double penY = y; | double penY = y; | ||||
double textOffset = getLeftMargin(); | double textOffset = getLeftMargin(); | ||||
boolean firstLine = true; | |||||
for(TextFragment line : _lines){ | for(TextFragment line : _lines){ | ||||
double penX = x; | double penX = x; | ||||
switch (getTextAlign()) { | switch (getTextAlign()) { | ||||
break; | break; | ||||
} | } | ||||
if(_bullet != null){ | |||||
if(_bullet != null && firstLine){ | |||||
_bullet.draw(graphics, penX + getIndent(), penY); | _bullet.draw(graphics, penX + getIndent(), penY); | ||||
} | } | ||||
line.draw(graphics, penX, penY); | line.draw(graphics, penX, penY); | ||||
// positive value means absolute spacing in points | // positive value means absolute spacing in points | ||||
penY += -spacing; | penY += -spacing; | ||||
} | } | ||||
firstLine = false; | |||||
} | } | ||||
return penY - y; | return penY - y; | ||||
} | } | ||||
void draw(Graphics2D graphics, double x, double y){ | void draw(Graphics2D graphics, double x, double y){ | ||||
double yBaseline = y + _layout.getAscent(); | 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(){ | public float getHeight(){ | ||||
} | } | ||||
public AttributedString getAttributedString(){ | |||||
String text = getText(); | |||||
AttributedString getAttributedString(Graphics2D graphics){ | |||||
String text = getVisibleText(); | |||||
AttributedString string = new AttributedString(text); | AttributedString string = new AttributedString(text); | ||||
int endIndex = startIndex + length; | int endIndex = startIndex + length; | ||||
string.addAttribute(TextAttribute.FOREGROUND, run.getFontColor(), startIndex, endIndex); | 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.FAMILY, run.getFontFamily(), startIndex, endIndex); | ||||
string.addAttribute(TextAttribute.SIZE, (float)run.getFontSize(), startIndex, endIndex); | string.addAttribute(TextAttribute.SIZE, (float)run.getFontSize(), startIndex, endIndex); | ||||
if(run.isBold()) { | if(run.isBold()) { | ||||
string.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIndex, endIndex); | string.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIndex, endIndex); | ||||
string.addAttribute(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, startIndex, endIndex); | string.addAttribute(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, startIndex, endIndex); | ||||
} | } | ||||
startIndex = endIndex; | startIndex = endIndex; | ||||
} | } | ||||
void breakText(Graphics2D graphics){ | void breakText(Graphics2D graphics){ | ||||
_lines = new ArrayList<TextFragment>(); | _lines = new ArrayList<TextFragment>(); | ||||
AttributedString at = getAttributedString(); | |||||
AttributedString at = getAttributedString(graphics); | |||||
AttributedCharacterIterator it = at.getIterator(); | AttributedCharacterIterator it = at.getIterator(); | ||||
if(it.getBeginIndex() == it.getEndIndex()) { | if(it.getBeginIndex() == it.getEndIndex()) { | ||||
return; | return; | ||||
int endIndex = measurer.getPosition(); | int endIndex = measurer.getPosition(); | ||||
if(getTextAlign() == TextAlign.JUSTIFY) { | |||||
TextAlign hAlign = getTextAlign(); | |||||
if(hAlign == TextAlign.JUSTIFY || hAlign == TextAlign.JUSTIFY_LOW) { | |||||
layout = layout.getJustifiedLayout((float)wrappingWidth); | layout = layout.getJustifiedLayout((float)wrappingWidth); | ||||
} | } | ||||
width = _shape.getSheet().getSlideShow().getPageSize().getWidth(); | width = _shape.getSheet().getSlideShow().getPageSize().getWidth(); | ||||
} else { | } else { | ||||
width = _shape.getAnchor().getWidth() - | width = _shape.getAnchor().getWidth() - | ||||
_shape.getMarginLeft() - _shape.getMarginRight() - getLeftMargin(); | |||||
_shape.getLeftInset() - _shape.getRightInset() - getLeftMargin(); | |||||
} | } | ||||
return width; | return width; | ||||
} | } | ||||
} | } | ||||
int level = getLevel(); | 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 p='http://schemas.openxmlformats.org/presentationml/2006/main' " + | ||||
"declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " + | "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " + | ||||
".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr"); | ".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr"); |
import org.apache.poi.xslf.model.CharacterPropertyFetcher; | import org.apache.poi.xslf.model.CharacterPropertyFetcher; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; | import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor; | 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.CTSolidColorFillProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont; | 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.CTTextParagraphProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType; | import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType; | 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 | * Represents a run of text within the containing text body. The run element is the | ||||
public Color getFontColor(){ | public Color getFontColor(){ | ||||
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme(); | 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()){ | CharacterPropertyFetcher<Color> fetcher = new CharacterPropertyFetcher<Color>(_p.getLevel()){ | ||||
public boolean fetch(CTTextCharacterProperties props){ | public boolean fetch(CTTextCharacterProperties props){ | ||||
CTSolidColorFillProperties solidFill = props.getSolidFill(); | 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); | setValue(c); | ||||
return true; | return true; | ||||
} | } | ||||
* @return font size in points or -1 if font size is not set. | * @return font size in points or -1 if font size is not set. | ||||
*/ | */ | ||||
public double getFontSize(){ | 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()){ | CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getLevel()){ | ||||
public boolean fetch(CTTextCharacterProperties props){ | public boolean fetch(CTTextCharacterProperties props){ | ||||
if(props.isSetSz()){ | if(props.isSetSz()){ | ||||
} | } | ||||
}; | }; | ||||
fetchCharacterProperty(fetcher); | 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(); | |||||
} | } | ||||
/** | /** | ||||
return fetcher.getValue() == null ? false : fetcher.getValue(); | 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 | * Specifies whether this run of text will be formatted as bold text | ||||
* | * |
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; | import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType; | import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType; | 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.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.geom.Rectangle2D; | ||||
import java.awt.image.BufferedImage; | import java.awt.image.BufferedImage; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Iterator; | |||||
import java.util.List; | import java.util.List; | ||||
/** | /** | ||||
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
public abstract class XSLFTextShape extends XSLFSimpleShape { | |||||
public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable<XSLFTextParagraph>{ | |||||
private final List<XSLFTextParagraph> _paragraphs; | private final List<XSLFTextParagraph> _paragraphs; | ||||
/*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) { | /*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) { | ||||
} | } | ||||
} | } | ||||
// textual properties | |||||
public Iterator<XSLFTextParagraph> iterator(){ | |||||
return _paragraphs.iterator(); | |||||
} | |||||
/** | |||||
* | |||||
* @return text contained within this shape or empty string | |||||
*/ | |||||
public String getText() { | public String getText() { | ||||
StringBuilder out = new StringBuilder(); | StringBuilder out = new StringBuilder(); | ||||
for (XSLFTextParagraph p : _paragraphs) { | for (XSLFTextParagraph p : _paragraphs) { | ||||
return out.toString(); | 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() { | public List<XSLFTextParagraph> getTextParagraphs() { | ||||
return _paragraphs; | return _paragraphs; | ||||
} | } | ||||
/** | |||||
* add a new paragraph run to this shape | |||||
* | |||||
* @return created paragraph run | |||||
*/ | |||||
public XSLFTextParagraph addNewTextParagraph() { | public XSLFTextParagraph addNewTextParagraph() { | ||||
CTTextBody txBody = getTextBody(true); | CTTextBody txBody = getTextBody(true); | ||||
CTTextParagraph p = txBody.addNewP(); | CTTextParagraph p = txBody.addNewP(); | ||||
/** | /** | ||||
* Sets the type of vertical alignment for the text. | * 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){ | public void setVerticalAlignment(VerticalAlignment anchor){ | ||||
CTTextBodyProperties bodyPr = getTextBodyPr(); | CTTextBodyProperties bodyPr = getTextBodyPr(); | ||||
/** | /** | ||||
* Returns the type of vertical alignment for the text. | * Returns the type of vertical alignment for the text. | ||||
* | * | ||||
* @return the type of alignment | |||||
* @return the type of vertical alignment | |||||
*/ | */ | ||||
public VerticalAlignment getVerticalAlignment(){ | public VerticalAlignment getVerticalAlignment(){ | ||||
PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){ | PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){ | ||||
} | } | ||||
return TextDirection.HORIZONTAL; | return TextDirection.HORIZONTAL; | ||||
} | } | ||||
/** | /** | ||||
* Returns the distance (in points) between the bottom of the text frame | * 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. | * 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>(){ | PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ | ||||
public boolean fetch(CTTextBodyProperties props){ | public boolean fetch(CTTextBodyProperties props){ | ||||
if(props.isSetBIns()){ | if(props.isSetBIns()){ | ||||
* and the left edge of the inscribed rectangle of the shape that contains | * and the left edge of the inscribed rectangle of the shape that contains | ||||
* the text. | * the text. | ||||
* | * | ||||
* @return the left margin | |||||
* @return the left inset in points | |||||
*/ | */ | ||||
public double getMarginLeft(){ | |||||
public double getLeftInset(){ | |||||
PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ | PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ | ||||
public boolean fetch(CTTextBodyProperties props){ | public boolean fetch(CTTextBodyProperties props){ | ||||
if(props.isSetLIns()){ | if(props.isSetLIns()){ | ||||
* text frame and the right edge of the inscribed rectangle of the shape | * text frame and the right edge of the inscribed rectangle of the shape | ||||
* that contains the text. | * 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>(){ | PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ | ||||
public boolean fetch(CTTextBodyProperties props){ | public boolean fetch(CTTextBodyProperties props){ | ||||
if(props.isSetRIns()){ | if(props.isSetRIns()){ | ||||
* Returns the distance (in points) between the top of the text frame | * 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. | * 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>(){ | PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){ | ||||
public boolean fetch(CTTextBodyProperties props){ | public boolean fetch(CTTextBodyProperties props){ | ||||
if(props.isSetTIns()){ | if(props.isSetTIns()){ | ||||
/** | /** | ||||
* Sets the botom margin. | * Sets the botom margin. | ||||
* @see #getMarginBottom() | |||||
* @see #getBottomInset() | |||||
* | * | ||||
* @param margin the bottom margin | * @param margin the bottom margin | ||||
*/ | */ | ||||
public void setMarginBottom(double margin){ | |||||
public void setBottomInset(double margin){ | |||||
CTTextBodyProperties bodyPr = getTextBodyPr(); | CTTextBodyProperties bodyPr = getTextBodyPr(); | ||||
if (bodyPr != null) { | if (bodyPr != null) { | ||||
if(margin == -1) bodyPr.unsetBIns(); | if(margin == -1) bodyPr.unsetBIns(); | ||||
/** | /** | ||||
* Sets the left margin. | * Sets the left margin. | ||||
* @see #getMarginLeft() | |||||
* @see #getLeftInset() | |||||
* | * | ||||
* @param margin the left margin | * @param margin the left margin | ||||
*/ | */ | ||||
public void setMarginLeft(double margin){ | |||||
public void setLeftInset(double margin){ | |||||
CTTextBodyProperties bodyPr = getTextBodyPr(); | CTTextBodyProperties bodyPr = getTextBodyPr(); | ||||
if (bodyPr != null) { | if (bodyPr != null) { | ||||
if(margin == -1) bodyPr.unsetLIns(); | if(margin == -1) bodyPr.unsetLIns(); | ||||
/** | /** | ||||
* Sets the right margin. | * Sets the right margin. | ||||
* @see #getMarginRight() | |||||
* @see #getRightInset() | |||||
* | * | ||||
* @param margin the right margin | * @param margin the right margin | ||||
*/ | */ | ||||
public void setMarginRight(double margin){ | |||||
public void setRightInset(double margin){ | |||||
CTTextBodyProperties bodyPr = getTextBodyPr(); | CTTextBodyProperties bodyPr = getTextBodyPr(); | ||||
if (bodyPr != null) { | if (bodyPr != null) { | ||||
if(margin == -1) bodyPr.unsetRIns(); | if(margin == -1) bodyPr.unsetRIns(); | ||||
/** | /** | ||||
* Sets the top margin. | * Sets the top margin. | ||||
* @see #getMarginTop() | |||||
* @see #getTopInset() | |||||
* | * | ||||
* @param margin the top margin | * @param margin the top margin | ||||
*/ | */ | ||||
public void setMarginTop(double margin){ | |||||
public void setTopInset(double margin){ | |||||
CTTextBodyProperties bodyPr = getTextBodyPr(); | CTTextBodyProperties bodyPr = getTextBodyPr(); | ||||
if (bodyPr != null) { | if (bodyPr != null) { | ||||
if(margin == -1) bodyPr.unsetTIns(); | if(margin == -1) bodyPr.unsetTIns(); | ||||
/** | /** | ||||
* 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(){ | public boolean getWordWrap(){ | ||||
PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){ | PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){ | ||||
} | } | ||||
/** | /** | ||||
* 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){ | public void setWordWrap(boolean wrap){ | ||||
CTTextBodyProperties bodyPr = getTextBodyPr(); | CTTextBodyProperties bodyPr = getTextBodyPr(); | ||||
} | } | ||||
} | } | ||||
@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); | |||||
} | |||||
if (line != null){ | |||||
graphics.setPaint(line); | |||||
applyStroke(graphics); | |||||
graphics.draw(outline); | |||||
/** | |||||
* 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)); | |||||
} | } | ||||
// text | |||||
if(getText().length() > 0) drawText(graphics); | |||||
} | |||||
} | |||||
/** | /** | ||||
* Compute the cumulative height occupied by the text | * Compute the cumulative height occupied by the text | ||||
return drawParagraphs(img.createGraphics(), 0, 0); | 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); | for(XSLFTextParagraph p : _paragraphs) p.breakText(graphics); | ||||
} | } | ||||
public void drawText(Graphics2D graphics) { | |||||
@Override | |||||
public void drawContent(Graphics2D graphics) { | |||||
breakText(graphics); | breakText(graphics); | ||||
Rectangle2D anchor = getAnchor(); | Rectangle2D anchor = getAnchor(); | ||||
double x = anchor.getX() + getMarginLeft(); | |||||
double x = anchor.getX() + getLeftInset(); | |||||
double y = anchor.getY(); | double y = anchor.getY(); | ||||
// first dry-run to calculate the total height of the text | // first dry-run to calculate the total height of the text | ||||
switch (getVerticalAlignment()){ | switch (getVerticalAlignment()){ | ||||
case TOP: | case TOP: | ||||
y += getMarginTop(); | |||||
y += getTopInset(); | |||||
break; | break; | ||||
case BOTTOM: | case BOTTOM: | ||||
y += anchor.getHeight() - textHeight - getMarginBottom(); | |||||
y += anchor.getHeight() - textHeight - getBottomInset(); | |||||
break; | break; | ||||
default: | default: | ||||
case MIDDLE: | case MIDDLE: | ||||
double delta = anchor.getHeight() - textHeight - | double delta = anchor.getHeight() - textHeight - | ||||
getMarginTop() - getMarginBottom(); | |||||
y += getMarginTop() + delta/2; | |||||
getTopInset() - getBottomInset(); | |||||
y += getTopInset() + delta/2; | |||||
break; | break; | ||||
} | } | ||||
drawParagraphs(graphics, x, y); | drawParagraphs(graphics, x, y); | ||||
} | } | ||||
double y0 = y; | double y0 = y; | ||||
for(int i = 0; i < _paragraphs.size(); i++){ | for(int i = 0; i < _paragraphs.size(); i++){ | ||||
XSLFTextParagraph p = _paragraphs.get(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) { | if(i > 0 && lines.size() > 0) { | ||||
// the amount of vertical white space before the paragraph | // the amount of vertical white space before the paragraph |
import org.apache.xmlbeans.XmlOptions; | import org.apache.xmlbeans.XmlOptions; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles; | import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; | 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.CTColorScheme; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeStyleSheet; | import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeStyleSheet; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument; | import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
/** | |||||
* A shared style sheet in a .pptx slide show | |||||
* | |||||
* @author Yegor Kozlov | |||||
*/ | |||||
@Beta | @Beta | ||||
public class XSLFTheme extends POIXMLDocumentPart { | public class XSLFTheme extends POIXMLDocumentPart { | ||||
private CTOfficeStyleSheet _theme; | private CTOfficeStyleSheet _theme; | ||||
String name = c.getDomNode().getLocalName(); | String name = c.getDomNode().getLocalName(); | ||||
_schemeColors.put(name, c); | _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(){ | public String getName(){ | ||||
return _theme.getName(); | return _theme.getName(); | ||||
} | } | ||||
/** | |||||
* Set name of this theme | |||||
* | |||||
* @param name name of this theme | |||||
*/ | |||||
public void setName(String name){ | public void setName(String name){ | ||||
_theme.setName(name); | _theme.setName(name); | ||||
} | } | ||||
out.close(); | 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(){ | public String getMajorFont(){ | ||||
return _theme.getThemeElements().getFontScheme().getMajorFont().getLatin().getTypeface(); | 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(){ | public String getMinorFont(){ | ||||
return _theme.getThemeElements().getFontScheme().getMinorFont().getLatin().getTypeface(); | return _theme.getThemeElements().getFontScheme().getMinorFont().getLatin().getTypeface(); | ||||
} | } |
import java.awt.Dimension; | import java.awt.Dimension; | ||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
import java.awt.RenderingHints; | import java.awt.RenderingHints; | ||||
import java.awt.geom.AffineTransform; | |||||
import java.awt.geom.Rectangle2D; | |||||
import java.awt.image.BufferedImage; | import java.awt.image.BufferedImage; | ||||
import java.io.File; | |||||
import java.io.FileOutputStream; | 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 | * @author Yegor Kozlov | ||||
*/ | */ | ||||
public class PPTX2PNG { | 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 { | public static void main(String[] args) throws Exception { | ||||
if (args.length == 0) { | if (args.length == 0) { | ||||
System.out.println("Usage: PPTX2PNG [options] <pptx file>"); | |||||
usage(); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if(file == null){ | |||||
usage(); | |||||
return; | |||||
} | |||||
System.out.println("Processing " + file); | System.out.println("Processing " + file); | ||||
XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file)); | XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file)); | ||||
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | ||||
Graphics2D graphics = img.createGraphics(); | Graphics2D graphics = img.createGraphics(); | ||||
// default rendering options | |||||
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); | ||||
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); | ||||
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); | graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); | ||||
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); | 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); | 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); | FileOutputStream out = new FileOutputStream(fname); | ||||
ImageIO.write(img, "png", out); | ImageIO.write(img, "png", out); | ||||
out.close(); | out.close(); |
}; | }; | ||||
CustomGeometry geom = new CustomGeometry(CTCustomGeometry2D.Factory.newInstance()); | CustomGeometry geom = new CustomGeometry(CTCustomGeometry2D.Factory.newInstance()); | ||||
Context ctx = new Context(geom, null); | |||||
Context ctx = new Context(geom, null, null); | |||||
for(Formula fmla : ops) { | for(Formula fmla : ops) { | ||||
ctx.evaluate(fmla); | ctx.evaluate(fmla); | ||||
} | } |
for(String name : shapes.keySet()) { | for(String name : shapes.keySet()) { | ||||
CustomGeometry geom = shapes.get(name); | 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) { | public Guide getAdjustValue(String name) { | ||||
return null; | return null; | ||||
} | } |
public class TestPPTX2PNG extends TestCase { | public class TestPPTX2PNG extends TestCase { | ||||
public void testRender(){ | public void testRender(){ | ||||
String[] testFiles = {"layouts.pptx", "sample.pptx", "shapes.pptx", | String[] testFiles = {"layouts.pptx", "sample.pptx", "shapes.pptx", | ||||
"45541_Header.pptx", "backgrounds.pptx"}; | |||||
"themes.pptx", "backgrounds.pptx"}; | |||||
for(String sampleFile : testFiles){ | for(String sampleFile : testFiles){ | ||||
XMLSlideShow pptx = XSLFTestDataSamples.openSampleDocument(sampleFile); | XMLSlideShow pptx = XSLFTestDataSamples.openSampleDocument(sampleFile); | ||||
Dimension pg = pptx.getPageSize(); | Dimension pg = pptx.getPageSize(); |
shape.addNewTextParagraph().addNewTextRun().setText("POI"); | shape.addNewTextParagraph().addNewTextRun().setText("POI"); | ||||
// default margins from slide master | // 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()); | |||||
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.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()); | |||||
assertEquals(3.6, shape.getBottomInset()); | |||||
assertEquals(3.6, shape.getTopInset()); | |||||
assertEquals(7.2, shape.getLeftInset()); | |||||
assertEquals(7.2, shape.getRightInset()); | |||||
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.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 | // 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 | // shape | ||||
assertTrue(shape.getWordWrap()); | assertTrue(shape.getWordWrap()); |
CTSRgbColor c = xml.addNewSrgbClr(); | CTSRgbColor c = xml.addNewSrgbClr(); | ||||
c.setVal(new byte[]{(byte)0xFF, 0, 0}); | 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()); | assertEquals(-1, color.getAlpha()); | ||||
c.addNewAlpha().setVal(50000); | c.addNewAlpha().setVal(50000); | ||||
c.setSat2(100000); | c.setSat2(100000); | ||||
c.setLum2(50000); | c.setLum2(50000); | ||||
XSLFColor color = new XSLFColor(xml, null); | |||||
XSLFColor color = new XSLFColor(xml, null, null); | |||||
assertEquals(new Color(128, 00, 00), color.getColor()); | assertEquals(new Color(128, 00, 00), color.getColor()); | ||||
} | } | ||||
CTColor xml = CTColor.Factory.newInstance(); | CTColor xml = CTColor.Factory.newInstance(); | ||||
xml.addNewSrgbClr().setVal(new byte[]{ (byte)0xFF, (byte)0xFF, 0}); | 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()); | assertEquals(new Color(0xFF, 0xFF, 0), color.getColor()); | ||||
} | } | ||||
CTColor xml = CTColor.Factory.newInstance(); | CTColor xml = CTColor.Factory.newInstance(); | ||||
xml.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_2); | 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"/> | // accent2 is theme1.xml is <a:srgbClr val="C0504D"/> | ||||
assertEquals(Color.decode("0xC0504D"), color.getColor()); | assertEquals(Color.decode("0xC0504D"), color.getColor()); | ||||
xml = CTColor.Factory.newInstance(); | xml = CTColor.Factory.newInstance(); | ||||
xml.addNewSchemeClr().setVal(STSchemeColorVal.LT_1); | xml.addNewSchemeClr().setVal(STSchemeColorVal.LT_1); | ||||
color = new XSLFColor(xml, theme); | |||||
color = new XSLFColor(xml, theme, null); | |||||
// <a:sysClr val="window" lastClr="FFFFFF"/> | // <a:sysClr val="window" lastClr="FFFFFF"/> | ||||
assertEquals(Color.decode("0xFFFFFF"), color.getColor()); | assertEquals(Color.decode("0xFFFFFF"), color.getColor()); | ||||
xml = CTColor.Factory.newInstance(); | xml = CTColor.Factory.newInstance(); | ||||
xml.addNewSchemeClr().setVal(STSchemeColorVal.DK_1); | xml.addNewSchemeClr().setVal(STSchemeColorVal.DK_1); | ||||
color = new XSLFColor(xml, theme); | |||||
color = new XSLFColor(xml, theme, null); | |||||
// <a:sysClr val="windowText" lastClr="000000"/> | // <a:sysClr val="windowText" lastClr="000000"/> | ||||
assertEquals(Color.decode("0x000000"), color.getColor()); | assertEquals(Color.decode("0x000000"), color.getColor()); | ||||
} | } | ||||
public void testPresetColor() { | public void testPresetColor() { | ||||
CTColor xml = CTColor.Factory.newInstance(); | CTColor xml = CTColor.Factory.newInstance(); | ||||
xml.addNewPrstClr().setVal(STPresetColorVal.AQUAMARINE); | 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()); | assertEquals(new Color(127, 255, 212), color.getColor()); | ||||
STPresetColorVal.Enum val = STPresetColorVal.Enum.forString(colorName); | STPresetColorVal.Enum val = STPresetColorVal.Enum.forString(colorName); | ||||
assertNotNull(colorName, val); | assertNotNull(colorName, val); | ||||
xml.addNewPrstClr().setVal(val); | xml.addNewPrstClr().setVal(val); | ||||
color = new XSLFColor(xml, null); | |||||
color = new XSLFColor(xml, null, null); | |||||
assertEquals(XSLFColor.presetColors.get(colorName), color.getColor()); | assertEquals(XSLFColor.presetColors.get(colorName), color.getColor()); | ||||
} | } | ||||
} | } |
import junit.framework.TestCase; | import junit.framework.TestCase; | ||||
import org.apache.poi.xslf.XSLFTestDataSamples; | import org.apache.poi.xslf.XSLFTestDataSamples; | ||||
import org.apache.poi.POIXMLDocumentPart; | |||||
import java.util.List; | |||||
/** | /** | ||||
* @author Yegor Kozlov | * @author Yegor Kozlov | ||||
assertEquals(0, ppt.getSlides().length); | assertEquals(0, ppt.getSlides().length); | ||||
XSLFSlide slide = ppt.createSlide(); | 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()); | |||||
} | } | ||||
} | } |
List<POIXMLDocumentPart> rels = slide1.getRelations(); | List<POIXMLDocumentPart> rels = slide1.getRelations(); | ||||
assertEquals(1, rels.size()); | 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(); | XSLFSlide slide2 = ppt.createSlide(); | ||||
assertEquals(2, ppt.getSlides().length); | assertEquals(2, ppt.getSlides().length); | ||||
assertEquals(1, masters.length); | assertEquals(1, masters.length); | ||||
XSLFSlide slide = ppt.createSlide(); | XSLFSlide slide = ppt.createSlide(); | ||||
assertSame(masters[0], slide.getMasterSheet()); | |||||
assertSame(masters[0], slide.getSlideMaster()); | |||||
} | } | ||||
public void testSlideLayout(){ | public void testSlideLayout(){ |
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | ||||
!bodyPr1.isSetAnchor() | !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()); | assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); | ||||
// now check text properties | // now check text properties | ||||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | ||||
!bodyPr2.isSetAnchor() | !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(VerticalAlignment.TOP, shape2.getVerticalAlignment()); | ||||
assertEquals("subtitle", shape2.getText()); | assertEquals("subtitle", shape2.getText()); | ||||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | ||||
!bodyPr1.isSetAnchor() | !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()); | assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); | ||||
// now check text properties | // now check text properties | ||||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | ||||
!bodyPr2.isSetAnchor() | !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(VerticalAlignment.TOP, shape2.getVerticalAlignment()); | ||||
XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); | XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); | ||||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | ||||
!bodyPr1.isSetAnchor() | !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()); | assertEquals(VerticalAlignment.TOP, shape1.getVerticalAlignment()); | ||||
// now check text properties | // now check text properties | ||||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | ||||
!bodyPr2.isSetAnchor() | !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(VerticalAlignment.BOTTOM, shape2.getVerticalAlignment()); | ||||
assertEquals("Section Header", shape2.getText()); | assertEquals("Section Header", shape2.getText()); | ||||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | ||||
!bodyPr1.isSetAnchor() | !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()); | assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); | ||||
// now check text properties | // now check text properties | ||||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | ||||
!bodyPr2.isSetAnchor() | !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(VerticalAlignment.TOP, shape2.getVerticalAlignment()); | ||||
XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); | XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); | ||||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | ||||
!bodyPr1.isSetAnchor() | !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()); | assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); | ||||
// now check text properties | // now check text properties | ||||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | ||||
!bodyPr2.isSetAnchor() | !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(VerticalAlignment.TOP, shape2.getVerticalAlignment()); | ||||
XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); | XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); | ||||
!bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && | ||||
!bodyPr1.isSetAnchor() | !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()); | assertEquals(VerticalAlignment.BOTTOM, shape1.getVerticalAlignment()); | ||||
// now check text properties | // now check text properties | ||||
!bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && | ||||
!bodyPr2.isSetAnchor() | !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(VerticalAlignment.TOP, shape2.getVerticalAlignment()); | ||||
XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); | XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); |
import junit.framework.TestCase; | import junit.framework.TestCase; | ||||
import org.apache.poi.xslf.XSLFTestDataSamples; | 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 | * @author Yegor Kozlov | ||||
*/ | */ | ||||
public class TestXSLFTheme extends TestCase { | public class TestXSLFTheme extends TestCase { | ||||
public void testRead(){ | 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()); | 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 | |||||
} | } | ||||
} | } |