From: Yegor Kozlov Date: Mon, 7 Nov 2011 09:12:16 +0000 (+0000) Subject: more progress with xlsf: support for gradient and texture fills, backgrounds, improve... X-Git-Tag: REL_3_8_BETA5~34 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=de14b40a970a2626701f59f1ccfa3b6970614519;p=poi.git more progress with xlsf: support for gradient and texture fills, backgrounds, improved drawing of preset shapes and many more updates ... git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1198658 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/build.xml b/build.xml index 62c208bf1d..84c2bccbfd 100644 --- a/build.xml +++ b/build.xml @@ -108,6 +108,7 @@ under the License. + @@ -553,6 +554,9 @@ under the License. + + + diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java b/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java new file mode 100644 index 0000000000..a83a17e4b8 --- /dev/null +++ b/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java @@ -0,0 +1,68 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.xslf.usermodel.tutorial; + +import org.apache.poi.xslf.usermodel.XMLSlideShow; +import org.apache.poi.xslf.usermodel.XSLFShape; +import org.apache.poi.xslf.usermodel.XSLFSlide; +import org.apache.poi.xslf.usermodel.XSLFTextParagraph; +import org.apache.poi.xslf.usermodel.XSLFTextRun; +import org.apache.poi.xslf.usermodel.XSLFTextShape; + +import java.io.FileInputStream; + +/** + * Reading a .pptx presentation and printing basic shape properties + * + * @author Yegor Kozlov + */ +public class Step1 { + + public static void main(String[] args) throws Exception { + if(args.length == 0) { + System.out.println("Input file is required"); + return; + } + + XMLSlideShow ppt = new XMLSlideShow(new FileInputStream(args[0])); + + for(XSLFSlide slide : ppt.getSlides()){ + System.out.println("Title: " + slide.getTitle()); + + for(XSLFShape shape : slide.getShapes()){ + if(shape instanceof XSLFTextShape) { + XSLFTextShape tsh = (XSLFTextShape)shape; + for(XSLFTextParagraph p : tsh){ + System.out.println("Paragraph level: " + p.getLevel()); + for(XSLFTextRun r : p){ + System.out.println(r.getText()); + System.out.println(" bold: " + r.isBold()); + System.out.println(" italic: " + r.isItalic()); + System.out.println(" underline: " + r.isUnderline()); + System.out.println(" font.family: " + r.getFontFamily()); + System.out.println(" font.size: " + r.getFontSize()); + System.out.println(" font.color: " + r.getFontColor()); + } + } + } + } + } + } +} diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step2.java b/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step2.java new file mode 100644 index 0000000000..16b155d3f2 --- /dev/null +++ b/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step2.java @@ -0,0 +1,80 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.xslf.usermodel.tutorial; + +import org.apache.poi.xslf.usermodel.SlideLayout; +import org.apache.poi.xslf.usermodel.XMLSlideShow; +import org.apache.poi.xslf.usermodel.XSLFSlide; +import org.apache.poi.xslf.usermodel.XSLFSlideLayout; +import org.apache.poi.xslf.usermodel.XSLFSlideMaster; +import org.apache.poi.xslf.usermodel.XSLFTextShape; + +import java.io.FileOutputStream; + +/** + * Create slides from pre-defined slide layouts + * + * @author Yegor Kozlov + */ +public class Step2 { + public static void main(String[] args) throws Exception{ + XMLSlideShow ppt = new XMLSlideShow(); + + + // first see what slide layouts are available by default + System.out.println("Available slide layouts:"); + for(XSLFSlideMaster master : ppt.getSlideMasters()){ + for(XSLFSlideLayout layout : master.getSlideLayouts()){ + System.out.println(layout.getType()); + } + } + + // blank slide + XSLFSlide blankSlide = ppt.createSlide(); + + XSLFSlideMaster defaultMaster = ppt.getSlideMasters()[0]; + + // title slide + XSLFSlideLayout titleLayout = defaultMaster.getLayout(SlideLayout.TITLE); + XSLFSlide slide1 = ppt.createSlide(titleLayout); + XSLFTextShape title1 = slide1.getPlaceholder(0); + title1.setText("First Title"); + + // title and content + XSLFSlideLayout titleBodyLayout = defaultMaster.getLayout(SlideLayout.TITLE_AND_CONTENT); + XSLFSlide slide2 = ppt.createSlide(titleBodyLayout); + + XSLFTextShape title2 = slide2.getPlaceholder(0); + title2.setText("Second Title"); + + XSLFTextShape body2 = slide2.getPlaceholder(1); + body2.clearText(); // unset any existing text + body2.addNewTextParagraph().addNewTextRun().setText("First paragraph"); + body2.addNewTextParagraph().addNewTextRun().setText("Second paragraph"); + body2.addNewTextParagraph().addNewTextRun().setText("Third paragraph"); + + + + FileOutputStream out = new FileOutputStream("step2.pptx"); + ppt.write(out); + out.close(); + + } +} diff --git a/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java b/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java index 812c7ad0e6..0f9a26fe21 100644 --- a/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java +++ b/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java @@ -128,7 +128,7 @@ public class XSLFPowerPointExtractor extends POIXMLTextExtractor { XSLFNotes notes = slide.getNotes(); XSLFComments comments = slide.getComments(); XSLFSlideLayout layout = slide.getSlideLayout(); - XSLFSlideMaster master = slide.getMasterSheet(); + XSLFSlideMaster master = layout.getSlideMaster(); // TODO Do the slide's name // (Stored in docProps/app.xml) diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/ArcToCommand.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/ArcToCommand.java index 9b2e1bcf31..b1ea0defc8 100644 --- a/src/ooxml/java/org/apache/poi/xslf/model/geom/ArcToCommand.java +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/ArcToCommand.java @@ -57,15 +57,11 @@ public class ArcToCommand implements PathCommand { double x0 = pt.getX() - rx - rx * Math.cos(Math.toRadians(start)); double y0 = pt.getY() - ry - ry * Math.sin(Math.toRadians(start)); - if(start == 180 && extent == 180) { - x0 -= rx*2; //YK: TODO revisit the code and get rid of this hack - } - Arc2D arc = new Arc2D.Double( x0, y0, 2 * rx, 2 * ry, - -start, -extent, // negate angles because DrawingML rotates counter-clockwise + -start, -extent, Arc2D.OPEN); path.append(arc, true); } diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/Context.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/Context.java index 230524cfde..ea86c51002 100644 --- a/src/ooxml/java/org/apache/poi/xslf/model/geom/Context.java +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/Context.java @@ -29,17 +29,19 @@ import java.util.Map; * @author Yegor Kozlov */ public class Context { - Map _ctx = new HashMap(); - IAdjustableShape _props; - - public Context(CustomGeometry geom, IAdjustableShape props){ + final Map _ctx = new HashMap(); + final IAdjustableShape _props; + final Rectangle2D _anchor; + + public Context(CustomGeometry geom, Rectangle2D anchor, IAdjustableShape props){ _props = props; + _anchor = anchor; for(Guide gd : geom.adjusts) evaluate(gd); for(Guide gd : geom.guides) evaluate(gd); } public Rectangle2D getShapeAnchor(){ - return _props.getAnchor(); + return _anchor; } public Guide getAdjustValue(String name){ diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/CustomGeometry.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/CustomGeometry.java index 7507f55b21..6745ccd513 100644 --- a/src/ooxml/java/org/apache/poi/xslf/model/geom/CustomGeometry.java +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/CustomGeometry.java @@ -24,6 +24,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.*; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.awt.geom.Rectangle2D; /** * Definition of a custom geometric shape @@ -34,8 +35,9 @@ public class CustomGeometry implements Iterable{ List adjusts = new ArrayList(); List guides = new ArrayList(); List paths = new ArrayList(); + Path textBounds; - public CustomGeometry(CTCustomGeometry2D geom){ + public CustomGeometry(CTCustomGeometry2D geom) { CTGeomGuideList avLst = geom.getAvLst(); if(avLst != null) for(CTGeomGuide gd : avLst.getGdList()){ adjusts.add(new AdjustValue(gd)); @@ -50,6 +52,21 @@ public class CustomGeometry implements Iterable{ if(pathLst != null) for(CTPath2D spPath : pathLst.getPathList()){ paths.add(new Path(spPath)); } + + if(geom.isSetRect()) { + CTGeomRect rect = geom.getRect(); + textBounds = new Path(); + textBounds.addCommand( + new MoveToCommand(rect.getL().toString(), rect.getT().toString())); + textBounds.addCommand( + new LineToCommand(rect.getR().toString(), rect.getT().toString())); + textBounds.addCommand( + new LineToCommand(rect.getR().toString(), rect.getB().toString())); + textBounds.addCommand( + new LineToCommand(rect.getL().toString(), rect.getB().toString())); + textBounds.addCommand( + new ClosePathCommand()); + } } @@ -58,4 +75,7 @@ public class CustomGeometry implements Iterable{ return paths.iterator(); } + public Path getTextBounds(){ + return textBounds; + } } diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/IAdjustableShape.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/IAdjustableShape.java index 174af3d34c..44f5a562f7 100644 --- a/src/ooxml/java/org/apache/poi/xslf/model/geom/IAdjustableShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/IAdjustableShape.java @@ -19,7 +19,6 @@ package org.apache.poi.xslf.model.geom; -import java.awt.geom.Rectangle2D; /** * A bridge to the consumer application. @@ -29,12 +28,6 @@ import java.awt.geom.Rectangle2D; * @author Yegor Kozlov */ public interface IAdjustableShape { - /** - * - * @return bounds of the shape - */ - Rectangle2D getAnchor(); - /** * * @param name name of a adjust value, e.g. adj1 diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/LineToCommand.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/LineToCommand.java index 3df2e499e1..5142dd234a 100644 --- a/src/ooxml/java/org/apache/poi/xslf/model/geom/LineToCommand.java +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/LineToCommand.java @@ -36,6 +36,11 @@ public class LineToCommand implements PathCommand { arg2 = pt.getY().toString(); } + LineToCommand(String s1, String s2){ + arg1 = s1; + arg2 = s2; + } + public void execute(GeneralPath path, Context ctx){ double x = ctx.getValue(arg1); double y = ctx.getValue(arg2); diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/MoveToCommand.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/MoveToCommand.java index a5a4b5ce69..9d9575ace1 100644 --- a/src/ooxml/java/org/apache/poi/xslf/model/geom/MoveToCommand.java +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/MoveToCommand.java @@ -36,6 +36,11 @@ public class MoveToCommand implements PathCommand { arg2 = pt.getY().toString(); } + MoveToCommand(String s1, String s2){ + arg1 = s1; + arg2 = s2; + } + public void execute(GeneralPath path, Context ctx){ double x = ctx.getValue(arg1); double y = ctx.getValue(arg2); diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/Outline.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/Outline.java new file mode 100644 index 0000000000..dbf9f1f9c9 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/Outline.java @@ -0,0 +1,45 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.xslf.model.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; + } +} diff --git a/src/ooxml/java/org/apache/poi/xslf/model/geom/Path.java b/src/ooxml/java/org/apache/poi/xslf/model/geom/Path.java index 9d5e9f71d3..94ab37662c 100644 --- a/src/ooxml/java/org/apache/poi/xslf/model/geom/Path.java +++ b/src/ooxml/java/org/apache/poi/xslf/model/geom/Path.java @@ -39,11 +39,26 @@ import java.util.List; public class Path { private final List commands; boolean _fill, _stroke; + long _w, _h; + + public Path(){ + this(true, true); + } + + public Path(boolean fill, boolean stroke){ + commands = new ArrayList(); + _w = -1; + _h = -1; + _fill = fill; + _stroke = stroke; + } public Path(CTPath2D spPath){ _fill = spPath.getFill() != STPathFillMode.NONE; _stroke = spPath.getStroke(); - + _w = spPath.isSetW() ? spPath.getW() : -1; + _h = spPath.isSetH() ? spPath.getH() : -1; + commands = new ArrayList(); for(XmlObject ch : spPath.selectPath("*")){ if(ch instanceof CTPath2DMoveTo){ @@ -74,6 +89,13 @@ public class Path { } } + public void addCommand(PathCommand cmd){ + commands.add(cmd); + } + + /** + * Convert the internal represenation to java.awt.GeneralPath + */ public GeneralPath getPath(Context ctx) { GeneralPath path = new GeneralPath(); for(PathCommand cmd : commands) @@ -88,4 +110,12 @@ public class Path { public boolean isFilled(){ return _fill; } + + public long getW(){ + return _w; + } + + public long getH(){ + return _h; + } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java index a96e88778d..087b28c054 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java @@ -30,7 +30,7 @@ public enum Placeholder { SLIDE_NUMBER, FOOTER, HEADER, - OBJECT, + CONTENT, CHART, TABLE, CLIP_ART, @@ -38,5 +38,4 @@ public enum Placeholder { MEDIA, SLIDE_IMAGE, PICTURE - } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/RenderableShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/RenderableShape.java index 393ba333e6..bbd0de9ea6 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/RenderableShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/RenderableShape.java @@ -1,11 +1,563 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + package org.apache.poi.xslf.usermodel; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.util.Internal; +import org.apache.poi.util.Units; +import org.apache.poi.xslf.model.PropertyFetcher; +import org.apache.poi.xslf.model.geom.Context; +import org.apache.poi.xslf.model.geom.CustomGeometry; +import org.apache.poi.xslf.model.geom.Guide; +import org.apache.poi.xslf.model.geom.IAdjustableShape; +import org.apache.poi.xslf.model.geom.Outline; +import org.apache.poi.xslf.model.geom.Path; +import org.apache.xmlbeans.XmlObject; +import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; +import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientStop; +import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTNoFillProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPathShadeProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; +import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; +import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference; +import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.GradientPaint; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; + /** - * Created by IntelliJ IDEA. - * User: yegor - * Date: Oct 27, 2011 - * Time: 4:50:08 PM - * To change this template use File | Settings | File Templates. + * Encapsulates logic to translate DrawingML objects to Java2D */ +@Internal class RenderableShape { + public final static Color NO_PAINT = new Color(0xFF, 0xFF, 0xFF, 0); + + private XSLFSimpleShape _shape; + + public RenderableShape(XSLFSimpleShape shape){ + _shape = shape; + } + + /** + * Convert shape fill into java.awt.Paint. The result is either Color or + * TexturePaint or GradientPaint or null + * + * @param graphics the target graphics + * @param obj the xml to read. Must contain elements from the EG_ColorChoice group: + * + * 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 + * + * + * @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() { + 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() { + 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 fetcher = new PropertyFetcher() { + 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 fetcher = new PropertyFetcher() { + 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 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 computeOutlines() { + CustomGeometry geom = _shape.getGeometry(); + + Collection lst = new ArrayList(); + + 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; + } + } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/SlideLayout.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/SlideLayout.java new file mode 100644 index 0000000000..729057b13b --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/SlideLayout.java @@ -0,0 +1,99 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.xslf.usermodel; + +/** + * Date: 11/5/11 + * + * @author Yegor Kozlov + */ +public enum SlideLayout { + /** + * Title layout with centered title and subtitle placeholders + */ + TITLE, + /** + * Title and text + */ + TEXT, + + TWO_COL_TX, + TBL, + TEXT_AND_CHART, + + /** + * Title, chart on left and text on right + */ + CHART_AND_TEXT, + + DGM, + + /** + * Title and chart + */ + CHART, + + TX_AND_CLIP_ART, + /** + * Title, clipart on left, text on right + */ + CLIP_ART_AND_TEXT, + + /** + * Title only + */ + TITLE_ONLY, + + /** + * Blank + */ + BLANK, + + TX_AND_OBJ, + OBJ_AND_TX, + OBJ_ONLY, + /** + * title and content + */ + TITLE_AND_CONTENT, + TX_AND_MEDIA, + MEDIA_AND_TX, + OBJ_OVER_TX, + TX_OVER_OBJ, + TX_AND_TWO_OBJ, + TWO_OBJ_AND_TX, + TWO_OBJ_OVER_TX, + FOUR_OBJ, + VERT_TX, + CLIP_ART_AND_VERT_TX, + VERT_TITLE_AND_TX, + VERT_TITLE_AND_TX_OVER_CHART, + TWO_OBJ, + OBJ_AND_TWO_OBJ, + TWO_OBJ_AND_OBJ, + CUST, + /** + * Section Header + */ + SECTION_HEADER, + TWO_TX_TWO_OBJ, + OBJ_TX, + PIC_TX, +} diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/TextAlign.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/TextAlign.java index c712dbacef..2570e6cfc9 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/TextAlign.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/TextAlign.java @@ -43,5 +43,8 @@ public enum TextAlign { * is smart in the sense that it will not justify sentences * which are short */ - JUSTIFY + JUSTIFY, + JUSTIFY_LOW, + DIST, + THAI_DIST } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/TextCap.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/TextCap.java new file mode 100644 index 0000000000..2e998efcf0 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/TextCap.java @@ -0,0 +1,33 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.xslf.usermodel; + +/** + * Created by IntelliJ IDEA. + * User: yegor + * Date: 11/3/11 + * Time: 5:07 PM + * To change this template use File | Settings | File Templates. + */ +public enum TextCap { + NONE, + SMALL, + ALL +} diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java index 8f25beeede..efec667a93 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java @@ -40,7 +40,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry; import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideSize; import org.openxmlformats.schemas.presentationml.x2006.main.PresentationDocument; -import java.awt.*; +import java.awt.Dimension; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -190,7 +190,13 @@ public class XMLSlideShow extends POIXMLDocument { return Collections.unmodifiableList(_pictures); } - public XSLFSlide createSlide() { + /** + * Create a slide and initialize it from the specified layout. + * + * @param layout + * @return created slide + */ + public XSLFSlide createSlide(XSLFSlideLayout layout) { int slideNumber = 256, cnt = 1; CTSlideIdList slideList; if (!_presentation.isSetSldIdLst()) slideList = _presentation.addNewSldIdLst(); @@ -209,12 +215,7 @@ public class XMLSlideShow extends POIXMLDocument { slideId.setId(slideNumber); slideId.setId2(slide.getPackageRelationship().getId()); - String masterId = _presentation.getSldMasterIdLst().getSldMasterIdArray(0).getId2(); - XSLFSlideMaster master = _masters.get(masterId); - - XSLFSlideLayout layout = master.getLayout("blank"); - if(layout == null) throw new IllegalArgumentException("Blank layout was not found"); - + layout.copyLayout(slide); slide.addRelation(layout.getPackageRelationship().getId(), layout); PackagePartName ppName = layout.getPackagePart().getPartName(); @@ -224,7 +225,20 @@ public class XMLSlideShow extends POIXMLDocument { _slides.add(slide); return slide; } - + + /** + * Create a blank slide. + */ + public XSLFSlide createSlide() { + String masterId = _presentation.getSldMasterIdLst().getSldMasterIdArray(0).getId2(); + XSLFSlideMaster master = _masters.get(masterId); + + XSLFSlideLayout layout = master.getLayout(SlideLayout.BLANK); + if(layout == null) throw new IllegalArgumentException("Blank layout was not found"); + + return createSlide(layout); + } + /** * Return the Notes Master, if there is one. * (May not be present if no notes exist) diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java index 2b8a1e08b8..5f4e838a0c 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java @@ -28,16 +28,14 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual; -import java.util.regex.Pattern; /** - * Represents a preset geometric shape. + * Represents a shape with a preset geometry. * * @author Yegor Kozlov */ @Beta public class XSLFAutoShape extends XSLFTextShape { - private static final Pattern adjPtrn = Pattern.compile("val\\s+(\\d+)"); /*package*/ XSLFAutoShape(CTShape shape, XSLFSheet sheet) { super(shape, sheet); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java index cd82eabead..7d8cb061ef 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java @@ -17,16 +17,16 @@ package org.apache.poi.xslf.usermodel; -import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; -import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties; -import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference; -import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix; -import org.openxmlformats.schemas.drawingml.x2006.main.CTBackgroundFillStyleList; import org.apache.xmlbeans.XmlObject; -import org.apache.xmlbeans.XmlCursor; +import org.openxmlformats.schemas.drawingml.x2006.main.CTBackgroundFillStyleList; +import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; +import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference; +import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; -import javax.xml.namespace.QName; -import java.awt.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Paint; import java.awt.geom.Rectangle2D; /** @@ -49,31 +49,46 @@ public class XSLFBackground extends XSLFSimpleShape { public void draw(Graphics2D graphics) { Rectangle2D anchor = getAnchor(); - XmlObject spPr = null; + Paint fill = getPaint(graphics); + if(fill != null) { + graphics.setPaint(fill); + graphics.fill(anchor); + } + } + + /** + * @return the Paint object to fill + */ + Paint getPaint(Graphics2D graphics){ + RenderableShape rShape = new RenderableShape(this); + + Paint fill = null; CTBackground bg = (CTBackground)getXmlObject(); if(bg.isSetBgPr()){ - spPr = bg.getBgPr(); + XmlObject spPr = bg.getBgPr(); + fill = rShape.getPaint(graphics, spPr, null); } else if (bg.isSetBgRef()){ CTStyleMatrixReference bgRef= bg.getBgRef(); - int idx = (int)bgRef.getIdx() - 1000; + CTSchemeColor phClr = bgRef.getSchemeClr(); + + int idx = (int)bgRef.getIdx() - 1001; XSLFTheme theme = getSheet().getTheme(); CTBackgroundFillStyleList bgStyles = theme.getXmlObject().getThemeElements().getFmtScheme().getBgFillStyleLst(); - // TODO pass this to getPaint 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; } - - } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java index 8ca8dbde9f..c0f4762c7e 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java @@ -30,7 +30,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; import org.openxmlformats.schemas.drawingml.x2006.main.CTSystemColor; import org.w3c.dom.Node; -import java.awt.*; +import java.awt.Color; import java.util.HashMap; import java.util.Map; @@ -40,12 +40,15 @@ import java.util.Map; * @author Yegor Kozlov */ @Beta +@Internal public class XSLFColor { private XmlObject _xmlObject; private Color _color; + private CTSchemeColor _phClr; - XSLFColor(XmlObject obj, XSLFTheme theme) { + public XSLFColor(XmlObject obj, XSLFTheme theme, CTSchemeColor phClr) { _xmlObject = obj; + _phClr = phClr; _color = toColor(obj, theme); } @@ -94,7 +97,7 @@ public class XSLFColor { return result; } - static Color toColor(XmlObject obj, XSLFTheme theme) { + Color toColor(XmlObject obj, XSLFTheme theme) { Color color = null; for (XmlObject ch : obj.selectPath("*")) { if (ch instanceof CTHslColor) { @@ -102,7 +105,8 @@ public class XSLFColor { int h = hsl.getHue2(); int s = hsl.getSat2(); int l = hsl.getLum2(); - // is it correct ? + // This conversion is not correct and differs from PowerPoint. + // TODO: Revisit and improve. color = Color.getHSBColor(h / 60000f, s / 100000f, l / 100000f); } else if (ch instanceof CTPresetColor) { CTPresetColor prst = (CTPresetColor)ch; @@ -111,12 +115,13 @@ public class XSLFColor { } else if (ch instanceof CTSchemeColor) { CTSchemeColor schemeColor = (CTSchemeColor)ch; String colorRef = schemeColor.getVal().toString(); + if(_phClr != null) { + // context color overrides the theme + colorRef = _phClr.getVal().toString(); + } // find referenced CTColor in the theme and convert it to java.awt.Color via a recursive call CTColor ctColor = theme.getCTColor(colorRef); if(ctColor != null) color = toColor(ctColor, null); - else { - color = Color.black; - } } else if (ch instanceof CTScRgbColor) { // same as CTSRgbColor but with values expressed in percents CTScRgbColor scrgb = (CTScRgbColor)ch; @@ -145,21 +150,59 @@ public class XSLFColor { return color; } + /** + * Read a perecentage value from the supplied xml bean. + * Example: + * + * + * the returned value is 45 + * + * @return the percentage value in the range [0 .. 100] + */ private int getPercentageValue(String elem){ - XmlObject[] obj = _xmlObject.selectPath( - "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' $this//a:" + elem); + String query = "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' $this//a:" + elem; + + XmlObject[] obj; + + // first ask the context color and if not found, ask the actual color bean + if(_phClr != null){ + obj = _phClr.selectPath(query); + if(obj.length == 1){ + Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); + if(attr != null) { + return Integer.parseInt(attr.getNodeValue()) / 1000; + } + } + } + + obj = _xmlObject.selectPath(query); if(obj.length == 1){ Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); if(attr != null) { return Integer.parseInt(attr.getNodeValue()) / 1000; } } + + return -1; } private int getAngleValue(String elem){ - XmlObject[] obj = _xmlObject.selectPath( - "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' $this//a:" + elem); + String color = "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' $this//a:" + elem; + XmlObject[] obj; + + // first ask the context color and if not found, ask the actual color bean + if(_phClr != null){ + obj = _xmlObject.selectPath( color ); + if(obj.length == 1){ + Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); + if(attr != null) { + return Integer.parseInt(attr.getNodeValue()) / 60000; + } + } + } + + obj = _xmlObject.selectPath( color ); if(obj.length == 1){ Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); if(attr != null) { @@ -341,7 +384,7 @@ public class XSLFColor { * A 10% shade is 10% of the input color combined with 90% black. * * @return the value of the shade specified as a - * percentage with 0% indicating minimal blue and 100% indicating maximum + * percentage with 0% indicating minimal shade and 100% indicating maximum * or -1 if the value is not set */ int getShade(){ @@ -353,7 +396,7 @@ public class XSLFColor { * A 10% tint is 10% of the input color combined with 90% white. * * @return the value of the tint specified as a - * percentage with 0% indicating minimal blue and 100% indicating maximum + * percentage with 0% indicating minimal tint and 100% indicating maximum * or -1 if the value is not set */ int getTint(){ @@ -389,6 +432,10 @@ public class XSLFColor { return color; } + /** + * This algorithm returns result different from PowerPoint. + * TODO: revisit and improve + */ private static Color shade(Color c, int shade) { return new Color( (int)(c.getRed() * shade * 0.01), @@ -397,6 +444,10 @@ public class XSLFColor { c.getAlpha()); } + /** + * This algorithm returns result different from PowerPoint. + * TODO: revisit and improve + */ private static Color tint(Color c, int tint) { int r = c.getRed(); int g = c.getGreen(); @@ -414,7 +465,7 @@ public class XSLFColor { /** * Preset colors defined in DrawingML */ - static Map presetColors; + static final Map presetColors; static { presetColors = new HashMap(); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java index 2e28774a4c..647b414c53 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFConnectorShape.java @@ -20,6 +20,8 @@ package org.apache.poi.xslf.usermodel; import org.apache.poi.util.Beta; +import org.apache.poi.xslf.model.geom.Outline; +import org.apache.poi.xslf.model.geom.Path; import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; @@ -32,11 +34,14 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; import org.openxmlformats.schemas.presentationml.x2006.main.CTConnectorNonVisual; -import java.awt.*; +import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Specifies a connection shape. @@ -197,36 +202,7 @@ public class XSLFConnectorShape extends XSLFSimpleShape { return len == null ? LineEndLength.MEDIUM : LineEndLength.values()[len.intValue() - 1]; } - @Override - public void draw(Graphics2D graphics) { - java.awt.Shape outline = getOutline(); - - // shadow - XSLFShadow shadow = getShadow(); - - //border - Paint line = getLinePaint(graphics); - if (line != null) { - if (shadow != null) shadow.draw(graphics); - - graphics.setPaint(line); - applyStroke(graphics); - graphics.draw(outline); - - Shape tailDecoration = getTailDecoration(); - if (tailDecoration != null) { - graphics.draw(tailDecoration); - } - - Shape headDecoration = getHeadDecoration(); - if (headDecoration != null) { - graphics.draw(headDecoration); - - } - } - } - - Shape getTailDecoration() { + Outline getTailDecoration() { LineEndLength tailLength = getLineTailLength(); LineEndWidth tailWidth = getLineTailWidth(); @@ -239,17 +215,20 @@ public class XSLFConnectorShape extends XSLFSimpleShape { AffineTransform at = new AffineTransform(); Shape shape = null; + Path p = null; Rectangle2D bounds; double scaleY = Math.pow(2, tailWidth.ordinal()); double scaleX = Math.pow(2, tailLength.ordinal()); - switch (getLineHeadDecoration()) { + switch (getLineTailDecoration()) { case OVAL: + p = new Path(); shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY); bounds = shape.getBounds2D(); at.translate(x2 - bounds.getWidth() / 2, y2 - bounds.getHeight() / 2); at.rotate(alpha, bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2); break; case ARROW: + p = new Path(); GeneralPath arrow = new GeneralPath(); arrow.moveTo((float) (-lineWidth * 3), (float) (-lineWidth * 2)); arrow.lineTo(0, 0); @@ -259,6 +238,7 @@ public class XSLFConnectorShape extends XSLFSimpleShape { at.rotate(alpha); break; case TRIANGLE: + p = new Path(); scaleY = tailWidth.ordinal() + 1; scaleX = tailLength.ordinal() + 1; GeneralPath triangle = new GeneralPath(); @@ -277,10 +257,10 @@ public class XSLFConnectorShape extends XSLFSimpleShape { if (shape != null) { shape = at.createTransformedShape(shape); } - return shape; + return shape == null ? null : new Outline(shape, p); } - Shape getHeadDecoration() { + Outline getHeadDecoration() { LineEndLength headLength = getLineHeadLength(); LineEndWidth headWidth = getLineHeadWidth(); @@ -293,11 +273,13 @@ public class XSLFConnectorShape extends XSLFSimpleShape { AffineTransform at = new AffineTransform(); Shape shape = null; + Path p = null; Rectangle2D bounds; double scaleY = 1; double scaleX = 1; switch (getLineHeadDecoration()) { case OVAL: + p = new Path(); shape = new Ellipse2D.Double(0, 0, lineWidth * scaleX, lineWidth * scaleY); bounds = shape.getBounds2D(); at.translate(x1 - bounds.getWidth() / 2, y1 - bounds.getHeight() / 2); @@ -305,6 +287,7 @@ public class XSLFConnectorShape extends XSLFSimpleShape { break; case STEALTH: case ARROW: + p = new Path(); GeneralPath arrow = new GeneralPath(); arrow.moveTo((float) (lineWidth * 3 * scaleX), (float) (-lineWidth * scaleY * 2)); arrow.lineTo(0, 0); @@ -314,6 +297,7 @@ public class XSLFConnectorShape extends XSLFSimpleShape { at.rotate(alpha); break; case TRIANGLE: + p = new Path(); scaleY = headWidth.ordinal() + 1; scaleX = headLength.ordinal() + 1; GeneralPath triangle = new GeneralPath(); @@ -332,7 +316,19 @@ public class XSLFConnectorShape extends XSLFSimpleShape { if (shape != null) { shape = at.createTransformedShape(shape); } - return shape; + return shape == null ? null : new Outline(shape, p); + } + + @Override + List getCustomOutlines(){ + List lst = new ArrayList(); + + Outline head = getHeadDecoration(); + if(head != null) lst.add(head); + + Outline tail = getTailDecoration(); + if(tail != null) lst.add(tail); + return lst; } } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java index 6de6e4d775..c3b0b1a511 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java @@ -25,7 +25,8 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; -import java.awt.*; +import java.awt.Color; +import java.awt.Rectangle; /** diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java index 10490c0c9a..36afac5f8c 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java @@ -188,10 +188,4 @@ public class XSLFFreeformShape extends XSLFAutoShape { geom.addNewPathLst(); return ct; } - - @Override - protected java.awt.Shape getOutline(){ - return getPath(); - } - } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java index 8e6809bba2..5beb53850c 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java @@ -26,7 +26,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; -import java.awt.*; +import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; /** diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java index 95826af0e4..3159ee98a4 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java @@ -35,7 +35,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisual; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; -import java.awt.*; +import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.List; @@ -62,10 +62,12 @@ public class XSLFGroupShape extends XSLFShape { _spPr = shape.getGrpSpPr(); } + @Override public CTGroupShape getXmlObject(){ return _shape; } + @Override public Rectangle2D getAnchor(){ CTGroupTransform2D xfrm = _spPr.getXfrm(); CTPoint2D off = xfrm.getOff(); @@ -79,6 +81,7 @@ public class XSLFGroupShape extends XSLFShape { Units.toPoints(cx), Units.toPoints(cy)); } + @Override public void setAnchor(Rectangle2D anchor){ CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm(); CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff(); @@ -93,6 +96,12 @@ public class XSLFGroupShape extends XSLFShape { ext.setCy(cy); } + /** + * + * @return the coordinates of the child extents rectangle + * used for calculations of grouping, scaling, and rotation + * behavior of shapes placed within a group. + */ public Rectangle2D getInteriorAnchor(){ CTGroupTransform2D xfrm = _spPr.getXfrm(); CTPoint2D off = xfrm.getChOff(); @@ -106,6 +115,12 @@ public class XSLFGroupShape extends XSLFShape { Units.toPoints(cx), Units.toPoints(cy)); } + /** + * + * @param anchor the coordinates of the child extents rectangle + * used for calculations of grouping, scaling, and rotation + * behavior of shapes placed within a group. + */ public void setInteriorAnchor(Rectangle2D anchor){ CTGroupTransform2D xfrm = _spPr.isSetXfrm() ? _spPr.getXfrm() : _spPr.addNewXfrm(); CTPoint2D off = xfrm.isSetChOff() ? xfrm.getChOff() : xfrm.addNewChOff(); @@ -120,10 +135,17 @@ public class XSLFGroupShape extends XSLFShape { ext.setCy(cy); } + /** + * + * @return child shapes contained witin this group + */ public XSLFShape[] getShapes(){ return _shapes.toArray(new XSLFShape[_shapes.size()]); } + /** + * Remove the specified shape from this group + */ public boolean removeShape(XSLFShape xShape) { XmlObject obj = xShape.getXmlObject(); if(obj instanceof CTShape){ @@ -138,10 +160,12 @@ public class XSLFGroupShape extends XSLFShape { return _shapes.remove(xShape); } + @Override public String getShapeName(){ return _shape.getNvGrpSpPr().getCNvPr().getName(); } + @Override public int getShapeId(){ return (int)_shape.getNvGrpSpPr().getCNvPr().getId(); } @@ -216,53 +240,37 @@ public class XSLFGroupShape extends XSLFShape { return sh; } - + @Override public void setFlipHorizontal(boolean flip){ _spPr.getXfrm().setFlipH(flip); } + @Override public void setFlipVertical(boolean flip){ _spPr.getXfrm().setFlipV(flip); } - /** - * Whether the shape is horizontally flipped - * - * @return whether the shape is horizontally flipped - */ + + @Override public boolean getFlipHorizontal(){ return _spPr.getXfrm().getFlipH(); } + @Override public boolean getFlipVertical(){ return _spPr.getXfrm().getFlipV(); } - /** - * Rotate this shape. - *

- * Positive angles are clockwise (i.e., towards the positive y axis); - * negative angles are counter-clockwise (i.e., towards the negative y axis). - *

- * - * @param theta the rotation angle in degrees. - */ + @Override public void setRotation(double theta){ _spPr.getXfrm().setRot((int)(theta*60000)); } - /** - * Rotation angle in degrees - *

- * Positive angles are clockwise (i.e., towards the positive y axis); - * negative angles are counter-clockwise (i.e., towards the negative y axis). - *

- * - * @return rotation angle in degrees - */ + @Override public double getRotation(){ return (double)_spPr.getXfrm().getRot()/60000; } + @Override public void draw(Graphics2D graphics){ // the coordinate system of this group of shape @@ -278,16 +286,14 @@ public class XSLFGroupShape extends XSLFShape { for (XSLFShape shape : getShapes()) { // remember the initial transform and restore it after we are done with the drawing - AffineTransform at0 = graphics.getTransform(); + AffineTransform at = graphics.getTransform(); graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true); - // apply rotation and flipping - shape.applyTransform(graphics); - + shape.applyTransform(graphics); shape.draw(graphics); // restore the coordinate system - graphics.setTransform(at0); + graphics.setTransform(at); graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true); } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFImageRendener.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFImageRendener.java index 8f763622f4..a8bbe8b6a2 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFImageRendener.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFImageRendener.java @@ -19,10 +19,11 @@ package org.apache.poi.xslf.usermodel; +import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.util.Beta; import javax.imageio.ImageIO; -import java.awt.*; +import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; @@ -76,11 +77,10 @@ public class XSLFImageRendener { public boolean drawImage(Graphics2D graphics, XSLFPictureData data, Rectangle2D anchor) { try { - BufferedImage img = readImage(new ByteArrayInputStream(data.getData())); - if (img != null){ - graphics.drawImage(img, (int) anchor.getX(), (int) anchor.getY(), - (int) anchor.getWidth(), (int) anchor.getHeight(), null); - } + BufferedImage img = ImageIO.read(data.getPackagePart().getInputStream()); + graphics.drawImage(img, + (int) anchor.getX(), (int) anchor.getY(), + (int) anchor.getWidth(), (int) anchor.getHeight(), null); return true; } catch (Exception e) { return false; @@ -89,12 +89,13 @@ public class XSLFImageRendener { } /** - * create a buffered image from input stream + * Create a buffered image from the supplied package part. + * This method is called to create texture paints. * * @return a BufferedImage containing the decoded * contents of the input, or null. */ - public BufferedImage readImage(InputStream is) throws IOException { - return ImageIO.read(is); + public BufferedImage readImage(PackagePart packagePart) throws IOException { + return ImageIO.read(packagePart.getInputStream()); } } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java index 3025afcc40..ac4a4d2870 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java @@ -75,4 +75,9 @@ public final class XSLFNotes extends XSLFSheet { protected String getRootElementName(){ return "notes"; } + + @Override + public XSLFSheet getMasterSheet() { + return null; + } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java index 05813bdb96..77ebf05956 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java @@ -24,7 +24,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMaster; import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument; import java.io.IOException; -import java.util.Map; /** * Notes master object associated with this layout. @@ -45,8 +44,6 @@ import java.util.Map; @Beta public class XSLFNotesMaster extends XSLFSheet { private CTNotesMaster _slide; - private Map _layouts; - private XSLFTheme _theme; XSLFNotesMaster() { super(); @@ -70,4 +67,10 @@ import java.util.Map; protected String getRootElementName(){ return "notesMaster"; } + + @Override + public XSLFSheet getMasterSheet() { + return null; + } + } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java index 0ceb5c5636..445c16e9b0 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java @@ -33,12 +33,14 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; import org.openxmlformats.schemas.presentationml.x2006.main.CTPictureNonVisual; import javax.imageio.ImageIO; -import java.awt.*; +import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; /** + * Represents a picture shape + * * @author Yegor Kozlov */ @Beta @@ -114,37 +116,14 @@ public class XSLFPictureShape extends XSLFSimpleShape { } @Override - public void draw(Graphics2D graphics){ - java.awt.Shape outline = getOutline(); - - // shadow - XSLFShadow shadow = getShadow(); - - Paint fill = getFill(graphics); - Paint line = getLinePaint(graphics); - if(shadow != null) { - shadow.draw(graphics); - } - - if(fill != null) { - graphics.setPaint(fill); - graphics.fill(outline); - } - + public void drawContent(Graphics2D graphics) { XSLFPictureData data = getPictureData(); if(data == null) return; - + XSLFImageRendener renderer = (XSLFImageRendener)graphics.getRenderingHint(XSLFRenderingHint.IMAGE_RENDERER); if(renderer == null) renderer = new XSLFImageRendener(); renderer.drawImage(graphics, data, getAnchor()); - - if (line != null){ - graphics.setPaint(line); - applyStroke(graphics); - graphics.draw(outline); - } } - } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRenderingHint.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRenderingHint.java index cc0df0fbfd..345d57c4b3 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRenderingHint.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRenderingHint.java @@ -19,7 +19,7 @@ package org.apache.poi.xslf.usermodel; -import java.awt.*; +import java.awt.RenderingHints; /** * @@ -38,5 +38,37 @@ public class XSLFRenderingHint extends RenderingHints.Key { public static final XSLFRenderingHint GSAVE = new XSLFRenderingHint(1); public static final XSLFRenderingHint GRESTORE = new XSLFRenderingHint(2); + + /** + * Use a custom image rendener + * + * @see XSLFImageRendener + */ public static final XSLFRenderingHint IMAGE_RENDERER = new XSLFRenderingHint(3); + + /** + * how to render text: + * + * {@link #TEXT_MODE_CHARACTERS} (default) means to draw via + * {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}. + * This mode draws text as characters. Use it if the target graphics writes the actual + * character codes instead of glyph outlines (PDFGraphics2D, SVGGraphics2D, etc.) + * + * {@link #TEXT_MODE_GLYPHS} means to render via + * {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}. + * This mode draws glyphs as shapes and provides some advanced capabilities such as + * justification and font substitution. Use it if the target graphics is an image. + * + */ + public static final XSLFRenderingHint TEXT_RENDERING_MODE = new XSLFRenderingHint(4); + + /** + * draw text via {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)} + */ + public static final int TEXT_MODE_CHARACTERS = 1; + + /** + * draw text via {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)} + */ + public static final int TEXT_MODE_GLYPHS = 2; } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java index 8838fa3e41..70d42ce5c3 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java @@ -19,8 +19,11 @@ package org.apache.poi.xslf.usermodel; import org.apache.poi.util.Units; import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect; +import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; -import java.awt.*; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; import java.awt.geom.Rectangle2D; /** @@ -37,36 +40,44 @@ public class XSLFShadow extends XSLFSimpleShape { _parent = parentShape; } - @Override - public void draw(Graphics2D graphics) { - Shape outline = _parent.getOutline(); - Paint parentFillColor = _parent.getFill(graphics); - Paint parentLineColor = _parent.getLinePaint(graphics); + public void fill(Graphics2D graphics, Shape outline) { double angle = getAngle(); double dist = getDistance(); - double dx = dist * Math.cos( Math.toRadians(angle)); - double dy = dist * Math.sin( Math.toRadians(angle)); + double dx = dist * Math.cos(Math.toRadians(angle)); + double dy = dist * Math.sin(Math.toRadians(angle)); graphics.translate(dx, dy); Color fillColor = getFillColor(); if (fillColor != null) { graphics.setColor(fillColor); + 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); } + @Override public Rectangle2D getAnchor(){ return _parent.getAnchor(); @@ -112,6 +123,11 @@ public class XSLFShadow extends XSLFSimpleShape { public Color getFillColor() { XSLFTheme theme = getSheet().getTheme(); CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject(); - return ct == null ? null : new XSLFColor(ct, theme).getColor(); + if(ct == null) { + return null; + } else { + CTSchemeColor phClr = ct.getSchemeClr(); + return new XSLFColor(ct, theme, phClr).getColor(); + } } } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java index 992973c518..9ff619257c 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java @@ -22,24 +22,54 @@ package org.apache.poi.xslf.usermodel; import org.apache.poi.util.Beta; import org.apache.xmlbeans.XmlObject; -import java.awt.*; +import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; /** + * Base super-class class for all shapes in PresentationML + * * @author Yegor Kozlov */ @Beta public abstract class XSLFShape { - + /** + * + * @return the position of this shape within the drawing canvas. + * The coordinates are expressed in points + */ public abstract Rectangle2D getAnchor(); + /** + * + * @param anchor the position of this shape within the drawing canvas. + * The coordinates are expressed in points + */ public abstract void setAnchor(Rectangle2D anchor); + /** + * + * @return the xml bean holding this shape's data + */ public abstract XmlObject getXmlObject(); + /** + * + * @return human-readable name of this shape, e.g. "Rectange 3" + */ public abstract String getShapeName(); + /** + * Returns a unique identifier for this shape within the current document. + * This ID may be used to assist in uniquely identifying this object so that it can + * be referred to by other parts of the document. + *

+ * If multiple objects within the same document share the same id attribute value, + * then the document shall be considered non-conformant. + *

+ * + * @return unique id of this shape + */ public abstract int getShapeId(); /** @@ -64,8 +94,16 @@ public abstract class XSLFShape { */ public abstract double getRotation(); + /** + * @param flip whether the shape is horizontally flipped + */ public abstract void setFlipHorizontal(boolean flip); + /** + * Whether the shape is vertically flipped + * + * @param flip whether the shape is vertically flipped + */ public abstract void setFlipVertical(boolean flip); /** @@ -75,14 +113,25 @@ public abstract class XSLFShape { */ public abstract boolean getFlipHorizontal(); + /** + * Whether the shape is vertically flipped + * + * @return whether the shape is vertically flipped + */ public abstract boolean getFlipVertical(); + /** + * Draw this shape into the supplied canvas + * + * @param graphics the graphics to draw into + */ public abstract void draw(Graphics2D graphics); - protected java.awt.Shape getOutline(){ - return getAnchor(); - } - + /** + * Apply 2-D transforms before drawing this shape. This includes rotation and flipping. + * + * @param graphics the graphics whos transform matrix will be modified + */ protected void applyTransform(Graphics2D graphics){ Rectangle2D anchor = getAnchor(); @@ -112,5 +161,5 @@ public abstract class XSLFShape { graphics.translate(-anchor.getX(), -anchor.getY()); } } - + } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java index 87da995d49..964df2df96 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java @@ -21,9 +21,9 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.util.Beta; +import org.apache.poi.util.Internal; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle; import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId; import org.openxmlformats.schemas.presentationml.x2006.main.CTCommonSlideData; import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; @@ -34,22 +34,25 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; import javax.xml.namespace.QName; -import java.awt.*; +import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Pattern; @Beta -public abstract class XSLFSheet extends POIXMLDocumentPart { +public abstract class XSLFSheet extends POIXMLDocumentPart implements Iterable { private XSLFCommonSlideData _commonSlideData; private XSLFDrawing _drawing; private List _shapes; private CTGroupShape _spTree; + + private List_placeholders; private Map _placeholderByIdMap; private Map _placeholderByTypeMap; @@ -61,6 +64,10 @@ public abstract class XSLFSheet extends POIXMLDocumentPart { super(part, rel); } + /** + * + * @return the XMLSlideShow this sheet belongs to + */ public XMLSlideShow getSlideShow() { POIXMLDocumentPart p = getParent(); while(p != null) { @@ -69,7 +76,7 @@ public abstract class XSLFSheet extends POIXMLDocumentPart { } p = p.getParent(); } - return null; + throw new IllegalStateException("SlideShow was not found"); } protected List buildShapes(CTGroupShape spTree){ @@ -92,11 +99,16 @@ public abstract class XSLFSheet extends POIXMLDocumentPart { return shapes; } + /** + * @return top-level Xml bean representing this sheet + */ public abstract XmlObject getXmlObject(); + @Internal public XSLFCommonSlideData getCommonSlideData() { return _commonSlideData; } + protected void setCommonSlideData(CTCommonSlideData data) { if(data == null) { _commonSlideData = null; @@ -180,10 +192,34 @@ public abstract class XSLFSheet extends POIXMLDocumentPart { return sh; } + /** + * Returns an array containing all of the shapes in this sheet + * + * @return an array of all shapes in this sheet + */ public XSLFShape[] getShapes(){ return getShapeList().toArray(new XSLFShape[_shapes.size()]); } + /** + * Returns an iterator over the shapes in this sheet + * + * @return an iterator over the shapes in this sheet + */ + public Iterator 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 true if this sheet contained the specified element + * @throws IllegalArgumentException if the type of the specified shape + * is incompatible with this sheet (optional) + */ public boolean removeShape(XSLFShape xShape) { XmlObject obj = xShape.getXmlObject(); CTGroupShape spTree = getSpTree(); @@ -199,10 +235,6 @@ public abstract class XSLFSheet extends POIXMLDocumentPart { return getShapeList().remove(xShape); } - public XSLFBackground getBackground(){ - return null; - } - protected abstract String getRootElementName(); protected CTGroupShape getSpTree(){ @@ -248,22 +280,22 @@ public abstract class XSLFSheet extends POIXMLDocumentPart { getXmlObject().set(src.getXmlObject()); } - public XSLFTheme getTheme(){ - return null; - } - - public XSLFSlideMaster getSlideMaster(){ + /** + * @return theme (shared styles) associated with this theme. + * By default returns null which means that this sheet is theme-less. + * Sheets that support the notion of themes (slides, masters, layouts, etc.) should override this + * method and return the corresposnding package part. + */ + XSLFTheme getTheme(){ return null; } - public 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){ for(XSLFShape shape : this.getShapes()){ if(shape instanceof XSLFTextShape) { @@ -286,72 +318,107 @@ public abstract class XSLFSheet extends POIXMLDocumentPart { return shape; } - XSLFSimpleShape getPlaceholderById(int id) { - if(_placeholderByIdMap == null) { + void initPlaceholders() { + if(_placeholders == null) { + _placeholders = new ArrayList(); _placeholderByIdMap = new HashMap(); + _placeholderByTypeMap = new HashMap(); + for(XSLFShape sh : getShapes()){ - if(sh instanceof XSLFSimpleShape){ - XSLFSimpleShape sShape = (XSLFSimpleShape)sh; + if(sh instanceof XSLFTextShape){ + XSLFTextShape sShape = (XSLFTextShape)sh; CTPlaceholder ph = sShape.getCTPlaceholder(); - if(ph != null && ph.isSetIdx()){ - int idx = (int)ph.getIdx(); - _placeholderByIdMap.put(idx, sShape); + if(ph != null) { + _placeholders.add(sShape); + if(ph.isSetIdx()) { + int idx = (int)ph.getIdx(); + _placeholderByIdMap.put(idx, sShape); + } + if(ph.isSetType()){ + _placeholderByTypeMap.put(ph.getType().intValue(), sShape); + } } } } } + } + + XSLFSimpleShape getPlaceholderById(int id) { + initPlaceholders(); return _placeholderByIdMap.get(id); } XSLFSimpleShape getPlaceholderByType(int ordinal) { - if(_placeholderByTypeMap == null) { - _placeholderByTypeMap = new HashMap(); - for(XSLFShape sh : getShapes()){ - if(sh instanceof XSLFSimpleShape){ - XSLFSimpleShape sShape = (XSLFSimpleShape)sh; - CTPlaceholder ph = sShape.getCTPlaceholder(); - if(ph != null && ph.isSetType()){ - _placeholderByTypeMap.put(ph.getType().intValue(), sShape); - } - } - } - } + initPlaceholders(); return _placeholderByTypeMap.get(ordinal); } + /** + * + * @param idx 0-based index of a placeholder in the sheet + * @return placeholder + */ + public XSLFTextShape getPlaceholder(int idx) { + initPlaceholders(); + return _placeholders.get(idx); + } + + /** + * + * @return all placeholder shapes in this sheet + */ + public XSLFTextShape[] getPlaceholders() { + initPlaceholders(); + return _placeholders.toArray(new XSLFTextShape[_placeholders.size()]); + } + /** * Checks if this sheet displays the specified shape. * - * Subclasses can override it and skip certain shapes from drawings. + * Subclasses can override it and skip certain shapes from drawings, + * for instance, slide masters and layouts don't display placeholders */ protected boolean canDraw(XSLFShape shape){ return true; } + /** + * + * @return whether shapes on the master sheet should be shown. By default master graphics is turned off. + * Sheets that support the notion of master (slide, slideLayout) should override it and + * check this setting in the sheet XML + */ + public boolean getFollowMasterGraphics(){ + return false; + } + /** * Render this sheet into the supplied graphics object * * @param graphics */ public void draw(Graphics2D graphics){ - XSLFBackground bg = getBackground(); - if(bg != null) bg.draw(graphics); + XSLFSheet master = getMasterSheet(); + if(getFollowMasterGraphics() && master != null) master.draw(graphics); for(XSLFShape shape : getShapeList()) { if(!canDraw(shape)) continue; // remember the initial transform and restore it after we are done with drawing - AffineTransform at0 = graphics.getTransform(); + AffineTransform at = graphics.getTransform(); + // concrete implementations can make sense of this hint, + // for example PSGraphics2D or PDFGraphics2D would call gsave() / grestore graphics.setRenderingHint(XSLFRenderingHint.GSAVE, true); // apply rotation and flipping shape.applyTransform(graphics); - + // draw stuff shape.draw(graphics); // restore the coordinate system - graphics.setTransform(at0); + graphics.setTransform(at); + graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true); } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java index 10bad70d03..c67f39e793 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java @@ -19,8 +19,6 @@ package org.apache.poi.xslf.usermodel; -import org.apache.poi.openxml4j.opc.PackagePart; -import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.util.Beta; import org.apache.poi.util.Units; import org.apache.poi.xslf.model.PropertyFetcher; @@ -28,36 +26,50 @@ import org.apache.poi.xslf.model.geom.Context; import org.apache.poi.xslf.model.geom.CustomGeometry; import org.apache.poi.xslf.model.geom.Guide; import org.apache.poi.xslf.model.geom.IAdjustableShape; +import org.apache.poi.xslf.model.geom.Outline; import org.apache.poi.xslf.model.geom.Path; import org.apache.poi.xslf.model.geom.PresetGeometries; import org.apache.xmlbeans.XmlObject; -import org.openxmlformats.schemas.drawingml.x2006.main.*; +import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem; +import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide; +import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; +import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetLineDashProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor; +import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; +import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; +import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap; +import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; +import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; -import java.awt.Paint; -import java.awt.Graphics2D; -import java.awt.Color; -import java.awt.TexturePaint; -import java.awt.AlphaComposite; -import java.awt.GradientPaint; -import java.awt.BasicStroke; -import java.awt.Stroke; -import java.util.Arrays; -import java.util.Comparator; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Constructor; +import java.util.Collection; +import java.util.Collections; +import java.util.List; /** + * Represents a single (non-group) shape in a .pptx slide show + * * @author Yegor Kozlov */ @Beta public abstract class XSLFSimpleShape extends XSLFShape { + private final XmlObject _shape; private final XSLFSheet _sheet; private CTShapeProperties _spPr; @@ -70,10 +82,15 @@ public abstract class XSLFSimpleShape extends XSLFShape { _sheet = sheet; } + @Override public XmlObject getXmlObject() { return _shape; } + /** + * + * @return the sheet this shape belongs to + */ public XSLFSheet getSheet() { return _sheet; } @@ -88,10 +105,12 @@ public abstract class XSLFSimpleShape extends XSLFShape { return stEnum == null ? 0 : stEnum.intValue(); } + @Override public String getShapeName() { return getNvPr().getName(); } + @Override public int getShapeId() { return (int) getNvPr().getId(); } @@ -132,22 +151,22 @@ public abstract class XSLFSimpleShape extends XSLFShape { return _spStyle; } - protected CTPlaceholder getCTPlaceholder(){ - if(_ph == null){ + protected CTPlaceholder getCTPlaceholder() { + if (_ph == null) { XmlObject[] obj = _shape.selectPath( "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:nvPr/p:ph"); - if(obj.length == 1){ - _ph = (CTPlaceholder)obj[0]; + if (obj.length == 1) { + _ph = (CTPlaceholder) obj[0]; } } return _ph; } - private CTTransform2D getXfrm(){ - PropertyFetcher fetcher = new PropertyFetcher(){ - public boolean fetch(XSLFSimpleShape shape){ + private CTTransform2D getXfrm() { + PropertyFetcher fetcher = new PropertyFetcher() { + public boolean fetch(XSLFSimpleShape shape) { CTShapeProperties pr = shape.getSpPr(); - if(pr.isSetXfrm()){ + if (pr.isSetXfrm()) { setValue(pr.getXfrm()); return true; } @@ -158,10 +177,11 @@ public abstract class XSLFSimpleShape extends XSLFShape { return fetcher.getValue(); } + @Override public Rectangle2D getAnchor() { CTTransform2D xfrm = getXfrm(); - + CTPoint2D off = xfrm.getOff(); long x = off.getX(); long y = off.getY(); @@ -173,6 +193,7 @@ public abstract class XSLFSimpleShape extends XSLFShape { Units.toPoints(cx), Units.toPoints(cy)); } + @Override public void setAnchor(Rectangle2D anchor) { CTShapeProperties spPr = getSpPr(); CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); @@ -189,64 +210,46 @@ public abstract class XSLFSimpleShape extends XSLFShape { ext.setCy(cy); } - /** - * Rotate this shape. - *

- * Positive angles are clockwise (i.e., towards the positive y axis); - * negative angles are counter-clockwise (i.e., towards the negative y - * axis). - *

- * - * @param theta the rotation angle in degrees. - */ + @Override public void setRotation(double theta) { CTShapeProperties spPr = getSpPr(); CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); xfrm.setRot((int) (theta * 60000)); } - /** - * Rotation angle in degrees - *

- * Positive angles are clockwise (i.e., towards the positive y axis); - * negative angles are counter-clockwise (i.e., towards the negative y - * axis). - *

- * - * @return rotation angle in degrees - */ + @Override public double getRotation() { CTTransform2D xfrm = getXfrm(); return (double) xfrm.getRot() / 60000; } + @Override public void setFlipHorizontal(boolean flip) { CTShapeProperties spPr = getSpPr(); CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); xfrm.setFlipH(flip); } + @Override public void setFlipVertical(boolean flip) { CTShapeProperties spPr = getSpPr(); CTTransform2D xfrm = spPr.isSetXfrm() ? spPr.getXfrm() : spPr.addNewXfrm(); xfrm.setFlipV(flip); } - /** - * Whether the shape is horizontally flipped - * - * @return whether the shape is horizontally flipped - */ + @Override public boolean getFlipHorizontal() { return getXfrm().getFlipH(); } + @Override public boolean getFlipVertical() { return getXfrm().getFlipV(); } /** - * Get line properties defined in the theme (if any) + * Get default line properties defined in the theme (if any). + * Used internally to resolve shape properties. * * @return line propeties from the theme of null */ @@ -262,6 +265,10 @@ public abstract class XSLFSimpleShape extends XSLFShape { return ln; } + /** + * @param color the color to paint the shape outline. + * A null value turns off the shape outline. + */ public void setLineColor(Color color) { CTShapeProperties spPr = getSpPr(); if (color == null) { @@ -281,48 +288,24 @@ public abstract class XSLFSimpleShape extends XSLFShape { } } + /** + * + * @return the color of the shape outline or null + * if outline is turned off + */ public Color getLineColor() { - Paint paint = getLinePaint(null); - if(paint instanceof Color){ - return (Color)paint; + RenderableShape rShape = new RenderableShape(this); + Paint paint = rShape.getLinePaint(null); + if (paint instanceof Color) { + return (Color) paint; } return null; } - public Paint getLinePaint(final Graphics2D graphics) { - final XSLFTheme theme = _sheet.getTheme(); - final Color nofill = new Color(0,0,0,0); - PropertyFetcher fetcher = new PropertyFetcher(){ - 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. 0 means no line + */ public void setLineWidth(double width) { CTShapeProperties spPr = getSpPr(); if (width == 0.) { @@ -335,9 +318,13 @@ public abstract class XSLFSimpleShape extends XSLFShape { } } + /** + * + * @return line width in points. 0 means no line. + */ public double getLineWidth() { - PropertyFetcher fetcher = new PropertyFetcher(){ - public boolean fetch(XSLFSimpleShape shape){ + PropertyFetcher fetcher = new PropertyFetcher() { + public boolean fetch(XSLFSimpleShape shape) { CTShapeProperties spPr = shape.getSpPr(); CTLineProperties ln = spPr.getLn(); if (ln != null) { @@ -347,7 +334,7 @@ public abstract class XSLFSimpleShape extends XSLFShape { } if (ln.isSetW()) { - setValue( Units.toPoints(ln.getW()) ); + setValue(Units.toPoints(ln.getW())); return true; } } @@ -357,7 +344,7 @@ public abstract class XSLFSimpleShape extends XSLFShape { fetchShapeProperty(fetcher); double lineWidth = 0; - if(fetcher.getValue() == null) { + if (fetcher.getValue() == null) { CTLineProperties defaultLn = getDefaultLineProperties(); if (defaultLn != null) { if (defaultLn.isSetW()) lineWidth = Units.toPoints(defaultLn.getW()); @@ -369,6 +356,10 @@ public abstract class XSLFSimpleShape extends XSLFShape { return lineWidth; } + /** + * + * @param dash a preset line dashing scheme to stroke thr shape outline + */ public void setLineDash(LineDash dash) { CTShapeProperties spPr = getSpPr(); if (dash == null) { @@ -384,16 +375,19 @@ public abstract class XSLFSimpleShape extends XSLFShape { } } + /** + * @return a preset line dashing scheme to stroke thr shape outline + */ public LineDash getLineDash() { - PropertyFetcher fetcher = new PropertyFetcher(){ - public boolean fetch(XSLFSimpleShape shape){ + PropertyFetcher fetcher = new PropertyFetcher() { + public boolean fetch(XSLFSimpleShape shape) { CTShapeProperties spPr = shape.getSpPr(); CTLineProperties ln = spPr.getLn(); if (ln != null) { CTPresetLineDashProperties ctDash = ln.getPrstDash(); if (ctDash != null) { - setValue( LineDash.values()[ctDash.getVal().intValue() - 1] ); + setValue(LineDash.values()[ctDash.getVal().intValue() - 1]); return true; } } @@ -403,7 +397,7 @@ public abstract class XSLFSimpleShape extends XSLFShape { fetchShapeProperty(fetcher); LineDash dash = fetcher.getValue(); - if(dash == null){ + if (dash == null) { CTLineProperties defaultLn = getDefaultLineProperties(); if (defaultLn != null) { CTPresetLineDashProperties ctDash = defaultLn.getPrstDash(); @@ -415,6 +409,10 @@ public abstract class XSLFSimpleShape extends XSLFShape { return dash; } + /** + * + * @param cap the line end cap style + */ public void setLineCap(LineCap cap) { CTShapeProperties spPr = getSpPr(); if (cap == null) { @@ -427,15 +425,19 @@ public abstract class XSLFSimpleShape extends XSLFShape { } } + /** + * + * @return the line end cap style + */ public LineCap getLineCap() { - PropertyFetcher fetcher = new PropertyFetcher(){ - public boolean fetch(XSLFSimpleShape shape){ + PropertyFetcher fetcher = new PropertyFetcher() { + public boolean fetch(XSLFSimpleShape shape) { CTShapeProperties spPr = shape.getSpPr(); CTLineProperties ln = spPr.getLn(); if (ln != null) { STLineCap.Enum stCap = ln.getCap(); if (stCap != null) { - setValue( LineCap.values()[stCap.intValue() - 1] ); + setValue(LineCap.values()[stCap.intValue() - 1]); return true; } } @@ -445,7 +447,7 @@ public abstract class XSLFSimpleShape extends XSLFShape { fetchShapeProperty(fetcher); LineCap cap = fetcher.getValue(); - if(cap == null){ + if (cap == null) { CTLineProperties defaultLn = getDefaultLineProperties(); if (defaultLn != null) { STLineCap.Enum stCap = defaultLn.getCap(); @@ -469,10 +471,10 @@ public abstract class XSLFSimpleShape extends XSLFShape { if (color == null) { if (spPr.isSetSolidFill()) spPr.unsetSolidFill(); - if(!spPr.isSetNoFill()) spPr.addNewNoFill(); + if (!spPr.isSetNoFill()) spPr.addNewNoFill(); } else { - if(spPr.isSetNoFill()) spPr.unsetNoFill(); - + if (spPr.isSetNoFill()) spPr.unsetNoFill(); + CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr .getSolidFill() : spPr.addNewSolidFill(); @@ -485,55 +487,24 @@ public abstract class XSLFSimpleShape extends XSLFShape { } /** - * @return solid fill color of null if not set + * @return solid fill color of null if not set or fill color + * is not solid (pattern or gradient) */ public Color getFillColor() { - Paint paint = getFill(null); - if(paint instanceof Color){ - return (Color)paint; + RenderableShape rShape = new RenderableShape(this); + Paint paint = rShape.getFillPaint(null); + if (paint instanceof Color) { + return (Color) paint; } return null; } /** - * fetch shape fill as a java.awt.Paint - * - * @return either Color or GradientPaint or TexturePaint or null + * @return shadow of this shape or null if shadow is disabled */ - Paint getFill(final Graphics2D graphics) { - final XSLFTheme theme = _sheet.getTheme(); - final Color nofill = new Color(0xFF,0xFF,0xFF, 0); - PropertyFetcher fetcher = new PropertyFetcher(){ - 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 fetcher = new PropertyFetcher(){ - public boolean fetch(XSLFSimpleShape shape){ + public XSLFShadow getShadow() { + PropertyFetcher fetcher = new PropertyFetcher() { + public boolean fetch(XSLFSimpleShape shape) { CTShapeProperties spPr = shape.getSpPr(); if (spPr.isSetEffectLst()) { CTOuterShadowEffect obj = spPr.getEffectLst().getOuterShdw(); @@ -546,233 +517,48 @@ public abstract class XSLFSimpleShape extends XSLFShape { fetchShapeProperty(fetcher); CTOuterShadowEffect obj = fetcher.getValue(); - if(obj == null){ + if (obj == null) { // fill color was not found, check if it is defined in the theme CTShapeStyle style = getSpStyle(); if (style != null) { // 1-based index of a shadow style within the style matrix int idx = (int) style.getEffectRef().getIdx(); - - CTStyleMatrix styleMatrix = _sheet.getTheme().getXmlObject().getThemeElements().getFmtScheme(); - CTEffectStyleItem ef = styleMatrix.getEffectStyleLst().getEffectStyleArray(idx - 1); - obj = ef.getEffectLst().getOuterShdw(); + if(idx != 0) { + CTStyleMatrix styleMatrix = _sheet.getTheme().getXmlObject().getThemeElements().getFmtScheme(); + CTEffectStyleItem ef = styleMatrix.getEffectStyleLst().getEffectStyleArray(idx - 1); + obj = ef.getEffectLst().getOuterShdw(); + } } } return obj == null ? null : new XSLFShadow(obj, this); } + @Override public void draw(Graphics2D graphics) { - - } - - @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(){ - 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: + *

+ * slide <-- slideLayout <-- slideMaster <-- default styles in the slideMaster + *

* - * @param visitor the object that collects the desired property + * @param visitor the object that collects the desired property * @return true if the property was fetched */ - boolean fetchShapeProperty(PropertyFetcher visitor){ + boolean fetchShapeProperty(PropertyFetcher visitor) { boolean ok = visitor.fetch(this); XSLFSimpleShape masterShape; - if(!ok){ - - // first try to fetch from the slide layout - XSLFSlideLayout layout = getSheet().getSlideLayout(); - if(layout != null) { + XSLFSheet layout = getSheet().getMasterSheet(); + if (layout != null) { + if (!ok) { + // first try to fetch from the slide layout CTPlaceholder ph = getCTPlaceholder(); if (ph != null) { masterShape = layout.getPlaceholder(ph); @@ -781,96 +567,77 @@ public abstract class XSLFSimpleShape extends XSLFShape { } } } - } - // try slide master - if (!ok) { - int textType; - CTPlaceholder ph = getCTPlaceholder(); - if(ph == null || !ph.isSetType()) textType = STPlaceholderType.INT_BODY; - else { - switch(ph.getType().intValue()){ - case STPlaceholderType.INT_TITLE: - case STPlaceholderType.INT_CTR_TITLE: - textType = STPlaceholderType.INT_TITLE; - break; - case STPlaceholderType.INT_FTR: - case STPlaceholderType.INT_SLD_NUM: - case STPlaceholderType.INT_DT: - textType = ph.getType().intValue(); - break; - default: - textType = STPlaceholderType.INT_BODY; - break; + // try slide master + if (!ok) { + int textType; + CTPlaceholder ph = getCTPlaceholder(); + if (ph == null || !ph.isSetType()) textType = STPlaceholderType.INT_BODY; + else { + switch (ph.getType().intValue()) { + case STPlaceholderType.INT_TITLE: + case STPlaceholderType.INT_CTR_TITLE: + textType = STPlaceholderType.INT_TITLE; + break; + case STPlaceholderType.INT_FTR: + case STPlaceholderType.INT_SLD_NUM: + case STPlaceholderType.INT_DT: + textType = ph.getType().intValue(); + break; + default: + textType = STPlaceholderType.INT_BODY; + break; + } } - } - XSLFSlideMaster master = getSheet().getSlideMaster(); - if(master != null) { - masterShape = master.getPlaceholderByType(textType); - if (masterShape != null) { - ok = visitor.fetch(masterShape); + XSLFSheet master = layout.getMasterSheet(); + if (master != null) { + masterShape = master.getPlaceholderByType(textType); + if (masterShape != null) { + ok = visitor.fetch(masterShape); + } } } } - return ok; } - - @Override - protected java.awt.Shape getOutline(){ - PresetGeometries dict = PresetGeometries.getInstance(); + /** + * + * @return definition of the shape geometry + */ + CustomGeometry getGeometry(){ CTShapeProperties spPr = getSpPr(); - String name; - if(spPr.isSetPrstGeom()) { - name = spPr.getPrstGeom().getPrst().toString(); + 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 { - 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 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){ + } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java index f6f92d4f59..598baaeee4 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java @@ -32,7 +32,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShapeNonVisua import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide; import org.openxmlformats.schemas.presentationml.x2006.main.SldDocument; -import java.awt.*; +import java.awt.Graphics2D; import java.io.IOException; @Beta @@ -109,11 +109,11 @@ public final class XSLFSlide extends XSLFSheet { return "sld"; } - public XSLFSlideMaster getMasterSheet(){ - return getSlideLayout().getSlideMaster(); + @Override + public XSLFSlideLayout getMasterSheet(){ + return getSlideLayout(); } - @Override public XSLFSlideLayout getSlideLayout(){ if(_layout == null){ for (POIXMLDocumentPart p : getRelations()) { @@ -128,7 +128,6 @@ public final class XSLFSlide extends XSLFSheet { return _layout; } - @Override public XSLFSlideMaster getSlideMaster(){ return getSlideLayout().getSlideMaster(); } @@ -159,20 +158,12 @@ public final class XSLFSlide extends XSLFSheet { } if(_notes == null) { // This slide lacks notes - // Not al have them, sorry... + // Not all have them, sorry... return null; } return _notes; } - public void setFollowMasterBackground(boolean value){ - _slide.setShowMasterSp(value); - } - - public boolean getFollowMasterBackground(){ - return !_slide.isSetShowMasterSp() || _slide.getShowMasterSp(); - } - /** * * @return title of this slide or empty string if title is not set @@ -182,27 +173,59 @@ public final class XSLFSlide extends XSLFSheet { return txt == null ? "" : txt.getText(); } + @Override public XSLFTheme getTheme(){ return getSlideLayout().getSlideMaster().getTheme(); } - @Override - public void draw(Graphics2D graphics){ - - 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()) { return new XSLFBackground(_slide.getCSld().getBg(), this); } + + XSLFSlideLayout layout = getMasterSheet(); + if(layout.getXmlObject().getCSld().isSetBg()) { + return new XSLFBackground(layout.getXmlObject().getCSld().getBg(), this); + } + + XSLFSlideMaster master = layout.getMasterSheet(); + if(master.getXmlObject().getCSld().isSetBg()) { + return new XSLFBackground(master.getXmlObject().getCSld().getBg(), this); + } return null; } + /** + * + * @return whether shapes on the master slide should be shown or not. + */ + public boolean getFollowMasterGraphics(){ + return !_slide.isSetShowMasterSp() || _slide.getShowMasterSp(); + } + + /** + * + * @param value whether shapes on the master slide should be shown or not. + */ + public void setFollowMasterGraphics(boolean value){ + _slide.setShowMasterSp(value); + } + + + @Override + public void draw(Graphics2D graphics){ + + XSLFBackground bg = getBackground(); + if(bg != null) bg.draw(graphics); + + super.draw(graphics); + } + + } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java index 699d153345..4a505972dc 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java @@ -22,7 +22,6 @@ import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.util.Beta; import org.apache.poi.util.Internal; import org.apache.xmlbeans.XmlException; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle; import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideLayout; import org.openxmlformats.schemas.presentationml.x2006.main.SldLayoutDocument; @@ -42,13 +41,13 @@ public class XSLFSlideLayout extends XSLFSheet { public XSLFSlideLayout(PackagePart part, PackageRelationship rel) throws IOException, XmlException { super(part, rel); SldLayoutDocument doc = - SldLayoutDocument.Factory.parse(getPackagePart().getInputStream()); + SldLayoutDocument.Factory.parse(getPackagePart().getInputStream()); _layout = doc.getSldLayout(); setCommonSlideData(_layout.getCSld()); } - public String getName(){ + public String getName() { return _layout.getCSld().getName(); } @@ -61,79 +60,92 @@ public class XSLFSlideLayout extends XSLFSheet { } @Override - protected String getRootElementName(){ + protected String getRootElementName() { return "sldLayout"; } /** * Slide master object associated with this layout. - *

- * Within a slide master slide are contained all elements - * that describe the objects and their corresponding formatting - * for within a presentation slide. - *

- *

- * 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. - *

* * @return slide master. Never null. * @throws IllegalStateException if slide master was not found */ - @Override - public XSLFSlideMaster getSlideMaster(){ - if(_master == null){ + public XSLFSlideMaster getSlideMaster() { + if (_master == null) { for (POIXMLDocumentPart p : getRelations()) { - if (p instanceof XSLFSlideMaster){ - _master = (XSLFSlideMaster)p; - } - } + if (p instanceof XSLFSlideMaster) { + _master = (XSLFSlideMaster) p; + } + } } - if(_master == null) { + if (_master == null) { throw new IllegalStateException("SlideMaster was not found for " + this.toString()); } return _master; } - - public XSLFTheme getTheme(){ - return getSlideMaster().getTheme(); - } + @Override + public XSLFSlideMaster getMasterSheet() { + return getSlideMaster(); + } + + @Override + public XSLFTheme getTheme() { + return getSlideMaster().getTheme(); + } @Override - protected CTTextListStyle getTextProperties(Placeholder textType) { - XSLFTextShape lp = getTextShapeByType(textType); - CTTextListStyle props = lp.getTextBody(false).getLstStyle(); - return props; + public boolean getFollowMasterGraphics() { + return !_layout.isSetShowMasterSp() || _layout.getShowMasterSp(); } /** * Render this sheet into the supplied graphics object - * */ @Override - protected boolean canDraw(XSLFShape shape){ - if(shape instanceof XSLFSimpleShape){ - XSLFSimpleShape txt = (XSLFSimpleShape)shape; + protected boolean canDraw(XSLFShape shape) { + if (shape instanceof XSLFSimpleShape) { + XSLFSimpleShape txt = (XSLFSimpleShape) shape; CTPlaceholder ph = txt.getCTPlaceholder(); - if(ph != null) { + if (ph != null) { return false; } } return true; } - @Override - public XSLFBackground getBackground(){ - if(_layout.getCSld().isSetBg()) { - return new XSLFBackground(_layout.getCSld().getBg(), this); + /** + * Copy placeholders from this layout to the destination slide + * + * @param slide destination slide + */ + public void copyLayout(XSLFSlide slide) { + for (XSLFShape sh : getShapes()) { + if (sh instanceof XSLFTextShape) { + XSLFTextShape tsh = (XSLFTextShape) sh; + Placeholder ph = tsh.getTextType(); + if (ph == null) continue; + + switch (ph) { + // these are special and not copied by default + case DATETIME: + case SLIDE_NUMBER: + case FOOTER: + break; + default: + slide.getSpTree().addNewSp().set(tsh.getXmlObject().copy()); + } + } } - return getSlideMaster().getBackground(); + } + + /** + * + * @return type of this layout + */ + public SlideLayout getType(){ + int ordinal = _layout.getType().intValue() - 1; + return SlideLayout.values()[ordinal]; } } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java index 2ec83609a8..e73ee7a4c1 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java @@ -21,7 +21,9 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.util.Beta; import org.apache.xmlbeans.XmlException; +import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle; +import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster; import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterTextStyles; import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument; @@ -78,7 +80,12 @@ import java.util.Map; return "sldMaster"; } - public XSLFSlideLayout getLayout(String name){ + @Override + public XSLFSheet getMasterSheet() { + return null; + } + + private Map getLayouts(){ if(_layouts == null){ _layouts = new HashMap(); for (POIXMLDocumentPart p : getRelations()) { @@ -88,14 +95,36 @@ import java.util.Map; } } } - return _layouts.get(name); + return _layouts; } + /** + * + * @return all slide layouts referencing this master + */ + public XSLFSlideLayout[] getSlideLayouts() { + return getLayouts().values().toArray(new XSLFSlideLayout[_layouts.size()]); + } + + public XSLFSlideLayout getLayout(SlideLayout type){ + for(XSLFSlideLayout layout : getLayouts().values()){ + if(layout.getType() == type) { + return layout; + } + } + return null; + } + + @Override public XSLFTheme getTheme(){ if(_theme == null){ for (POIXMLDocumentPart p : getRelations()) { if (p instanceof XSLFTheme){ _theme = (XSLFTheme)p; + CTColorMapping cmap = _slide.getClrMap(); + if(cmap != null){ + _theme.initColorMap(cmap); + } break; } } @@ -122,11 +151,20 @@ import java.util.Map; return props; } + /** + * Render this sheet into the supplied graphics object + * + */ @Override - public XSLFBackground getBackground(){ - if(_slide.getCSld().isSetBg()) { - return new XSLFBackground(_slide.getCSld().getBg(), this); + protected boolean canDraw(XSLFShape shape){ + if(shape instanceof XSLFSimpleShape){ + XSLFSimpleShape txt = (XSLFSimpleShape)shape; + CTPlaceholder ph = txt.getCTPlaceholder(); + if(ph != null) { + return false; + } } - return null; + return true; } + } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java index 335e77d593..f3d4400aa0 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java @@ -35,7 +35,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth; import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment; import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; -import java.awt.*; +import java.awt.Color; /** * Represents a cell of a table in a .pptx presentation @@ -77,7 +77,7 @@ public class XSLFTableCell extends XSLFTextShape { } @Override - public void setMarginLeft(double margin){ + public void setLeftInset(double margin){ CTTableCellProperties pr = getXmlObject().getTcPr(); if(pr == null) pr = getXmlObject().addNewTcPr(); @@ -85,7 +85,7 @@ public class XSLFTableCell extends XSLFTextShape { } @Override - public void setMarginRight(double margin){ + public void setRightInset(double margin){ CTTableCellProperties pr = getXmlObject().getTcPr(); if(pr == null) pr = getXmlObject().addNewTcPr(); @@ -93,7 +93,7 @@ public class XSLFTableCell extends XSLFTextShape { } @Override - public void setMarginTop(double margin){ + public void setTopInset(double margin){ CTTableCellProperties pr = getXmlObject().getTcPr(); if(pr == null) pr = getXmlObject().addNewTcPr(); @@ -101,7 +101,7 @@ public class XSLFTableCell extends XSLFTextShape { } @Override - public void setMarginBottom(double margin){ + public void setBottomInset(double margin){ CTTableCellProperties pr = getXmlObject().getTcPr(); if(pr == null) pr = getXmlObject().addNewTcPr(); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java index 177e8099eb..ef523b4fc8 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java @@ -63,23 +63,4 @@ public class XSLFTextBox extends XSLFAutoShape { return ct; } - - /** - * Specifies that the corresponding shape should be represented by the generating application - * as a placeholder. When a shape is considered a placeholder by the generating application - * it can have special properties to alert the user that they may enter content into the shape. - * Different types of placeholders are allowed and can be specified by using the placeholder - * type attribute for this element - * - * @param placeholder - */ - public void setPlaceholder(Placeholder placeholder){ - CTShape sh = (CTShape)getXmlObject(); - CTApplicationNonVisualDrawingProps nv = sh.getNvSpPr().getNvPr(); - if(placeholder == null) { - if(nv.isSetPh()) nv.unsetPh(); - } else { - nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ordinal() + 1)); - } - } } \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java index a67dc0d34a..7134246bbb 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java @@ -30,7 +30,8 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType; import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; -import java.awt.*; +import java.awt.Color; +import java.awt.Graphics2D; import java.awt.font.LineBreakMeasurer; import java.awt.font.TextAttribute; import java.awt.font.TextLayout; @@ -80,6 +81,23 @@ public class XSLFTextParagraph implements Iterable{ return out.toString(); } + private String getVisibleText(){ + StringBuilder out = new StringBuilder(); + for (XSLFTextRun r : _runs) { + String txt = r.getText(); + switch (r.getTextCap()){ + case ALL: + txt = txt.toUpperCase(); + break; + case SMALL: + txt = txt.toLowerCase(); + break; + } + out.append(txt); + } + return out.toString(); + } + @Internal public CTTextParagraph getXmlObject(){ return _p; @@ -89,6 +107,7 @@ public class XSLFTextParagraph implements Iterable{ return _shape; } + public List getTextRuns(){ return _runs; } @@ -186,7 +205,7 @@ public class XSLFTextParagraph implements Iterable{ ParagraphPropertyFetcher fetcher = new ParagraphPropertyFetcher(getLevel()){ public boolean fetch(CTTextParagraphProperties props){ if(props.isSetBuClr()){ - XSLFColor c = new XSLFColor(props.getBuClr(), theme); + XSLFColor c = new XSLFColor(props.getBuClr(), theme, null); setValue(c.getColor()); return true; } @@ -496,17 +515,18 @@ public class XSLFTextParagraph implements Iterable{ return "[" + getClass() + "]" + getText(); } - public List getTextLines(){ + List getTextLines(){ return _lines; } public double draw(Graphics2D graphics, double x, double y){ - double marginLeft = _shape.getMarginLeft(); - double marginRight = _shape.getMarginRight(); + double marginLeft = _shape.getLeftInset(); + double marginRight = _shape.getRightInset(); Rectangle2D anchor = _shape.getAnchor(); double penY = y; double textOffset = getLeftMargin(); + boolean firstLine = true; for(TextFragment line : _lines){ double penX = x; switch (getTextAlign()) { @@ -521,7 +541,7 @@ public class XSLFTextParagraph implements Iterable{ break; } - if(_bullet != null){ + if(_bullet != null && firstLine){ _bullet.draw(graphics, penX + getIndent(), penY); } line.draw(graphics, penX, penY); @@ -535,6 +555,8 @@ public class XSLFTextParagraph implements Iterable{ // positive value means absolute spacing in points penY += -spacing; } + + firstLine = false; } return penY - y; } @@ -551,8 +573,12 @@ public class XSLFTextParagraph implements Iterable{ void draw(Graphics2D graphics, double x, double y){ double yBaseline = y + _layout.getAscent(); - graphics.drawString(_str.getIterator(), (float)x, (float)yBaseline ); - + Integer textMode = (Integer)graphics.getRenderingHint(XSLFRenderingHint.TEXT_RENDERING_MODE); + if(textMode != null && textMode == XSLFRenderingHint.TEXT_MODE_GLYPHS){ + _layout.draw(graphics, (float)x, (float)yBaseline); + } else { + graphics.drawString(_str.getIterator(), (float)x, (float)yBaseline ); + } } public float getHeight(){ @@ -564,8 +590,8 @@ public class XSLFTextParagraph implements Iterable{ } - public AttributedString getAttributedString(){ - String text = getText(); + AttributedString getAttributedString(Graphics2D graphics){ + String text = getVisibleText(); AttributedString string = new AttributedString(text); @@ -579,7 +605,10 @@ public class XSLFTextParagraph implements Iterable{ int endIndex = startIndex + length; string.addAttribute(TextAttribute.FOREGROUND, run.getFontColor(), startIndex, endIndex); + + // user can pass an object to convert fonts via a rendering hint string.addAttribute(TextAttribute.FAMILY, run.getFontFamily(), startIndex, endIndex); + string.addAttribute(TextAttribute.SIZE, (float)run.getFontSize(), startIndex, endIndex); if(run.isBold()) { string.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, startIndex, endIndex); @@ -601,6 +630,7 @@ public class XSLFTextParagraph implements Iterable{ string.addAttribute(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, startIndex, endIndex); } + startIndex = endIndex; } @@ -610,7 +640,7 @@ public class XSLFTextParagraph implements Iterable{ void breakText(Graphics2D graphics){ _lines = new ArrayList(); - AttributedString at = getAttributedString(); + AttributedString at = getAttributedString(graphics); AttributedCharacterIterator it = at.getIterator(); if(it.getBeginIndex() == it.getEndIndex()) { return; @@ -628,7 +658,8 @@ public class XSLFTextParagraph implements Iterable{ int endIndex = measurer.getPosition(); - if(getTextAlign() == TextAlign.JUSTIFY) { + TextAlign hAlign = getTextAlign(); + if(hAlign == TextAlign.JUSTIFY || hAlign == TextAlign.JUSTIFY_LOW) { layout = layout.getJustifiedLayout((float)wrappingWidth); } @@ -673,7 +704,7 @@ public class XSLFTextParagraph implements Iterable{ width = _shape.getSheet().getSlideShow().getPageSize().getWidth(); } else { width = _shape.getAnchor().getWidth() - - _shape.getMarginLeft() - _shape.getMarginRight() - getLeftMargin(); + _shape.getLeftInset() - _shape.getRightInset() - getLeftMargin(); } return width; } @@ -700,7 +731,13 @@ public class XSLFTextParagraph implements Iterable{ } int level = getLevel(); - XmlObject[] o = _shape.getSheet().getSlideMaster().getXmlObject().selectPath( + + XSLFSheet masterSheet = _shape.getSheet(); + while (masterSheet.getMasterSheet() != null){ + masterSheet = masterSheet.getMasterSheet(); + } + + XmlObject[] o = masterSheet.getXmlObject().selectPath( "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' " + "declare namespace a='http://schemas.openxmlformats.org/drawingml/2006/main' " + ".//p:txStyles/p:" + defaultStyleSelector +"/a:lvl" +(level+1)+ "pPr"); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java index e4ebf9db58..b4aa3ca8bf 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java @@ -20,14 +20,17 @@ import org.apache.poi.util.Beta; import org.apache.poi.xslf.model.CharacterPropertyFetcher; import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor; +import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; +import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties; import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType; -import java.awt.*; +import java.awt.Color; /** * Represents a run of text within the containing text body. The run element is the @@ -70,12 +73,14 @@ public class XSLFTextRun { public Color getFontColor(){ final XSLFTheme theme = _p.getParentShape().getSheet().getTheme(); + CTShapeStyle style = _p.getParentShape().getSpStyle(); + final CTSchemeColor shapeStyle = style == null ? null : style.getFontRef().getSchemeClr(); CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getLevel()){ public boolean fetch(CTTextCharacterProperties props){ CTSolidColorFillProperties solidFill = props.getSolidFill(); - if(solidFill != null){ - Color c = new XSLFColor(solidFill, theme).getColor(); + if(solidFill != null) { + Color c = new XSLFColor(solidFill, theme, shapeStyle).getColor(); setValue(c); return true; } @@ -104,6 +109,10 @@ public class XSLFTextRun { * @return font size in points or -1 if font size is not set. */ public double getFontSize(){ + double scale = 1; + CTTextNormalAutofit afit = getParentParagraph().getParentShape().getTextBodyPr().getNormAutofit(); + if(afit != null) scale = (double)afit.getFontScale() / 100000; + CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getLevel()){ public boolean fetch(CTTextCharacterProperties props){ if(props.isSetSz()){ @@ -114,7 +123,27 @@ public class XSLFTextRun { } }; fetchCharacterProperty(fetcher); - return fetcher.getValue() == null ? -1 : fetcher.getValue(); + return fetcher.getValue() == null ? -1 : fetcher.getValue()*scale; + } + + /** + * + * @return the spacing between characters within a text run, + * If this attribute is omitted than a value of 0 or no adjustment is assumed. + */ + public double getCharacterSpacing(){ + + CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getLevel()){ + public boolean fetch(CTTextCharacterProperties props){ + if(props.isSetSpc()){ + setValue(props.getSpc()*0.01); + return true; + } + return false; + } + }; + fetchCharacterProperty(fetcher); + return fetcher.getValue() == null ? 0 : fetcher.getValue(); } /** @@ -234,6 +263,24 @@ public class XSLFTextRun { return fetcher.getValue() == null ? false : fetcher.getValue(); } + /** + * @return whether a run of text will be formatted as a superscript text. Default is false. + */ + public TextCap getTextCap() { + CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_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 * diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java index 279cac9198..dd49c316a0 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java @@ -30,12 +30,16 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType; +import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps; import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; +import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; +import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; -import java.awt.*; +import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; /** @@ -44,7 +48,7 @@ import java.util.List; * @author Yegor Kozlov */ @Beta -public abstract class XSLFTextShape extends XSLFSimpleShape { +public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable{ private final List _paragraphs; /*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) { @@ -59,7 +63,14 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { } } - // textual properties + public Iterator iterator(){ + return _paragraphs.iterator(); + } + + /** + * + * @return text contained within this shape or empty string + */ public String getText() { StringBuilder out = new StringBuilder(); for (XSLFTextParagraph p : _paragraphs) { @@ -69,10 +80,34 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { return out.toString(); } + /** + * unset text from this shape + */ + public void clearText(){ + _paragraphs.clear(); + CTTextBody txBody = getTextBody(true); + txBody.setPArray(null); // remove any existing paragraphs + } + + public void setText(String text){ + clearText(); + + addNewTextParagraph().addNewTextRun().setText(text); + } + + /** + * + * @return text paragraphs in this shape + */ public List getTextParagraphs() { return _paragraphs; } + /** + * add a new paragraph run to this shape + * + * @return created paragraph run + */ public XSLFTextParagraph addNewTextParagraph() { CTTextBody txBody = getTextBody(true); CTTextParagraph p = txBody.addNewP(); @@ -84,9 +119,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { /** * Sets the type of vertical alignment for the text. - * One of the Anchor* 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 null values unsets this property. */ public void setVerticalAlignment(VerticalAlignment anchor){ CTTextBodyProperties bodyPr = getTextBodyPr(); @@ -102,7 +137,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { /** * Returns the type of vertical alignment for the text. * - * @return the type of alignment + * @return the type of vertical alignment */ public VerticalAlignment getVerticalAlignment(){ PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ @@ -147,13 +182,15 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { } return TextDirection.HORIZONTAL; } + + /** * Returns the distance (in points) between the bottom of the text frame * and the bottom of the inscribed rectangle of the shape that contains the text. * - * @return the bottom margin or -1 if not set + * @return the bottom inset in points */ - public double getMarginBottom(){ + public double getBottomInset(){ PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ public boolean fetch(CTTextBodyProperties props){ if(props.isSetBIns()){ @@ -173,9 +210,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { * and the left edge of the inscribed rectangle of the shape that contains * the text. * - * @return the left margin + * @return the left inset in points */ - public double getMarginLeft(){ + public double getLeftInset(){ PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ public boolean fetch(CTTextBodyProperties props){ if(props.isSetLIns()){ @@ -195,9 +232,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { * text frame and the right edge of the inscribed rectangle of the shape * that contains the text. * - * @return the right margin + * @return the right inset in points */ - public double getMarginRight(){ + public double getRightInset(){ PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ public boolean fetch(CTTextBodyProperties props){ if(props.isSetRIns()){ @@ -216,9 +253,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { * Returns the distance (in points) between the top of the text frame * and the top of the inscribed rectangle of the shape that contains the text. * - * @return the top margin + * @return the top inset in points */ - public double getMarginTop(){ + public double getTopInset(){ PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ public boolean fetch(CTTextBodyProperties props){ if(props.isSetTIns()){ @@ -235,11 +272,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { /** * Sets the botom margin. - * @see #getMarginBottom() + * @see #getBottomInset() * * @param margin the bottom margin */ - public void setMarginBottom(double margin){ + public void setBottomInset(double margin){ CTTextBodyProperties bodyPr = getTextBodyPr(); if (bodyPr != null) { if(margin == -1) bodyPr.unsetBIns(); @@ -249,11 +286,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { /** * Sets the left margin. - * @see #getMarginLeft() + * @see #getLeftInset() * * @param margin the left margin */ - public void setMarginLeft(double margin){ + public void setLeftInset(double margin){ CTTextBodyProperties bodyPr = getTextBodyPr(); if (bodyPr != null) { if(margin == -1) bodyPr.unsetLIns(); @@ -263,11 +300,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { /** * Sets the right margin. - * @see #getMarginRight() + * @see #getRightInset() * * @param margin the right margin */ - public void setMarginRight(double margin){ + public void setRightInset(double margin){ CTTextBodyProperties bodyPr = getTextBodyPr(); if (bodyPr != null) { if(margin == -1) bodyPr.unsetRIns(); @@ -277,11 +314,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { /** * Sets the top margin. - * @see #getMarginTop() + * @see #getTopInset() * * @param margin the top margin */ - public void setMarginTop(double margin){ + public void setTopInset(double margin){ CTTextBodyProperties bodyPr = getTextBodyPr(); if (bodyPr != null) { if(margin == -1) bodyPr.unsetTIns(); @@ -291,10 +328,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { /** - * Returns the value indicating word wrap. - * One of the Wrap* constants defined in this class. - * - * @return the value indicating word wrap + * @return whether to wrap words within the bounding rectangle */ public boolean getWordWrap(){ PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ @@ -311,9 +345,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { } /** - * Specifies how the text should be wrapped * - * @param wrap the value indicating how the text should be wrapped + * @param wrap whether to wrap words within the bounding rectangle */ public void setWordWrap(boolean wrap){ CTTextBodyProperties bodyPr = getTextBodyPr(); @@ -381,33 +414,25 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { } } - @Override - public void draw(Graphics2D graphics){ - java.awt.Shape outline = getOutline(); - - // shadow - XSLFShadow shadow = getShadow(); - - Paint fill = getFill(graphics); - Paint line = getLinePaint(graphics); - if(shadow != null) { - shadow.draw(graphics); - } - - 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 @@ -418,15 +443,19 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { return drawParagraphs(img.createGraphics(), 0, 0); } - void breakText(Graphics2D graphics){ + /** + * break the contained text into lines + */ + private void breakText(Graphics2D graphics){ for(XSLFTextParagraph p : _paragraphs) p.breakText(graphics); } - public void drawText(Graphics2D graphics) { + @Override + public void drawContent(Graphics2D graphics) { breakText(graphics); Rectangle2D anchor = getAnchor(); - double x = anchor.getX() + getMarginLeft(); + double x = anchor.getX() + getLeftInset(); double y = anchor.getY(); // first dry-run to calculate the total height of the text @@ -434,21 +463,20 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { switch (getVerticalAlignment()){ case TOP: - y += getMarginTop(); + y += getTopInset(); break; case BOTTOM: - y += anchor.getHeight() - textHeight - getMarginBottom(); + y += anchor.getHeight() - textHeight - getBottomInset(); break; default: case MIDDLE: double delta = anchor.getHeight() - textHeight - - getMarginTop() - getMarginBottom(); - y += getMarginTop() + delta/2; + getTopInset() - getBottomInset(); + y += getTopInset() + delta/2; break; } drawParagraphs(graphics, x, y); - } @@ -461,7 +489,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape { double y0 = y; for(int i = 0; i < _paragraphs.size(); i++){ XSLFTextParagraph p = _paragraphs.get(i); - java.util.List lines = p.getTextLines(); + List lines = p.getTextLines(); if(i > 0 && lines.size() > 0) { // the amount of vertical white space before the paragraph diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java index 77dd0a8564..b996dd5fb4 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java @@ -26,6 +26,7 @@ import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles; import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; +import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; import org.openxmlformats.schemas.drawingml.x2006.main.CTColorScheme; import org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeStyleSheet; import org.openxmlformats.schemas.drawingml.x2006.main.ThemeDocument; @@ -36,6 +37,11 @@ import java.io.OutputStream; import java.util.HashMap; import java.util.Map; +/** + * A shared style sheet in a .pptx slide show + * + * @author Yegor Kozlov + */ @Beta public class XSLFTheme extends POIXMLDocumentPart { private CTOfficeStyleSheet _theme; @@ -64,17 +70,33 @@ public class XSLFTheme extends POIXMLDocumentPart { String name = c.getDomNode().getLocalName(); _schemeColors.put(name, c); } + } - _schemeColors.put("bg1", _schemeColors.get("lt1")); - _schemeColors.put("bg2", _schemeColors.get("lt2")); - _schemeColors.put("tx1", _schemeColors.get("dk1")); - _schemeColors.put("tx2", _schemeColors.get("dk2")); + /** + * re-map colors + * + * @param cmap color map defined in the master slide referencing this theme + */ + void initColorMap(CTColorMapping cmap) { + _schemeColors.put("bg1", _schemeColors.get(cmap.getBg1().toString())); + _schemeColors.put("bg2", _schemeColors.get(cmap.getBg2().toString())); + _schemeColors.put("tx1", _schemeColors.get(cmap.getTx1().toString())); + _schemeColors.put("tx2", _schemeColors.get(cmap.getTx2().toString())); } + /** + * + * @return name of this theme, e.g. "Office Theme" + */ public String getName(){ return _theme.getName(); } + /** + * Set name of this theme + * + * @param name name of this theme + */ public void setName(String name){ _theme.setName(name); } @@ -111,10 +133,20 @@ public class XSLFTheme extends POIXMLDocumentPart { out.close(); } + /** + * @return typeface of the major font to use in a document. + * Typically the major font is used for heading areas of a document. + * + */ public String getMajorFont(){ return _theme.getThemeElements().getFontScheme().getMajorFont().getLatin().getTypeface(); } + /** + * @return typeface of the minor font to use in a document. + * Typically the monor font is used for normal text or paragraph areas. + * + */ public String getMinorFont(){ return _theme.getThemeElements().getFontScheme().getMinorFont().getLatin().getTypeface(); } diff --git a/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java b/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java index f4e6955e6a..76bb08559f 100644 --- a/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java +++ b/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java @@ -28,21 +28,26 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; -import java.io.File; import java.io.FileOutputStream; /** - * Date: 10/11/11 + * An utulity to convert slides of a .pptx slide show to a PNG image * * @author Yegor Kozlov */ public class PPTX2PNG { + + static void usage(){ + System.out.println("Usage: PPTX2PNG [options] "); + System.out.println("Options:"); + System.out.println(" -scale scale factor"); + System.out.println(" -slide 1-based index of a slide to render"); + } + public static void main(String[] args) throws Exception { if (args.length == 0) { - System.out.println("Usage: PPTX2PNG [options] "); + usage(); return; } @@ -62,6 +67,11 @@ public class PPTX2PNG { } } + if(file == null){ + usage(); + return; + } + System.out.println("Processing " + file); XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file)); @@ -79,19 +89,23 @@ public class PPTX2PNG { BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D graphics = img.createGraphics(); + // default rendering options graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); - graphics.setPaint(Color.white); - graphics.fill(new Rectangle2D.Float(0, 0, width, height)); + graphics.setColor(Color.white); + graphics.clearRect(0, 0, width, height); - graphics.scale((double) width / pgsize.width, (double) height / pgsize.height); + graphics.scale(scale, scale); + // draw stuff slide[i].draw(graphics); - String fname = file.replaceAll("\\.pptx", "-" + (i + 1) + ".png"); + // save the result + int sep = file.lastIndexOf("."); + String fname = file.substring(0, sep == -1 ? file.length() : sep) + "-" + (i + 1) +".png"; FileOutputStream out = new FileOutputStream(fname); ImageIO.write(img, "png", out); out.close(); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java index b9f15139d5..df3e2ec29d 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java @@ -24,7 +24,7 @@ public class TestFormulaParser extends TestCase { }; CustomGeometry geom = new CustomGeometry(CTCustomGeometry2D.Factory.newInstance()); - Context ctx = new Context(geom, null); + Context ctx = new Context(geom, null, null); for(Formula fmla : ops) { ctx.evaluate(fmla); } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java index 5c19b4e53e..c71a065bb7 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java @@ -21,11 +21,7 @@ public class TestPresetGeometries extends TestCase { for(String name : shapes.keySet()) { CustomGeometry geom = shapes.get(name); - Context ctx = new Context(geom, new IAdjustableShape() { - public Rectangle2D getAnchor() { - return new Rectangle2D.Double(0, 0, 100, 100); - } - + Context ctx = new Context(geom, new Rectangle2D.Double(0, 0, 100, 100), new IAdjustableShape() { public Guide getAdjustValue(String name) { return null; } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java index 1f8826fdad..948b792b8b 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java @@ -34,7 +34,7 @@ import java.awt.image.BufferedImage; public class TestPPTX2PNG extends TestCase { public void testRender(){ String[] testFiles = {"layouts.pptx", "sample.pptx", "shapes.pptx", - "45541_Header.pptx", "backgrounds.pptx"}; + "themes.pptx", "backgrounds.pptx"}; for(String sampleFile : testFiles){ XMLSlideShow pptx = XSLFTestDataSamples.openSampleDocument(sampleFile); Dimension pg = pptx.getPageSize(); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java index 7cab8ea4e3..d29cb30662 100755 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java @@ -34,38 +34,38 @@ public class TestXSLFAutoShape extends TestCase { shape.addNewTextParagraph().addNewTextRun().setText("POI"); // default margins from slide master - assertEquals(3.6, shape.getMarginBottom()); - assertEquals(3.6, shape.getMarginTop()); - assertEquals(7.2, shape.getMarginLeft()); - assertEquals(7.2, shape.getMarginRight()); - - 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 - shape.setMarginBottom(-1); - assertEquals(3.6, shape.getMarginBottom()); - shape.setMarginTop(-1); - assertEquals(3.6, shape.getMarginTop()); - shape.setMarginLeft(-1); - assertEquals(7.2, shape.getMarginLeft()); - shape.setMarginRight(-1); - assertEquals(7.2, shape.getMarginRight()); + shape.setBottomInset(-1); + assertEquals(3.6, shape.getBottomInset()); + shape.setTopInset(-1); + assertEquals(3.6, shape.getTopInset()); + shape.setLeftInset(-1); + assertEquals(7.2, shape.getLeftInset()); + shape.setRightInset(-1); + assertEquals(7.2, shape.getRightInset()); // shape assertTrue(shape.getWordWrap()); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java index ffb25b37e1..108fca327b 100755 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java @@ -37,7 +37,7 @@ public class TestXSLFColor extends TestCase { CTSRgbColor c = xml.addNewSrgbClr(); c.setVal(new byte[]{(byte)0xFF, 0, 0}); - XSLFColor color = new XSLFColor(xml, null); + XSLFColor color = new XSLFColor(xml, null, null); assertEquals(-1, color.getAlpha()); c.addNewAlpha().setVal(50000); @@ -99,7 +99,7 @@ public class TestXSLFColor extends TestCase { c.setSat2(100000); c.setLum2(50000); - XSLFColor color = new XSLFColor(xml, null); + XSLFColor color = new XSLFColor(xml, null, null); assertEquals(new Color(128, 00, 00), color.getColor()); } @@ -107,7 +107,7 @@ public class TestXSLFColor extends TestCase { CTColor xml = CTColor.Factory.newInstance(); xml.addNewSrgbClr().setVal(new byte[]{ (byte)0xFF, (byte)0xFF, 0}); - XSLFColor color = new XSLFColor(xml, null); + XSLFColor color = new XSLFColor(xml, null, null); assertEquals(new Color(0xFF, 0xFF, 0), color.getColor()); } @@ -118,19 +118,19 @@ public class TestXSLFColor extends TestCase { CTColor xml = CTColor.Factory.newInstance(); xml.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_2); - XSLFColor color = new XSLFColor(xml, theme); + XSLFColor color = new XSLFColor(xml, theme, null); // accent2 is theme1.xml is assertEquals(Color.decode("0xC0504D"), color.getColor()); xml = CTColor.Factory.newInstance(); xml.addNewSchemeClr().setVal(STSchemeColorVal.LT_1); - color = new XSLFColor(xml, theme); + color = new XSLFColor(xml, theme, null); // assertEquals(Color.decode("0xFFFFFF"), color.getColor()); xml = CTColor.Factory.newInstance(); xml.addNewSchemeClr().setVal(STSchemeColorVal.DK_1); - color = new XSLFColor(xml, theme); + color = new XSLFColor(xml, theme, null); // assertEquals(Color.decode("0x000000"), color.getColor()); } @@ -138,7 +138,7 @@ public class TestXSLFColor extends TestCase { public void testPresetColor() { CTColor xml = CTColor.Factory.newInstance(); xml.addNewPrstClr().setVal(STPresetColorVal.AQUAMARINE); - XSLFColor color = new XSLFColor(xml, null); + XSLFColor color = new XSLFColor(xml, null, null); assertEquals(new Color(127, 255, 212), color.getColor()); @@ -147,7 +147,7 @@ public class TestXSLFColor extends TestCase { STPresetColorVal.Enum val = STPresetColorVal.Enum.forString(colorName); assertNotNull(colorName, val); xml.addNewPrstClr().setVal(val); - color = new XSLFColor(xml, null); + color = new XSLFColor(xml, null, null); assertEquals(XSLFColor.presetColors.get(colorName), color.getColor()); } } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java index 9ffe69fe98..d8cb5783e4 100755 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java @@ -19,9 +19,6 @@ package org.apache.poi.xslf.usermodel; import junit.framework.TestCase; import org.apache.poi.xslf.XSLFTestDataSamples; -import org.apache.poi.POIXMLDocumentPart; - -import java.util.List; /** * @author Yegor Kozlov @@ -99,11 +96,11 @@ public class TestXSLFSlide extends TestCase { assertEquals(0, ppt.getSlides().length); XSLFSlide slide = ppt.createSlide(); - assertTrue(slide.getFollowMasterBackground()); - slide.setFollowMasterBackground(false); - assertFalse(slide.getFollowMasterBackground()); - slide.setFollowMasterBackground(true); - assertTrue(slide.getFollowMasterBackground()); + assertTrue(slide.getFollowMasterGraphics()); + slide.setFollowMasterGraphics(false); + assertFalse(slide.getFollowMasterGraphics()); + slide.setFollowMasterGraphics(true); + assertTrue(slide.getFollowMasterGraphics()); } } \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java index c07493a3f9..46e10e45d8 100755 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java @@ -38,7 +38,7 @@ public class TestXSLFSlideShow extends TestCase { List rels = slide1.getRelations(); assertEquals(1, rels.size()); - assertEquals(slide1.getMasterSheet().getLayout("blank"), rels.get(0)); + assertEquals(slide1.getSlideMaster().getLayout(SlideLayout.BLANK), rels.get(0)); XSLFSlide slide2 = ppt.createSlide(); assertEquals(2, ppt.getSlides().length); @@ -91,7 +91,7 @@ public class TestXSLFSlideShow extends TestCase { assertEquals(1, masters.length); XSLFSlide slide = ppt.createSlide(); - assertSame(masters[0], slide.getMasterSheet()); + assertSame(masters[0], slide.getSlideMaster()); } public void testSlideLayout(){ diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java index 7524b25292..6347b63ccf 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java @@ -65,10 +65,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getMarginLeft()); // 0.1" - assertEquals(7.2, shape1.getMarginRight()); // 0.1" - assertEquals(3.6, shape1.getMarginTop()); // 0.05" - assertEquals(3.6, shape1.getMarginBottom()); // 0.05" + assertEquals(7.2, shape1.getLeftInset()); // 0.1" + assertEquals(7.2, shape1.getRightInset()); // 0.1" + assertEquals(3.6, shape1.getTopInset()); // 0.05" + assertEquals(3.6, shape1.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); // now check text properties @@ -95,10 +95,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getMarginLeft()); // 0.1" - assertEquals(7.2, shape2.getMarginRight()); // 0.1" - assertEquals(3.6, shape2.getMarginTop()); // 0.05" - assertEquals(3.6, shape2.getMarginBottom()); // 0.05" + assertEquals(7.2, shape2.getLeftInset()); // 0.1" + assertEquals(7.2, shape2.getRightInset()); // 0.1" + assertEquals(3.6, shape2.getTopInset()); // 0.05" + assertEquals(3.6, shape2.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); assertEquals("subtitle", shape2.getText()); @@ -134,10 +134,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getMarginLeft()); // 0.1" - assertEquals(7.2, shape1.getMarginRight()); // 0.1" - assertEquals(3.6, shape1.getMarginTop()); // 0.05" - assertEquals(3.6, shape1.getMarginBottom()); // 0.05" + assertEquals(7.2, shape1.getLeftInset()); // 0.1" + assertEquals(7.2, shape1.getRightInset()); // 0.1" + assertEquals(3.6, shape1.getTopInset()); // 0.05" + assertEquals(3.6, shape1.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); // now check text properties @@ -169,10 +169,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getMarginLeft()); // 0.1" - assertEquals(7.2, shape2.getMarginRight()); // 0.1" - assertEquals(3.6, shape2.getMarginTop()); // 0.05" - assertEquals(3.6, shape2.getMarginBottom()); // 0.05" + assertEquals(7.2, shape2.getLeftInset()); // 0.1" + assertEquals(7.2, shape2.getRightInset()); // 0.1" + assertEquals(3.6, shape2.getTopInset()); // 0.05" + assertEquals(3.6, shape2.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); @@ -244,10 +244,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getMarginLeft()); // 0.1" - assertEquals(7.2, shape1.getMarginRight()); // 0.1" - assertEquals(3.6, shape1.getMarginTop()); // 0.05" - assertEquals(3.6, shape1.getMarginBottom()); // 0.05" + assertEquals(7.2, shape1.getLeftInset()); // 0.1" + assertEquals(7.2, shape1.getRightInset()); // 0.1" + assertEquals(3.6, shape1.getTopInset()); // 0.05" + assertEquals(3.6, shape1.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.TOP, shape1.getVerticalAlignment()); // now check text properties @@ -278,10 +278,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getMarginLeft()); // 0.1" - assertEquals(7.2, shape2.getMarginRight()); // 0.1" - assertEquals(3.6, shape2.getMarginTop()); // 0.05" - assertEquals(3.6, shape2.getMarginBottom()); // 0.05" + assertEquals(7.2, shape2.getLeftInset()); // 0.1" + assertEquals(7.2, shape2.getRightInset()); // 0.1" + assertEquals(3.6, shape2.getTopInset()); // 0.05" + assertEquals(3.6, shape2.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.BOTTOM, shape2.getVerticalAlignment()); assertEquals("Section Header", shape2.getText()); @@ -318,10 +318,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getMarginLeft()); // 0.1" - assertEquals(7.2, shape1.getMarginRight()); // 0.1" - assertEquals(3.6, shape1.getMarginTop()); // 0.05" - assertEquals(3.6, shape1.getMarginBottom()); // 0.05" + assertEquals(7.2, shape1.getLeftInset()); // 0.1" + assertEquals(7.2, shape1.getRightInset()); // 0.1" + assertEquals(3.6, shape1.getTopInset()); // 0.05" + assertEquals(3.6, shape1.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); // now check text properties @@ -351,10 +351,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getMarginLeft()); // 0.1" - assertEquals(7.2, shape2.getMarginRight()); // 0.1" - assertEquals(3.6, shape2.getMarginTop()); // 0.05" - assertEquals(3.6, shape2.getMarginBottom()); // 0.05" + assertEquals(7.2, shape2.getLeftInset()); // 0.1" + assertEquals(7.2, shape2.getRightInset()); // 0.1" + assertEquals(3.6, shape2.getTopInset()); // 0.05" + assertEquals(3.6, shape2.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); @@ -425,10 +425,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getMarginLeft()); // 0.1" - assertEquals(7.2, shape1.getMarginRight()); // 0.1" - assertEquals(3.6, shape1.getMarginTop()); // 0.05" - assertEquals(3.6, shape1.getMarginBottom()); // 0.05" + assertEquals(7.2, shape1.getLeftInset()); // 0.1" + assertEquals(7.2, shape1.getRightInset()); // 0.1" + assertEquals(3.6, shape1.getTopInset()); // 0.05" + assertEquals(3.6, shape1.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); // now check text properties @@ -449,10 +449,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getMarginLeft()); // 0.1" - assertEquals(7.2, shape2.getMarginRight()); // 0.1" - assertEquals(3.6, shape2.getMarginTop()); // 0.05" - assertEquals(3.6, shape2.getMarginBottom()); // 0.05" + assertEquals(7.2, shape2.getLeftInset()); // 0.1" + assertEquals(7.2, shape2.getRightInset()); // 0.1" + assertEquals(3.6, shape2.getTopInset()); // 0.05" + assertEquals(3.6, shape2.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); @@ -498,10 +498,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getMarginLeft()); // 0.1" - assertEquals(7.2, shape1.getMarginRight()); // 0.1" - assertEquals(3.6, shape1.getMarginTop()); // 0.05" - assertEquals(3.6, shape1.getMarginBottom()); // 0.05" + assertEquals(7.2, shape1.getLeftInset()); // 0.1" + assertEquals(7.2, shape1.getRightInset()); // 0.1" + assertEquals(3.6, shape1.getTopInset()); // 0.05" + assertEquals(3.6, shape1.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.BOTTOM, shape1.getVerticalAlignment()); // now check text properties @@ -532,10 +532,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getMarginLeft()); // 0.1" - assertEquals(7.2, shape2.getMarginRight()); // 0.1" - assertEquals(3.6, shape2.getMarginTop()); // 0.05" - assertEquals(3.6, shape2.getMarginBottom()); // 0.05" + assertEquals(7.2, shape2.getLeftInset()); // 0.1" + assertEquals(7.2, shape2.getRightInset()); // 0.1" + assertEquals(3.6, shape2.getTopInset()); // 0.05" + assertEquals(3.6, shape2.getBottomInset()); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java index 81f35d3250..b01c25e1d5 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java @@ -18,22 +18,141 @@ package org.apache.poi.xslf.usermodel; import junit.framework.TestCase; + import org.apache.poi.xslf.XSLFTestDataSamples; +import java.awt.Color; +import java.awt.TexturePaint; + /** - * test common properties for sheets (slides, masters, layouts, etc.) + * test reading properties from a multi-theme and multi-master document * * @author Yegor Kozlov */ public class TestXSLFTheme extends TestCase { public void testRead(){ - XMLSlideShow ppt = new XMLSlideShow(); - XSLFSlide slide = ppt.createSlide(); - XSLFTheme theme = slide.getSlideLayout().getSlideMaster().getTheme(); - assertNotNull(theme); - + XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("themes.pptx"); + XSLFSlide[] slides = ppt.getSlides(); + + slide1(slides[0]); + slide2(slides[1]); + slide3(slides[2]); + slide4(slides[3]); + slide5(slides[4]); + slide6(slides[5]); + slide7(slides[6]); + slide8(slides[7]); + slide9(slides[8]); + slide10(slides[9]); + } + + private XSLFShape getShape(XSLFSheet sheet, String name){ + for(XSLFShape sh : sheet.getShapes()){ + if(sh.getShapeName().equals(name)) return sh; + } + throw new IllegalArgumentException("Shape not found: " + name); + } + + void slide1(XSLFSlide slide){ + assertEquals(Color.white, slide.getBackground().getFillColor()); + + XSLFTheme theme = slide.getTheme(); assertEquals("Office Theme", theme.getName()); - //XSLFColor accent1 = theme.getColor("accent1"); - //assertNotNull(accent1); + + XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 3"); + RenderableShape rsh1 = new RenderableShape(sh1); + XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(Color.white, run1.getFontColor()); + assertEquals(new Color(79, 129, 189), sh1.getFillColor()); + assertTrue(rsh1.getFillPaint(null) instanceof Color) ; // solid fill + + } + + void slide2(XSLFSlide slide){ + // Background 2, darker 10% + // YK: PPT shows slightly different color: new Color(221, 217, 195) + assertEquals(new Color(214, 212, 203), slide.getBackground().getFillColor()); + } + + void slide3(XSLFSlide slide){ + assertNull(slide.getBackground().getFillColor()); + assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0); + } + + void slide4(XSLFSlide slide){ + assertNull(slide.getBackground().getFillColor()); + assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0); + + XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 4"); + RenderableShape rsh1 = new RenderableShape(sh1); + XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(Color.white, run1.getFontColor()); + assertEquals(new Color(148, 198, 0), sh1.getFillColor()); + assertTrue(rsh1.getFillPaint(null) instanceof Color) ; // solid fill + + XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 3"); + XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(new Color(148, 198, 0), run2.getFontColor()); + assertNull(sh2.getFillColor()); // no fill + + assertTrue(slide.getSlideLayout().getFollowMasterGraphics()); + } + + void slide5(XSLFSlide slide){ + assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint); + + XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 1"); + XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(new Color(148, 198, 0), run2.getFontColor()); + assertNull(sh2.getFillColor()); // no fill + // font size is 40pt and scale factor is 90% + assertEquals(36.0, run2.getFontSize()); + + assertTrue(slide.getSlideLayout().getFollowMasterGraphics()); + } + + void slide6(XSLFSlide slide){ + + XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Subtitle 3"); + XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(new Color(66, 66, 66), run1.getFontColor()); + assertNull(sh1.getFillColor()); // no fill + + XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 2"); + XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(new Color(148, 198, 0), run2.getFontColor()); + assertNull(sh2.getFillColor()); // no fill + + assertFalse(slide.getSlideLayout().getFollowMasterGraphics()); + } + + void slide7(XSLFSlide slide){ + + //YK: PPT reports a slightly different color: r=189,g=239,b=87 + assertEquals(new Color(182, 218, 108), slide.getBackground().getFillColor()); + + assertFalse(slide.getFollowMasterGraphics()); + } + + void slide8(XSLFSlide slide){ + assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint); + } + + void slide9(XSLFSlide slide){ + assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint); + } + + void slide10(XSLFSlide slide){ + assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0); + + XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Title 3"); + XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(Color.white, run1.getFontColor()); + assertNull(sh1.getFillColor()); // no fill + + XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Subtitle 4"); + XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(Color.white, run2.getFontColor()); + assertNull(sh2.getFillColor()); // no fill } } diff --git a/src/resources/ooxml/org/apache/poi/xslf/usermodel/empty.pptx b/src/resources/ooxml/org/apache/poi/xslf/usermodel/empty.pptx new file mode 100755 index 0000000000..eea1e064e9 Binary files /dev/null and b/src/resources/ooxml/org/apache/poi/xslf/usermodel/empty.pptx differ diff --git a/src/resources/ooxml/org/apache/poi/xslf/usermodel/presetShapeDefinitions.xml b/src/resources/ooxml/org/apache/poi/xslf/usermodel/presetShapeDefinitions.xml new file mode 100755 index 0000000000..f5fead717f --- /dev/null +++ b/src/resources/ooxml/org/apache/poi/xslf/usermodel/presetShapeDefinitions.xml @@ -0,0 +1,19915 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/resources/scratchpad/org/apache/poi/xslf/usermodel/empty.pptx b/src/resources/scratchpad/org/apache/poi/xslf/usermodel/empty.pptx deleted file mode 100755 index eea1e064e9..0000000000 Binary files a/src/resources/scratchpad/org/apache/poi/xslf/usermodel/empty.pptx and /dev/null differ diff --git a/src/resources/scratchpad/org/apache/poi/xslf/usermodel/presetShapeDefinitions.xml b/src/resources/scratchpad/org/apache/poi/xslf/usermodel/presetShapeDefinitions.xml deleted file mode 100755 index f5fead717f..0000000000 --- a/src/resources/scratchpad/org/apache/poi/xslf/usermodel/presetShapeDefinitions.xml +++ /dev/null @@ -1,19915 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test-data/slideshow/pptx2svg.pptx b/test-data/slideshow/pptx2svg.pptx new file mode 100644 index 0000000000..2f9a3515cb Binary files /dev/null and b/test-data/slideshow/pptx2svg.pptx differ diff --git a/test-data/slideshow/pptx2svg.svg b/test-data/slideshow/pptx2svg.svg new file mode 100644 index 0000000000..9ea3636916 --- /dev/null +++ b/test-data/slideshow/pptx2svg.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + +Paragraphs and Rich Formatting + + +✭ +The Paragraphs and Rich Formatting portion of the DrawingML framework stores text +and related formatting information for a text body contained within a shape. +Formatting for text within a shape can be broken down into three levels of precision, +namely body, paragraph, and run formatting properties. +✭ +Body Formatting +✭ + + +Being the highest level of formatting available within a shape, the body properties allow for the +manipulation of the text area as a whole. This means that all paragraphs and runs of text for the shape +in question would be encompassed within here and, therefore, follow the text body style defined here. + + +✭ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +POI + + + + + + + + + + + + + + + + + + + + + diff --git a/test-data/slideshow/themes.pptx b/test-data/slideshow/themes.pptx new file mode 100755 index 0000000000..ff39de3ed4 Binary files /dev/null and b/test-data/slideshow/themes.pptx differ