|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- /*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- */
-
- package org.apache.poi.xslf.usermodel;
-
- import java.awt.Graphics2D;
- import java.awt.geom.Rectangle2D;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.Arrays;
- import java.util.Comparator;
-
- import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
- import org.apache.poi.openxml4j.opc.PackagePart;
- import org.apache.poi.openxml4j.opc.PackageRelationship;
- import org.apache.poi.sl.draw.DrawFactory;
- import org.apache.poi.sl.draw.DrawPaint;
- import org.apache.poi.sl.usermodel.ColorStyle;
- import org.apache.poi.sl.usermodel.MasterSheet;
- import org.apache.poi.sl.usermodel.PaintStyle;
- import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
- import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
- import org.apache.poi.sl.usermodel.PlaceableShape;
- import org.apache.poi.sl.usermodel.Placeholder;
- import org.apache.poi.sl.usermodel.PlaceholderDetails;
- import org.apache.poi.sl.usermodel.Shape;
- import org.apache.poi.sl.usermodel.SimpleShape;
- import org.apache.poi.util.Beta;
- import org.apache.poi.util.Internal;
- import org.apache.poi.xslf.model.PropertyFetcher;
- import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
- import org.apache.xmlbeans.XmlCursor;
- 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.CTGradientFillProperties;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientStop;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
- import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
- import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
- import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
- import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
- import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
-
- /**
- * Base super-class class for all shapes in PresentationML
- */
- @Beta
- public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
- static final String PML_NS = "http://schemas.openxmlformats.org/presentationml/2006/main";
-
- private final XmlObject _shape;
- private final XSLFSheet _sheet;
- private XSLFShapeContainer _parent;
-
- private CTShapeStyle _spStyle;
- private CTNonVisualDrawingProps _nvPr;
-
- protected XSLFShape(XmlObject shape, XSLFSheet sheet) {
- _shape = shape;
- _sheet = sheet;
- }
-
- /**
- * @return the xml bean holding this shape's data
- */
- public final XmlObject getXmlObject() {
- // it's final because the xslf inheritance hierarchy is not necessary the same as
- // the (not existing) xmlbeans hierarchy and subclasses shouldn't narrow it's return value
- return _shape;
- }
-
- public XSLFSheet getSheet() {
- return _sheet;
- }
-
- /**
- * @return human-readable name of this shape, e.g. "Rectange 3"
- */
- public String getShapeName(){
- return getCNvPr().getName();
- }
-
- /**
- * Returns a unique identifier for this shape within the current document.
- * This ID may be used to assist in uniquely identifying this object so that it can
- * be referred to by other parts of the document.
- * <p>
- * If multiple objects within the same document share the same id attribute value,
- * then the document shall be considered non-conformant.
- * </p>
- *
- * @return unique id of this shape
- */
- public int getShapeId() {
- return (int)getCNvPr().getId();
- }
-
- /**
- * Set the contents of this shape to be a copy of the source shape.
- * This method is called recursively for each shape when merging slides
- *
- * @param sh the source shape
- * @see org.apache.poi.xslf.usermodel.XSLFSlide#importContent(XSLFSheet)
- */
- @Internal
- void copy(XSLFShape sh) {
- if (!getClass().isInstance(sh)) {
- throw new IllegalArgumentException(
- "Can't copy " + sh.getClass().getSimpleName() + " into " + getClass().getSimpleName());
- }
-
- if (this instanceof PlaceableShape) {
- PlaceableShape<?,?> ps = (PlaceableShape<?,?>)this;
- ps.setAnchor(sh.getAnchor());
- }
-
-
- }
-
- public void setParent(XSLFShapeContainer parent) {
- this._parent = parent;
- }
-
- public XSLFShapeContainer getParent() {
- return this._parent;
- }
-
- protected PaintStyle getFillPaint() {
- final XSLFTheme theme = getSheet().getTheme();
- final boolean hasPlaceholder = getPlaceholder() != null;
- PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
- public boolean fetch(XSLFShape shape) {
- XSLFFillProperties fp = XSLFPropertiesDelegate.getFillDelegate(shape.getShapeProperties());
- if (fp == null) {
- return false;
- }
-
- if (fp.isSetNoFill()) {
- setValue(null);
- return true;
- }
-
- PackagePart pp = shape.getSheet().getPackagePart();
- PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
- if (paint != null) {
- setValue(paint);
- return true;
- }
-
- CTShapeStyle style = shape.getSpStyle();
- if (style != null) {
- fp = XSLFPropertiesDelegate.getFillDelegate(style.getFillRef());
- paint = selectPaint(fp, null, pp, theme, hasPlaceholder);
- }
- if (paint != null) {
- setValue(paint);
- return true;
- }
-
-
- return false;
- }
- };
- fetchShapeProperty(fetcher);
-
- return fetcher.getValue();
- }
-
- protected CTBackgroundProperties getBgPr() {
- return getChild(CTBackgroundProperties.class, PML_NS, "bgPr");
- }
-
- protected CTStyleMatrixReference getBgRef() {
- return getChild(CTStyleMatrixReference.class, PML_NS, "bgRef");
- }
-
- protected CTGroupShapeProperties getGrpSpPr() {
- return getChild(CTGroupShapeProperties.class, PML_NS, "grpSpPr");
- }
-
- protected CTNonVisualDrawingProps getCNvPr() {
- if (_nvPr == null) {
- String xquery = "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:cNvPr";
- _nvPr = selectProperty(CTNonVisualDrawingProps.class, xquery);
- }
- return _nvPr;
- }
-
- protected CTShapeStyle getSpStyle() {
- if (_spStyle == null) {
- _spStyle = getChild(CTShapeStyle.class, PML_NS, "style");
- }
- return _spStyle;
- }
-
- /**
- * Return direct child objects of this shape
- *
- * @param childClass the class to cast the properties to
- * @param namespace the namespace - usually it is {@code "http://schemas.openxmlformats.org/presentationml/2006/main"}
- * @param nodename the node name, without prefix
- * @return the properties object or null if it can't be found
- */
- @SuppressWarnings("unchecked")
- protected <T extends XmlObject> T getChild(Class<T> childClass, String namespace, String nodename) {
- XmlCursor cur = getXmlObject().newCursor();
- T child = null;
- if (cur.toChild(namespace, nodename)) {
- child = (T)cur.getObject();
- }
- if (cur.toChild("http://schemas.openxmlformats.org/drawingml/2006/main", nodename)) {
- child = (T)cur.getObject();
- }
- cur.dispose();
- return child;
- }
-
- public boolean isPlaceholder() {
- return getPlaceholderDetails().getCTPlaceholder(false) != null;
- }
-
- /**
- * @see PlaceholderDetails#getPlaceholder()
- */
- public Placeholder getPlaceholder() {
- return getPlaceholderDetails().getPlaceholder();
- }
-
- /**
- * @see PlaceholderDetails#setPlaceholder(Placeholder)
- */
- public void setPlaceholder(final Placeholder placeholder) {
- getPlaceholderDetails().setPlaceholder(placeholder);
- }
-
- /**
- * @see SimpleShape#getPlaceholderDetails()
- */
- public XSLFPlaceholderDetails getPlaceholderDetails() {
- return new XSLFPlaceholderDetails(this);
- }
-
- /**
- * As there's no xmlbeans hierarchy, but XSLF works with subclassing, not all
- * child classes work with a {@link CTShape} object, but often contain the same
- * properties. This method is the generalized form of selecting and casting those
- * properties.
- *
- * @param resultClass the requested result class
- * @param xquery the simple (xmlbean) xpath expression to the property
- * @return the xml object at the xpath location, or null if not found
- */
- @SuppressWarnings("unchecked")
- protected <T extends XmlObject> T selectProperty(Class<T> resultClass, String xquery) {
- XmlObject[] rs = getXmlObject().selectPath(xquery);
- if (rs.length == 0) return null;
- return (resultClass.isInstance(rs[0])) ? (T)rs[0] : null;
- }
-
- /**
- * Walk up the inheritance tree and fetch shape properties.<p>
- *
- * The following order of inheritance is assumed:<p>
- * <ol>
- * <li>slide
- * <li>slideLayout
- * <li>slideMaster
- * </ol>
- *
- * Currently themes and their defaults aren't correctly handled
- *
- * @param visitor the object that collects the desired property
- * @return true if the property was fetched
- */
- protected boolean fetchShapeProperty(PropertyFetcher<?> visitor) {
- // try shape properties in slide
- if (visitor.fetch(this)) {
- return true;
- }
-
- final CTPlaceholder ph = getPlaceholderDetails().getCTPlaceholder(false);
- if (ph == null) {
- return false;
- }
- MasterSheet<XSLFShape,XSLFTextParagraph> sm = getSheet().getMasterSheet();
-
- // try slide layout
- if (sm instanceof XSLFSlideLayout) {
- XSLFSlideLayout slideLayout = (XSLFSlideLayout)sm;
- XSLFSimpleShape placeholderShape = slideLayout.getPlaceholder(ph);
- if (placeholderShape != null && visitor.fetch(placeholderShape)) {
- return true;
- }
- sm = slideLayout.getMasterSheet();
- }
-
- // try slide master
- if (sm instanceof XSLFSlideMaster) {
- XSLFSlideMaster master = (XSLFSlideMaster)sm;
- int textType = getPlaceholderType(ph);
- XSLFSimpleShape masterShape = master.getPlaceholderByType(textType);
- if (masterShape != null && visitor.fetch(masterShape)) {
- return true;
- }
- }
-
- return false;
- }
-
- private static int getPlaceholderType(CTPlaceholder ph) {
- if ( !ph.isSetType()) {
- return STPlaceholderType.INT_BODY;
- }
-
- switch (ph.getType().intValue()) {
- case STPlaceholderType.INT_TITLE:
- case STPlaceholderType.INT_CTR_TITLE:
- return STPlaceholderType.INT_TITLE;
- case STPlaceholderType.INT_FTR:
- case STPlaceholderType.INT_SLD_NUM:
- case STPlaceholderType.INT_DT:
- return ph.getType().intValue();
- default:
- return STPlaceholderType.INT_BODY;
- }
- }
-
- /**
- * Convert shape fill into java.awt.Paint. The result is either Color or
- * TexturePaint or GradientPaint or null
- *
- * @param fp a properties handler specific to the underlying shape properties
- * @param phClr context color
- * @param parentPart the parent package part. Any external references (images, etc.) are resolved relative to it.
- * @param theme the theme for the shape/sheet
- *
- * @return the applied Paint or null if none was applied
- */
- protected static PaintStyle selectPaint(XSLFFillProperties fp, final CTSchemeColor phClr, final PackagePart parentPart, final XSLFTheme theme, boolean hasPlaceholder) {
- if (fp == null || fp.isSetNoFill()) {
- return null;
- } else if (fp.isSetSolidFill()) {
- return selectPaint(fp.getSolidFill(), phClr, theme);
- } else if (fp.isSetBlipFill()) {
- return selectPaint(fp.getBlipFill(), parentPart);
- } else if (fp.isSetGradFill()) {
- return selectPaint(fp.getGradFill(), phClr, theme);
- } else if (fp.isSetMatrixStyle()) {
- return selectPaint(fp.getMatrixStyle(), theme, fp.isLineStyle(), hasPlaceholder);
- } else {
- return null;
- }
- }
-
- protected static PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr, final XSLFTheme theme) {
- if (solidFill.isSetSchemeClr()) {
- // if there's a reference to the placeholder color,
- // stop evaluating further and let the caller select
- // the next style inheritance level
- // if (STSchemeColorVal.PH_CLR.equals(solidFill.getSchemeClr().getVal())) {
- // return null;
- // }
- if (phClr == null) {
- phClr = solidFill.getSchemeClr();
- }
- }
- final XSLFColor c = new XSLFColor(solidFill, theme, phClr);
- return DrawPaint.createSolidPaint(c.getColorStyle());
- }
-
- protected static PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) {
- final CTBlip blip = blipFill.getBlip();
- return new TexturePaint() {
- private PackagePart getPart() {
- try {
- String blipId = blip.getEmbed();
- PackageRelationship rel = parentPart.getRelationship(blipId);
- return parentPart.getRelatedPart(rel);
- } catch (InvalidFormatException e) {
- throw new RuntimeException(e);
- }
- }
-
- public InputStream getImageData() {
- try {
- return getPart().getInputStream();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- public String getContentType() {
- /* TOOD: map content-type */
- return getPart().getContentType();
- }
-
- public int getAlpha() {
- return (blip.sizeOfAlphaModFixArray() > 0)
- ? blip.getAlphaModFixArray(0).getAmt()
- : 100000;
- }
- };
- }
-
- protected static PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) {
-
- final CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
-
- Arrays.sort(gs, new Comparator<CTGradientStop>() {
- public int compare(CTGradientStop o1, CTGradientStop o2) {
- Integer pos1 = o1.getPos();
- Integer pos2 = o2.getPos();
- return pos1.compareTo(pos2);
- }
- });
-
- final ColorStyle cs[] = new ColorStyle[gs.length];
- final float fractions[] = new float[gs.length];
-
- int i=0;
- for (CTGradientStop cgs : gs) {
- CTSchemeColor phClrCgs = phClr;
- if (phClrCgs == null && cgs.isSetSchemeClr()) {
- phClrCgs = cgs.getSchemeClr();
- }
- cs[i] = new XSLFColor(cgs, theme, phClrCgs).getColorStyle();
- fractions[i] = cgs.getPos() / 100000.f;
- i++;
- }
-
- return new GradientPaint() {
-
- public double getGradientAngle() {
- return (gradFill.isSetLin())
- ? gradFill.getLin().getAng() / 60000.d
- : 0;
- }
-
- public ColorStyle[] getGradientColors() {
- return cs;
- }
-
- public float[] getGradientFractions() {
- return fractions;
- }
-
- public boolean isRotatedWithShape() {
- return gradFill.getRotWithShape();
- }
-
- public GradientType getGradientType() {
- if (gradFill.isSetLin()) {
- return GradientType.linear;
- }
-
- if (gradFill.isSetPath()) {
- /* TODO: handle rect path */
- STPathShadeType.Enum ps = gradFill.getPath().getPath();
- if (ps == STPathShadeType.CIRCLE) {
- return GradientType.circular;
- } else if (ps == STPathShadeType.SHAPE) {
- return GradientType.shape;
- }
- }
-
- return GradientType.linear;
- }
- };
- }
-
- protected static PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme, boolean isLineStyle, boolean hasPlaceholder) {
- if (fillRef == null) return null;
-
- // 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();
- CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme();
- final XmlObject styleLst;
- int childIdx;
- if (idx >= 1 && idx <= 999) {
- childIdx = idx-1;
- styleLst = (isLineStyle) ? matrix.getLnStyleLst() : matrix.getFillStyleLst();
- } else if (idx >= 1001 ){
- childIdx = idx - 1001;
- styleLst = matrix.getBgFillStyleLst();
- } else {
- return null;
- }
- XmlCursor cur = styleLst.newCursor();
- XSLFFillProperties fp = null;
- if (cur.toChild(childIdx)) {
- fp = XSLFPropertiesDelegate.getFillDelegate(cur.getObject());
- }
- cur.dispose();
-
- CTSchemeColor phClr = fillRef.getSchemeClr();
- PaintStyle res = selectPaint(fp, phClr, theme.getPackagePart(), theme, hasPlaceholder);
- // check for empty placeholder value
- // see http://officeopenxml.com/prSlide-color.php - "Color Placeholders within Themes"
- if (res != null || hasPlaceholder) {
- return res;
- }
- XSLFColor col = new XSLFColor(fillRef, theme, phClr);
- return DrawPaint.createSolidPaint(col.getColorStyle());
- }
-
- @Override
- public void draw(Graphics2D graphics, Rectangle2D bounds) {
- DrawFactory.getInstance(graphics).drawShape(graphics, this, bounds);
- }
-
- /**
- * Return the shape specific (visual) properties
- *
- * @return the shape specific properties
- */
- protected XmlObject getShapeProperties() {
- return getChild(CTShapeProperties.class, PML_NS, "spPr");
- }
- }
|