package org.apache.poi.sl.draw;
+import java.awt.AlphaComposite;
+import java.awt.Graphics2D;
import java.awt.PaintContext;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
+import java.awt.TexturePaint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
+import org.apache.poi.sl.usermodel.Insets2D;
import org.apache.poi.sl.usermodel.PaintStyle;
+import org.apache.poi.util.Dimension2DDouble;
/* package */ class DrawTexturePaint extends java.awt.TexturePaint {
private final PaintStyle.TexturePaint fill;
private final double flipX, flipY;
private final boolean isBitmapSrc;
+ private static final Insets2D INSETS_EMPTY = new Insets2D(0,0,0,0);
+
+
DrawTexturePaint(BufferedImage txtr, Shape shape, PaintStyle.TexturePaint fill, double flipX, double flipY, boolean isBitmapSrc) {
// deactivate scaling/translation in super class, by specifying the dimension of the texture
super(txtr, new Rectangle2D.Double(0,0,txtr.getWidth(),txtr.getHeight()));
@Override
public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) {
- final double usr_w, usr_h;
-
+ final Dimension2D userDim = new Dimension2DDouble();
+ final Rectangle2D usedBounds;
if (fill.isRotatedWithShape() || shape == null) {
- usr_w = userBounds.getWidth();
- usr_h = userBounds.getHeight();
-
- xform.translate(userBounds.getX(), userBounds.getY());
+ usedBounds = userBounds;
} else {
AffineTransform transform = new AffineTransform(xform);
// TODO: check if approximation via rotating only the bounds (instead of the shape) is sufficient
transform = AffineTransform.getRotateInstance(rad, userBounds.getCenterX(), userBounds.getCenterY());
- Rectangle2D newBounds = transform.createTransformedShape(shape).getBounds2D();
- usr_w = newBounds.getWidth();
- usr_h = newBounds.getHeight();
+ usedBounds = transform.createTransformedShape(shape).getBounds2D();
+ }
+ userDim.setSize(usedBounds.getWidth(), usedBounds.getHeight());
+ xform.translate(usedBounds.getX(), usedBounds.getY());
+
+ BufferedImage bi = getImage(usedBounds);
+
+ if (fill.getStretch() != null) {
+ TexturePaint tp = new TexturePaint(bi, new Rectangle2D.Double(0, 0, bi.getWidth(), bi.getHeight()));
+ return tp.createContext(cm, deviceBounds, usedBounds, xform, hints);
+ } else if (fill.getScale() != null) {
+ AffineTransform newXform = getTiledInstance(usedBounds, (AffineTransform) xform.clone());
+ TexturePaint tp = new TexturePaint(bi, new Rectangle2D.Double(0, 0, bi.getWidth(), bi.getHeight()));
+ return tp.createContext(cm, deviceBounds, userBounds, newXform, hints);
+ } else {
+ return super.createContext(cm, deviceBounds, userBounds, xform, hints);
+ }
+ }
+
+ public BufferedImage getImage(Rectangle2D userBounds) {
+ BufferedImage bi = super.getImage();
+ final Insets2D insets = fill.getInsets();
+ final Insets2D stretch = fill.getStretch();
- xform.translate(newBounds.getX(), newBounds.getY());
+ if ((insets == null || INSETS_EMPTY.equals(insets)) && (stretch == null)) {
+ return bi;
}
- final Dimension2D scale = fill.getScale();
+ if (insets != null && !INSETS_EMPTY.equals(insets)) {
+ final int width = bi.getWidth();
+ final int height = bi.getHeight();
+
+ bi = bi.getSubimage(
+ (int)(Math.max(insets.left,0)/100_000 * width),
+ (int)(Math.max(insets.top,0)/100_000 * height),
+ (int)((100_000-Math.max(insets.left,0)-Math.max(insets.right,0))/100_000 * width),
+ (int)((100_000-Math.max(insets.top,0)-Math.max(insets.bottom,0))/100_000 * height)
+ );
+
+ int addTop = (int)(Math.max(-insets.top, 0)/100_000 * height);
+ int addLeft = (int)(Math.max(-insets.left, 0)/100_000 * width);
+ int addBottom = (int)(Math.max(-insets.bottom, 0)/100_000 * height);
+ int addRight = (int)(Math.max(-insets.right, 0)/100_000 * width);
+
+ // handle outsets
+ if (addTop > 0 || addLeft > 0 || addBottom > 0 || addRight > 0) {
+ int[] buf = new int[bi.getWidth()*bi.getHeight()];
+ bi.getRGB(0, 0, bi.getWidth(), bi.getHeight(), buf, 0, bi.getWidth());
+ BufferedImage borderBi = new BufferedImage(bi.getWidth()+addLeft+addRight, bi.getHeight()+addTop+addBottom, bi.getType());
+ borderBi.setRGB(addLeft, addTop, bi.getWidth(), bi.getHeight(), buf, 0, bi.getWidth());
+ bi = borderBi;
+ }
+ }
+
+ if (stretch != null) {
+ Rectangle2D srcBounds = new Rectangle2D.Double(
+ 0, 0, bi.getWidth(), bi.getHeight()
+ );
+ Rectangle2D dstBounds = new Rectangle2D.Double(
+ stretch.left/100_000 * userBounds.getWidth(),
+ stretch.top/100_000 * userBounds.getHeight(),
+ (100_000-stretch.left-stretch.right)/100_000 * userBounds.getWidth(),
+ (100_000-stretch.top-stretch.bottom)/100_000 * userBounds.getHeight()
+ );
+
+ BufferedImage stretchBi = new BufferedImage((int)userBounds.getWidth(), (int)userBounds.getHeight(), BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g = stretchBi.createGraphics();
+
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+ g.setComposite(AlphaComposite.Clear);
+ g.fillRect(0, 0, stretchBi.getWidth(), stretchBi.getHeight());
+ g.setComposite(AlphaComposite.SrcOver);
+
+ AffineTransform at = new AffineTransform();
+ at.translate(dstBounds.getCenterX(), dstBounds.getCenterY());
+ at.scale(dstBounds.getWidth()/srcBounds.getWidth(), dstBounds.getHeight()/srcBounds.getHeight());
+ at.translate(-srcBounds.getCenterX(), -srcBounds.getCenterY());
+
+ g.drawRenderedImage(bi, at);
+
+ g.dispose();
+
+ bi = stretchBi;
+ }
+
+ return bi;
+ }
+
+ private AffineTransform getTiledInstance(final Rectangle2D usedBounds, final AffineTransform xform) {
final BufferedImage bi = getImage();
- final double img_w = bi.getWidth() * (scale == null ? 1 : scale.getWidth())/flipX;
- final double img_h = bi.getHeight() * (scale == null ? 1 : scale.getHeight())/flipY;
+ final Dimension2D scale = fill.getScale();
+ assert(scale != null);
+ final double img_w = bi.getWidth() * (scale.getWidth() == 0 ? 1 : scale.getWidth())/flipX;
+ final double img_h = bi.getHeight() * (scale.getHeight() == 0 ? 1 : scale.getHeight())/flipY;
// Alignment happens after the scaling but before any offset.
PaintStyle.TextureAlignment ta = fill.getAlignment();
final double alg_x, alg_y;
+ final double usr_w = usedBounds.getWidth(), usr_h = usedBounds.getHeight();
switch (ta == null ? PaintStyle.TextureAlignment.TOP_LEFT : ta) {
case BOTTOM:
alg_x = (usr_w-img_w)/2;
xform.translate(offset.getX(),offset.getY());
}
- if (scale != null) {
- xform.scale(scale.getWidth()/(isBitmapSrc ? flipX : 1.),scale.getHeight()/(isBitmapSrc ? flipY : 1.));
- }
+ xform.scale(scale.getWidth()/(isBitmapSrc ? flipX : 1.),scale.getHeight()/(isBitmapSrc ? flipY : 1.));
- return super.createContext(cm, deviceBounds, userBounds, xform, hints);
+ return xform;
}
}
default TextureAlignment getAlignment() { return null; }
+
+ /**
+ * Specifies the portion of the blip or image that is used for the fill.<p>
+ *
+ * Each edge of the image is defined by a percentage offset from the edge of the bounding box.
+ * A positive percentage specifies an inset and a negative percentage specifies an outset.<p>
+ *
+ * The percentage are ints based on 100000, so 100% = 100000.<p>
+ *
+ * So, for example, a left offset of 25% specifies that the left edge of the image is located
+ * to the right of the bounding box's left edge by 25% of the bounding box's width.
+ *
+ * @return the cropping insets of the source image
+ */
+ default Insets2D getInsets() {
+ return null;
+ }
+
+ /**
+ * The stretch specifies the edges of a fill rectangle.<p>
+ *
+ * Each edge of the fill rectangle is defined by a perentage offset from the corresponding edge
+ * of the picture's bounding box. A positive percentage specifies an inset and a negative percentage
+ * specifies an outset.<p>
+ *
+ * The percentage are ints based on 100000, so 100% = 100000.
+ *
+ * @return the stretching in the destination image
+ */
+ default Insets2D getStretch() {
+ return null;
+ }
}
}
--- /dev/null
+/* ====================================================================
+ 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.util.Arrays;
+
+import org.apache.poi.sl.usermodel.ColorStyle;
+import org.apache.poi.sl.usermodel.PaintStyle;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientStop;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
+
+@Internal
+public class XSLFGradientPaint implements PaintStyle.GradientPaint {
+
+ private final CTGradientFillProperties gradFill;
+ final ColorStyle[] cs;
+ final float[] fractions;
+
+ public XSLFGradientPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) {
+ this.gradFill = gradFill;
+
+ final CTGradientStop[] gs = gradFill.getGsLst() == null ?
+ new CTGradientStop[0] : gradFill.getGsLst().getGsArray();
+
+ Arrays.sort(gs, (o1, o2) -> {
+ int pos1 = o1.getPos();
+ int pos2 = o2.getPos();
+ return Integer.compare(pos1, pos2);
+ });
+
+ cs = new ColorStyle[gs.length];
+ 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++;
+ }
+
+ }
+
+
+ @Override
+ public double getGradientAngle() {
+ return (gradFill.isSetLin())
+ ? gradFill.getLin().getAng() / 60000.d
+ : 0;
+ }
+
+ @Override
+ public ColorStyle[] getGradientColors() {
+ return cs;
+ }
+
+ @Override
+ public float[] getGradientFractions() {
+ return fractions;
+ }
+
+ @Override
+ public boolean isRotatedWithShape() {
+ return gradFill.getRotWithShape();
+ }
+
+ @Override
+ public PaintStyle.GradientPaint.GradientType getGradientType() {
+ if (gradFill.isSetLin()) {
+ return PaintStyle.GradientPaint.GradientType.linear;
+ }
+
+ if (gradFill.isSetPath()) {
+ /* TODO: handle rect path */
+ STPathShadeType.Enum ps = gradFill.getPath().getPath();
+ if (ps == STPathShadeType.CIRCLE) {
+ return PaintStyle.GradientPaint.GradientType.circular;
+ } else if (ps == STPathShadeType.SHAPE) {
+ return PaintStyle.GradientPaint.GradientType.shape;
+ }
+ }
+
+ return PaintStyle.GradientPaint.GradientType.linear;
+ }
+
+}
package org.apache.poi.xslf.usermodel;
import java.awt.Graphics2D;
-import java.awt.geom.Dimension2D;
-import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-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.Dimension2DDouble;
import org.apache.poi.util.Internal;
-import org.apache.poi.util.Units;
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.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTileInfoProperties;
-import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
-import org.openxmlformats.schemas.drawingml.x2006.main.STTileFlipMode;
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
protected PaintStyle getFillPaint() {
final XSLFTheme theme = getSheet().getTheme();
final boolean hasPlaceholder = getPlaceholder() != null;
+
PropertyFetcher<PaintStyle> fetcher = new PropertyFetcher<PaintStyle>() {
@Override
public boolean fetch(XSLFShape shape) {
@SuppressWarnings("WeakerAccess")
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);
- }
- }
-
- @Override
- public InputStream getImageData() {
- try {
- return getPart().getInputStream();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public String getContentType() {
- if (blip == null || !blip.isSetEmbed() || blip.getEmbed().isEmpty()) {
- return null;
- }
- /* TOOD: map content-type */
- return getPart().getContentType();
- }
-
- @Override
- public int getAlpha() {
- return (blip.sizeOfAlphaModFixArray() > 0)
- ? blip.getAlphaModFixArray(0).getAmt()
- : 100000;
- }
-
- @Override
- public boolean isRotatedWithShape() {
- return blipFill.isSetRotWithShape() && blipFill.getRotWithShape();
- }
-
- @Override
- public Dimension2D getScale() {
- CTTileInfoProperties tile = blipFill.getTile();
- return (tile == null) ? null : new Dimension2DDouble(
- tile.isSetSx() ? tile.getSx()/100_000. : 1,
- tile.isSetSy() ? tile.getSy()/100_000. : 1);
- }
-
- @Override
- public Point2D getOffset() {
- CTTileInfoProperties tile = blipFill.getTile();
- return (tile == null) ? null : new Point2D.Double(
- tile.isSetTx() ? Units.toPoints(tile.getTx()) : 0,
- tile.isSetTy() ? Units.toPoints(tile.getTy()) : 0);
- }
-
- @Override
- public FlipMode getFlipMode() {
- CTTileInfoProperties tile = blipFill.getTile();
- switch (tile == null || tile.getFlip() == null ? STTileFlipMode.INT_NONE : tile.getFlip().intValue()) {
- default:
- case STTileFlipMode.INT_NONE:
- return FlipMode.NONE;
- case STTileFlipMode.INT_X:
- return FlipMode.X;
- case STTileFlipMode.INT_Y:
- return FlipMode.Y;
- case STTileFlipMode.INT_XY:
- return FlipMode.XY;
- }
- }
-
- @Override
- public TextureAlignment getAlignment() {
- CTTileInfoProperties tile = blipFill.getTile();
- return (tile == null || !tile.isSetAlgn()) ? null
- : TextureAlignment.fromOoxmlId(tile.getAlgn().toString());
- }
- };
+ return new XSLFTexturePaint(blipFill, parentPart);
}
@SuppressWarnings("WeakerAccess")
protected static PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) {
-
- @SuppressWarnings("deprecation")
- final CTGradientStop[] gs = gradFill.getGsLst() == null ?
- new CTGradientStop[0] : gradFill.getGsLst().getGsArray();
-
- Arrays.sort(gs, (o1, o2) -> {
- int pos1 = o1.getPos();
- int pos2 = o2.getPos();
- return Integer.compare(pos1, 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() {
-
- @Override
- public double getGradientAngle() {
- return (gradFill.isSetLin())
- ? gradFill.getLin().getAng() / 60000.d
- : 0;
- }
-
- @Override
- public ColorStyle[] getGradientColors() {
- return cs;
- }
-
- @Override
- public float[] getGradientFractions() {
- return fractions;
- }
-
- @Override
- public boolean isRotatedWithShape() {
- return gradFill.getRotWithShape();
- }
-
- @Override
- 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;
- }
- };
+ return new XSLFGradientPaint(gradFill, phClr, theme);
}
@SuppressWarnings("WeakerAccess")
--- /dev/null
+/* ====================================================================
+ 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.geom.Dimension2D;
+import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.function.Supplier;
+
+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.usermodel.Insets2D;
+import org.apache.poi.sl.usermodel.PaintStyle;
+import org.apache.poi.util.Dimension2DDouble;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.Units;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRelativeRect;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTileInfoProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTileFlipMode;
+
+@Internal
+public class XSLFTexturePaint implements PaintStyle.TexturePaint {
+ private final CTBlipFillProperties blipFill;
+ private final PackagePart parentPart;
+ private final CTBlip blip;
+
+ public XSLFTexturePaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) {
+ this.blipFill = blipFill;
+ this.parentPart = parentPart;
+ blip = blipFill.getBlip();
+ }
+
+
+ private PackagePart getPart() {
+ try {
+ String blipId = blip.getEmbed();
+ PackageRelationship rel = parentPart.getRelationship(blipId);
+ return parentPart.getRelatedPart(rel);
+ } catch (InvalidFormatException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public InputStream getImageData() {
+ try {
+ return getPart().getInputStream();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String getContentType() {
+ if (blip == null || !blip.isSetEmbed() || blip.getEmbed().isEmpty()) {
+ return null;
+ }
+ /* TOOD: map content-type */
+ return getPart().getContentType();
+ }
+
+ @Override
+ public int getAlpha() {
+ return (blip.sizeOfAlphaModFixArray() > 0)
+ ? blip.getAlphaModFixArray(0).getAmt()
+ : 100000;
+ }
+
+ @Override
+ public boolean isRotatedWithShape() {
+ return blipFill.isSetRotWithShape() && blipFill.getRotWithShape();
+ }
+
+ @Override
+ public Dimension2D getScale() {
+ CTTileInfoProperties tile = blipFill.getTile();
+ return (tile == null) ? null : new Dimension2DDouble(
+ tile.isSetSx() ? tile.getSx()/100_000. : 1,
+ tile.isSetSy() ? tile.getSy()/100_000. : 1);
+ }
+
+ @Override
+ public Point2D getOffset() {
+ CTTileInfoProperties tile = blipFill.getTile();
+ return (tile == null) ? null : new Point2D.Double(
+ tile.isSetTx() ? Units.toPoints(tile.getTx()) : 0,
+ tile.isSetTy() ? Units.toPoints(tile.getTy()) : 0);
+ }
+
+ @Override
+ public PaintStyle.FlipMode getFlipMode() {
+ CTTileInfoProperties tile = blipFill.getTile();
+ switch (tile == null || tile.getFlip() == null ? STTileFlipMode.INT_NONE : tile.getFlip().intValue()) {
+ default:
+ case STTileFlipMode.INT_NONE:
+ return PaintStyle.FlipMode.NONE;
+ case STTileFlipMode.INT_X:
+ return PaintStyle.FlipMode.X;
+ case STTileFlipMode.INT_Y:
+ return PaintStyle.FlipMode.Y;
+ case STTileFlipMode.INT_XY:
+ return PaintStyle.FlipMode.XY;
+ }
+ }
+
+ @Override
+ public PaintStyle.TextureAlignment getAlignment() {
+ CTTileInfoProperties tile = blipFill.getTile();
+ return (tile == null || !tile.isSetAlgn()) ? null
+ : PaintStyle.TextureAlignment.fromOoxmlId(tile.getAlgn().toString());
+ }
+
+ @Override
+ public Insets2D getInsets() {
+ return getRectVal(blipFill.getSrcRect());
+ }
+
+ @Override
+ public Insets2D getStretch() {
+ return getRectVal(blipFill.isSetStretch() ? blipFill.getStretch().getFillRect() : null);
+ }
+
+ private static Insets2D getRectVal(CTRelativeRect rect) {
+ return rect == null ? null : new Insets2D(
+ getRectVal(rect::isSetT, rect::getT),
+ getRectVal(rect::isSetL, rect::getL),
+ getRectVal(rect::isSetB, rect::getB),
+ getRectVal(rect::isSetR, rect::getR)
+ );
+ }
+
+ private static int getRectVal(Supplier<Boolean> isSet, Supplier<Integer> val) {
+ return isSet.get() ? val.get() : 0;
+ }
+}
public FillStyle getFillStyle() {
- return new FillStyle() {
- @Override
- public PaintStyle getPaint() {
- AbstractEscherOptRecord opt = shape.getEscherOptRecord();
+ return this::getPaintStyle;
+ }
- EscherSimpleProperty hitProp = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST);
- int propVal = (hitProp == null) ? 0 : hitProp.getPropertyValue();
+ private PaintStyle getPaintStyle() {
+ AbstractEscherOptRecord opt = shape.getEscherOptRecord();
- EscherSimpleProperty masterProp = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.SHAPE__MASTER);
+ EscherSimpleProperty hitProp = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.FILL__NOFILLHITTEST);
+ int propVal = (hitProp == null) ? 0 : hitProp.getPropertyValue();
- if (!FILL_USE_FILLED.isSet(propVal) && masterProp != null) {
- int masterId = masterProp.getPropertyValue();
- HSLFShape o = shape.getSheet().getMasterSheet().getShapes().stream().filter(s -> s.getShapeId() == masterId).findFirst().orElse(null);
- return o != null ? o.getFillStyle().getPaint() : null;
- }
+ EscherSimpleProperty masterProp = HSLFShape.getEscherProperty(opt, EscherPropertyTypes.SHAPE__MASTER);
- final int fillType = getFillType();
- // TODO: fix gradient types, this mismatches with the MS-ODRAW definition ...
- // need to handle (not only) the type (radial,rectangular,linear),
- // the direction, e.g. top right, and bounds (e.g. for rectangular boxes)
- switch (fillType) {
- case FILL_SOLID:
- return DrawPaint.createSolidPaint(getForegroundColor());
- case FILL_SHADE_SHAPE:
- return getGradientPaint(GradientType.shape);
- case FILL_SHADE_CENTER:
- case FILL_SHADE_TITLE:
- return getGradientPaint(GradientType.circular);
- case FILL_SHADE:
- case FILL_SHADE_SCALE:
- return getGradientPaint(GradientType.linear);
- case FILL_PICTURE:
- return getTexturePaint();
- default:
- LOG.log(POILogger.WARN, "unsuported fill type: " + fillType);
- return null;
- }
- }
- };
+ if (!FILL_USE_FILLED.isSet(propVal) && masterProp != null) {
+ int masterId = masterProp.getPropertyValue();
+ HSLFShape o = shape.getSheet().getMasterSheet().getShapes().stream().filter(s -> s.getShapeId() == masterId).findFirst().orElse(null);
+ return o != null ? o.getFillStyle().getPaint() : null;
+ }
+
+ final int fillType = getFillType();
+ // TODO: fix gradient types, this mismatches with the MS-ODRAW definition ...
+ // need to handle (not only) the type (radial,rectangular,linear),
+ // the direction, e.g. top right, and bounds (e.g. for rectangular boxes)
+ switch (fillType) {
+ case FILL_SOLID:
+ return DrawPaint.createSolidPaint(getForegroundColor());
+ case FILL_SHADE_SHAPE:
+ return getGradientPaint(GradientType.shape);
+ case FILL_SHADE_CENTER:
+ case FILL_SHADE_TITLE:
+ return getGradientPaint(GradientType.circular);
+ case FILL_SHADE:
+ case FILL_SHADE_SCALE:
+ return getGradientPaint(GradientType.linear);
+ case FILL_PICTURE:
+ return getTexturePaint();
+ default:
+ LOG.log(POILogger.WARN, "unsuported fill type: " + fillType);
+ return null;
+ }
}
private boolean isRotatedWithShape() {