From 0fb322bb921b9252bdd1b12d8767c7d3a2115d9c Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 19 Jan 2020 20:44:36 +0000 Subject: [PATCH] #64088 - SlideShow rendering fixes git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1872984 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/sl/draw/BitmapImageRenderer.java | 21 +- .../org/apache/poi/sl/draw/DrawPaint.java | 174 ++++++++++--- .../apache/poi/sl/usermodel/PaintStyle.java | 25 +- .../poi/xslf/usermodel/XSLFBackground.java | 10 +- .../apache/poi/xslf/usermodel/XSLFColor.java | 232 ++++++++++-------- .../poi/xslf/usermodel/XSLFGradientPaint.java | 17 +- .../apache/poi/xslf/usermodel/XSLFNotes.java | 6 +- .../poi/xslf/usermodel/XSLFNotesMaster.java | 14 +- .../apache/poi/xslf/usermodel/XSLFShadow.java | 14 +- .../apache/poi/xslf/usermodel/XSLFShape.java | 22 +- .../apache/poi/xslf/usermodel/XSLFSheet.java | 75 +++++- .../poi/xslf/usermodel/XSLFSimpleShape.java | 90 +++---- .../apache/poi/xslf/usermodel/XSLFSlide.java | 17 +- .../poi/xslf/usermodel/XSLFSlideLayout.java | 6 + .../poi/xslf/usermodel/XSLFSlideMaster.java | 8 +- .../poi/xslf/usermodel/XSLFTableCell.java | 38 +-- .../poi/xslf/usermodel/XSLFTextParagraph.java | 2 +- .../poi/xslf/usermodel/XSLFTextRun.java | 5 +- .../poi/xslf/usermodel/XSLFTexturePaint.java | 27 +- .../apache/poi/xslf/usermodel/XSLFTheme.java | 75 +++--- .../poi/xslf/usermodel/TestXSLFColor.java | 23 +- .../poi/hslf/usermodel/HSLFTextParagraph.java | 24 +- 22 files changed, 580 insertions(+), 345 deletions(-) diff --git a/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java b/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java index 3f6c886859..7b7fd7aa21 100644 --- a/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java +++ b/src/java/org/apache/poi/sl/draw/BitmapImageRenderer.java @@ -75,7 +75,7 @@ public class BitmapImageRenderer implements ImageRenderer { public void loadImage(byte[] data, String contentType) throws IOException { img = readImage(new ByteArrayInputStream(data), contentType); } - + /** * Read the image data via ImageIO and optionally try to workaround metadata errors. * The resulting image is of image type {@link BufferedImage#TYPE_INT_ARGB} @@ -117,7 +117,7 @@ public class BitmapImageRenderer implements ImageRenderer { } try { - + switch (mode) { case 0: reader.setInput(iis, false, true); @@ -146,7 +146,7 @@ public class BitmapImageRenderer implements ImageRenderer { reader.setInput(iis, false, true); int height = reader.getHeight(0); int width = reader.getWidth(0); - + Iterator imageTypes = reader.getImageTypes(0); if (imageTypes.hasNext()) { ImageTypeSpecifier imageTypeSpecifier = imageTypes.next(); @@ -172,11 +172,11 @@ public class BitmapImageRenderer implements ImageRenderer { img = argbImg; } } - } + } break; } } - + } catch (IOException e) { if (mode < 2) { lastException = e; @@ -192,7 +192,7 @@ public class BitmapImageRenderer implements ImageRenderer { } finally { iis.close(); } - + // If you don't have an image at the end of all readers if (img == null) { if (lastException != null) { @@ -212,7 +212,7 @@ public class BitmapImageRenderer implements ImageRenderer { g.dispose(); return argbImg; } - + return img; } @@ -229,8 +229,8 @@ public class BitmapImageRenderer implements ImageRenderer { } return 0; } - - + + @Override public BufferedImage getImage() { return img; @@ -245,6 +245,9 @@ public class BitmapImageRenderer implements ImageRenderer { double h_old = img.getHeight(); double w_new = dim.getWidth(); double h_new = dim.getHeight(); + if (w_old == w_new && h_old == h_new) { + return img; + } BufferedImage scaled = new BufferedImage((int)w_new, (int)h_new, BufferedImage.TYPE_INT_ARGB); AffineTransform at = new AffineTransform(); at.scale(w_new/w_old, h_new/h_old); diff --git a/src/java/org/apache/poi/sl/draw/DrawPaint.java b/src/java/org/apache/poi/sl/draw/DrawPaint.java index 60a861cc49..d8a11a956e 100644 --- a/src/java/org/apache/poi/sl/draw/DrawPaint.java +++ b/src/java/org/apache/poi/sl/draw/DrawPaint.java @@ -22,7 +22,10 @@ import static org.apache.poi.sl.draw.geom.ArcToCommand.convertOoxml2AwtAngle; import java.awt.Color; import java.awt.Graphics2D; import java.awt.LinearGradientPaint; +import java.awt.MultipleGradientPaint.ColorSpaceType; +import java.awt.MultipleGradientPaint.CycleMethod; import java.awt.Paint; +import java.awt.Point; import java.awt.RadialGradientPaint; import java.awt.Shape; import java.awt.geom.AffineTransform; @@ -30,15 +33,24 @@ import java.awt.geom.Dimension2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.TreeMap; import java.util.function.BiFunction; +import java.util.stream.Stream; import org.apache.poi.sl.usermodel.AbstractColorStyle; import org.apache.poi.sl.usermodel.ColorStyle; +import org.apache.poi.sl.usermodel.Insets2D; import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle.FlipMode; import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; @@ -214,6 +226,9 @@ public class DrawPaint { } private int scale(int value, PaintModifier lessModifier, PaintModifier moreModifier) { + if (value == -1) { + return -1; + } int delta = (modifier == lessModifier ? 20000 : (modifier == moreModifier ? 40000 : 0)); return Math.min(100000, Math.max(0,value)+delta); } @@ -227,6 +242,8 @@ public class DrawPaint { switch (fill.getGradientType()) { case linear: return createLinearGradientPaint(fill, graphics); + case rectangular: + // TODO: implement rectangular gradient fill case circular: return createRadialGradientPaint(fill, graphics); case shape: @@ -314,6 +331,8 @@ public class DrawPaint { image = img; } + image = colorizePattern(fill, image); + Shape s = (Shape)graphics.getRenderingHint(Drawable.GRADIENT_SHAPE); // TODO: check why original bitmaps scale/behave differently to vector based images @@ -324,6 +343,49 @@ public class DrawPaint { } } + /** + * In case a duotone element is specified, handle image as pattern and replace its color values + * with the corresponding percentile / linear value between fore- and background color + * + * @return the original image if no duotone was found, otherwise the colorized pattern + */ + private static BufferedImage colorizePattern(TexturePaint fill, BufferedImage pattern) { + List duoTone = fill.getDuoTone(); + if (duoTone == null || duoTone.size() != 2) { + return pattern; + } + + // the pattern image is actually a gray scale image, so we simply take the first color component + // as an index into our gradient samples + int blendShades = 1 << pattern.getSampleModel().getSampleSize(0); + int[] gradSample = linearBlendedColors(duoTone, blendShades); + int[] redSample = pattern.getRaster().getSamples(0, 0, pattern.getWidth(), pattern.getHeight(), 0, (int[])null); + + for (int i=0; i duoTone, final int blendShades) { + Color[] colors = duoTone.stream().map(DrawPaint::applyColorTransform).toArray(Color[]::new); + float[] fractions = { 0, 1 }; + + // create lookup list of blended colors of back- and foreground + BufferedImage gradBI = new BufferedImage(blendShades, 1, BufferedImage.TYPE_INT_ARGB); + Graphics2D gradG = gradBI.createGraphics(); + gradG.setPaint(new LinearGradientPaint(0,0, blendShades,0, fractions, colors)); + gradG.fillRect(0,0, blendShades,1); + gradG.dispose(); + + return gradBI.getRGB(0, 0, blendShades, 1, null, 0, blendShades); + } + + /** * Convert color transformations in {@link ColorStyle} to a {@link Color} instance * @@ -341,7 +403,8 @@ public class DrawPaint { Color result = color.getColor(); double alpha = getAlpha(result, color); - double[] hsl = RGB2HSL(result); // values are in the range [0..100] (usually ...) + // values are in the range [0..100] (usually ...) + double[] hsl = RGB2HSL(result); applyHslModOff(hsl, 0, color.getHueMod(), color.getHueOff()); applyHslModOff(hsl, 1, color.getSatMod(), color.getSatOff()); applyHslModOff(hsl, 2, color.getLumMod(), color.getLumOff()); @@ -386,16 +449,11 @@ public class DrawPaint { * @param off the offset adjustment */ private static void applyHslModOff(double[] hsl, int hslPart, int mod, int off) { - if (mod == -1) { - mod = 100000; - } - if (off == -1) { - off = 0; + if (mod != -1) { + hsl[hslPart] *= mod / 100_000d; } - if (!(mod == 100000 && off == 0)) { - double fOff = off / 1000d; - double fMod = mod / 100000d; - hsl[hslPart] = hsl[hslPart]*fMod+fOff; + if (off != -1) { + hsl[hslPart] += off / 1000d; } } @@ -410,9 +468,8 @@ public class DrawPaint { return; } - double shadePct = shade / 100000.; - - hsl[2] *= 1. - shadePct; + double shadePct = shade / 100_000.; + hsl[2] *= shadePct; } /** @@ -423,13 +480,23 @@ public class DrawPaint { */ private static void applyTint(double[] hsl, ColorStyle fc) { int tint = fc.getTint(); - if (tint == -1) { + if (tint == -1 || tint == 0) { return; } // see 18.8.19 fgColor (Foreground Color) - double tintPct = tint / 100000.; - hsl[2] = hsl[2]*(1.-tintPct) + (100.-100.*(1.-tintPct)); + double tintPct = tint / 100_000.; + + + // The tint value is stored as a double from -1.0 .. 1.0, where -1.0 means 100% darken + // and 1.0 means 100% lighten. Also, 0.0 means no change. + if (tintPct < 0) { + // Lum’ = Lum * (1.0 + tint) + hsl[2] *= (1 + tintPct); + } else { + // Lum‘ = Lum * (1.0-tint) + (HLSMAX – HLSMAX * (1.0-tint)) + hsl[2] = hsl[2]*(1-tintPct) + (100-100*(1-tintPct)); + } } @SuppressWarnings("WeakerAccess") @@ -444,6 +511,9 @@ public class DrawPaint { } Rectangle2D anchor = DrawShape.getAnchor(graphics, shape); + if (anchor == null) { + return TRANSPARENT; + } angle = convertOoxml2AwtAngle(-angle, anchor.getWidth(), anchor.getHeight()); @@ -467,12 +537,50 @@ public class DrawPaint { @SuppressWarnings("WeakerAccess") protected Paint createRadialGradientPaint(GradientPaint fill, Graphics2D graphics) { Rectangle2D anchor = DrawShape.getAnchor(graphics, shape); + if (anchor == null) { + return TRANSPARENT; + } + + Insets2D insets = fill.getFillToInsets(); + if (insets == null) { + insets = new Insets2D(0,0,0,0); + } + + // TODO: handle negative width/height + final Point2D pCenter = new Point2D.Double( + anchor.getCenterX(), anchor.getCenterY() + ); - final Point2D pCenter = new Point2D.Double(anchor.getCenterX(), anchor.getCenterY()); + final Point2D pFocus = new Point2D.Double( + getCenterVal(anchor.getMinX(), anchor.getMaxX(), insets.left, insets.right), + getCenterVal(anchor.getMinY(), anchor.getMaxY(), insets.top, insets.bottom) + ); final float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight()); - return safeFractions((f,c)->new RadialGradientPaint(pCenter,radius,f,c), fill); + final AffineTransform at = new AffineTransform(); + at.translate(pFocus.getX(), pFocus.getY()); + at.scale( + getScale(anchor.getMinX(), anchor.getMaxX(), insets.left, insets.right), + getScale(anchor.getMinY(), anchor.getMaxY(), insets.top, insets.bottom) + ); + at.translate(-pFocus.getX(), -pFocus.getY()); + + return safeFractions((f,c)->new RadialGradientPaint(pCenter, radius, pFocus, f, c, CycleMethod.NO_CYCLE, ColorSpaceType.SRGB, at), fill); + } + + private static double getScale(double absMin, double absMax, double relMin, double relMax) { + double absDelta = absMax-absMin; + double absStart = absMin+absDelta*relMin; + double absStop = (relMin+relMax <= 1) ? absMax-absDelta*relMax : absMax+absDelta*relMax; + return (absDelta == 0) ? 1 : (absStop-absStart)/absDelta; + } + + private static double getCenterVal(double absMin, double absMax, double relMin, double relMax) { + double absDelta = absMax-absMin; + double absStart = absMin+absDelta*relMin; + double absStop = (relMin+relMax <= 1) ? absMax-absDelta*relMax : absMax+absDelta*relMax; + return absStart+(absStop-absStart)/2.; } @SuppressWarnings({"WeakerAccess", "unused"}) @@ -483,29 +591,25 @@ public class DrawPaint { } private Paint safeFractions(BiFunction init, GradientPaint fill) { - float[] fractions = fill.getGradientFractions(); - final ColorStyle[] styles = fill.getGradientColors(); + // if style is null, use transparent color to get color of background + final Iterator styles = Stream.of(fill.getGradientColors()) + .map(s -> s == null ? TRANSPARENT : applyColorTransform(s)) + .iterator(); // need to remap the fractions, because Java doesn't like repeating fraction values Map m = new TreeMap<>(); - for (int i = 0; i me : m.entrySet()) { - fractions[i] = me.getKey(); - colors[i] = me.getValue(); - i++; - } + return init.apply(toArray(m.keySet()), m.values().toArray(new Color[0])); + } - return init.apply(fractions, colors); + private static float[] toArray(Collection floatList) { + int[] idx = { 0 }; + float[] ret = new float[floatList.size()]; + floatList.forEach(f -> ret[idx[0]++] = f); + return ret; } /** diff --git a/src/java/org/apache/poi/sl/usermodel/PaintStyle.java b/src/java/org/apache/poi/sl/usermodel/PaintStyle.java index 92371b68c5..21f0824a2f 100644 --- a/src/java/org/apache/poi/sl/usermodel/PaintStyle.java +++ b/src/java/org/apache/poi/sl/usermodel/PaintStyle.java @@ -20,7 +20,7 @@ package org.apache.poi.sl.usermodel; import java.awt.geom.Dimension2D; import java.awt.geom.Point2D; import java.io.InputStream; - +import java.util.List; public interface PaintStyle { @@ -87,8 +87,8 @@ public interface PaintStyle { } interface GradientPaint extends PaintStyle { - enum GradientType { linear, circular, shape } - + enum GradientType { linear, circular, rectangular, shape } + /** * @return the angle of the gradient */ @@ -97,8 +97,12 @@ public interface PaintStyle { float[] getGradientFractions(); boolean isRotatedWithShape(); GradientType getGradientType(); - } - + + default Insets2D getFillToInsets() { + return null; + } + } + interface TexturePaint extends PaintStyle { /** * @return the raw image stream @@ -109,7 +113,7 @@ public interface PaintStyle { * @return the content type of the image data */ String getContentType(); - + /** * @return the alpha mask in percents [0..100000] */ @@ -170,5 +174,14 @@ public interface PaintStyle { default Insets2D getStretch() { return null; } + + + /** + * For pattern images, the duo tone defines the black/white pixel color replacement + */ + default List getDuoTone() { + return null; + } + } } 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 dbc623b141..add51e6566 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java @@ -48,7 +48,7 @@ public class XSLFBackground extends XSLFSimpleShape /** * background does not have a associated transform, therefore we return null - * + * * @param create ignored * * @return null @@ -57,7 +57,7 @@ public class XSLFBackground extends XSLFSimpleShape protected CTTransform2D getXfrm(boolean create) { return null; } - + @Override public void setPlaceholder(Placeholder placeholder) { // extending XSLFSimpleShape is a bit unlucky ... @@ -74,7 +74,7 @@ public class XSLFBackground extends XSLFSimpleShape } return bg.getBgPr(); } - + public void setFillColor(Color color) { CTBackgroundProperties bgPr = getBgPr(true); @@ -105,8 +105,8 @@ public class XSLFBackground extends XSLFSimpleShape } CTSolidColorFillProperties fill = bgPr.isSetSolidFill() ? bgPr.getSolidFill() : bgPr.addNewSolidFill(); - - XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); + + XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr(), getSheet()); col.setColor(color); } } 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 95fc4a1386..7a2e6e2b97 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java @@ -19,6 +19,9 @@ package org.apache.poi.xslf.usermodel; import java.awt.Color; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.usermodel.AbstractColorStyle; @@ -52,11 +55,13 @@ public class XSLFColor { private XmlObject _xmlObject; private Color _color; private CTSchemeColor _phClr; + private XSLFSheet _sheet; @SuppressWarnings("WeakerAccess") - public XSLFColor(XmlObject obj, XSLFTheme theme, CTSchemeColor phClr) { + public XSLFColor(XmlObject obj, XSLFTheme theme, CTSchemeColor phClr, XSLFSheet sheet) { _xmlObject = obj; _phClr = phClr; + _sheet = sheet; _color = toColor(obj, theme); } @@ -74,116 +79,87 @@ public class XSLFColor { return DrawPaint.applyColorTransform(getColorStyle()); } + @SuppressWarnings("WeakerAccess") public ColorStyle getColorStyle() { - return new AbstractColorStyle() { - @Override - public Color getColor() { - return _color; - } - - @Override - public int getAlpha() { - return getRawValue("alpha"); - } - - @Override - public int getHueOff() { - return getRawValue("hueOff"); - } - - @Override - public int getHueMod() { - return getRawValue("hueMod"); - } + return new XSLFColorStyle(_xmlObject, _color, _phClr); + } - @Override - public int getSatOff() { - return getRawValue("satOff"); - } + private Color toColor(CTHslColor hsl) { + return DrawPaint.HSL2RGB( + hsl.getHue2() / 60000d, + hsl.getSat2() / 1000d, + hsl.getLum2() / 1000d, + 1d); + } - @Override - public int getSatMod() { - return getRawValue("satMod"); - } + private Color toColor(CTPresetColor prst) { + String colorName = prst.getVal().toString(); + PresetColor pc = PresetColor.valueOfOoxmlId(colorName); + return (pc != null) ? pc.color : null; + } - @Override - public int getLumOff() { - return getRawValue("lumOff"); - } + private Color toColor(CTSchemeColor schemeColor, XSLFTheme theme) { + 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 == null ? null : theme.getCTColor(_sheet.mapSchemeColor(colorRef)); + return (ctColor != null) ? toColor(ctColor, null) : null; + } - @Override - public int getLumMod() { - return getRawValue("lumMod"); - } + private Color toColor(CTScRgbColor scrgb) { + // color in percentage is in linear RGB color space, i.e. needs to be gamma corrected for AWT color + return new Color(DrawPaint.lin2srgb(scrgb.getR()), DrawPaint.lin2srgb(scrgb.getG()), DrawPaint.lin2srgb(scrgb.getB())); + } - @Override - public int getShade() { - return getRawValue("shade"); - } + private Color toColor(CTSRgbColor srgb) { + // color in sRGB color space, i.e. same as AWT Color + byte[] val = srgb.getVal(); + return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]); + } - @Override - public int getTint() { - return getRawValue("tint"); - } - }; + private Color toColor(CTSystemColor sys) { + if (sys.isSetLastClr()) { + byte[] val = sys.getLastClr(); + return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]); + } else { + String colorName = sys.getVal().toString(); + PresetColor pc = PresetColor.valueOfOoxmlId(colorName); + return (pc != null && pc.color != null) ? pc.color : Color.black; + } } private Color toColor(XmlObject obj, XSLFTheme theme) { Color color = null; - for (XmlObject ch : obj.selectPath("*")) { + List xo = new ArrayList<>(); + xo.add(obj); + xo.addAll(Arrays.asList(obj.selectPath("*"))); + boolean isFirst = true; + for (XmlObject ch : xo) { if (ch instanceof CTHslColor) { - CTHslColor hsl = (CTHslColor)ch; - int h = hsl.getHue2(); - int s = hsl.getSat2(); - int l = hsl.getLum2(); - color = DrawPaint.HSL2RGB(h / 60000d, s / 1000d, l / 1000d, 1d); + color = toColor((CTHslColor)ch); } else if (ch instanceof CTPresetColor) { - CTPresetColor prst = (CTPresetColor)ch; - String colorName = prst.getVal().toString(); - PresetColor pc = PresetColor.valueOfOoxmlId(colorName); - if (pc != null) { - color = pc.color; - } + color = toColor((CTPresetColor)ch); } 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 == null ? null : theme.getCTColor(colorRef); - if(ctColor != null) { - color = toColor(ctColor, null); - } + color = toColor((CTSchemeColor)ch, theme); } else if (ch instanceof CTScRgbColor) { - // color in percentage is in linear RGB color space, i.e. needs to be gamma corrected for AWT color - CTScRgbColor scrgb = (CTScRgbColor)ch; - color = new Color(DrawPaint.lin2srgb(scrgb.getR()), DrawPaint.lin2srgb(scrgb.getG()), DrawPaint.lin2srgb(scrgb.getB())); + color = toColor((CTScRgbColor)ch); } else if (ch instanceof CTSRgbColor) { - // color in sRGB color space, i.e. same as AWT Color - CTSRgbColor srgb = (CTSRgbColor)ch; - byte[] val = srgb.getVal(); - color = new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]); + color = toColor((CTSRgbColor)ch); } else if (ch instanceof CTSystemColor) { - CTSystemColor sys = (CTSystemColor)ch; - if(sys.isSetLastClr()) { - byte[] val = sys.getLastClr(); - color = new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]); - } else { - String colorName = sys.getVal().toString(); - PresetColor pc = PresetColor.valueOfOoxmlId(colorName); - if (pc != null) { - color = pc.color; - } - if (color == null) { - color = Color.black; - } - } + color = toColor((CTSystemColor)ch); } else if (!(ch instanceof CTFontReference)) { - throw new IllegalArgumentException("Unexpected color choice: " + ch.getClass()); + if (!isFirst) { + throw new IllegalArgumentException("Unexpected color choice: " + ch.getClass()); + } + } + if (color != null) { + break; } + isFirst = false; } return color; } @@ -257,14 +233,14 @@ public class XSLFColor { return Math.abs((f*255d) - Math.rint(f*255d)) < 0.00001; } - private int getRawValue(String elem) { + private static int getRawValue(CTSchemeColor phClr, XmlObject xmlObject, String 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 (phClr != null){ + obj = phClr.selectPath(query); if (obj.length == 1){ Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); if(attr != null) { @@ -273,7 +249,7 @@ public class XSLFColor { } } - obj = _xmlObject.selectPath(query); + obj = xmlObject.selectPath(query); if (obj.length == 1){ Node attr = obj[0].getDomNode().getAttributes().getNamedItem("val"); if(attr != null) { @@ -294,7 +270,7 @@ public class XSLFColor { * @return the percentage value in the range [0 .. 100] */ private int getPercentageValue(String elem){ - int val = getRawValue(elem); + int val = getRawValue(_phClr, _xmlObject, elem); return (val == -1) ? val : (val / 1000); } @@ -333,7 +309,7 @@ public class XSLFColor { @SuppressWarnings("unused") int getHue(){ - int val = getRawValue("hue"); + int val = getRawValue(_phClr, _xmlObject, "hue"); return (val == -1) ? val : (val / 60000); } @@ -500,4 +476,66 @@ public class XSLFColor { public int getTint(){ return getPercentageValue("tint"); } + + private static class XSLFColorStyle extends AbstractColorStyle { + private XmlObject xmlObject; + private Color color; + private CTSchemeColor phClr; + + XSLFColorStyle(XmlObject xmlObject, Color color, CTSchemeColor phClr) { + this.xmlObject = xmlObject; + this.color = color; + this.phClr = phClr; + } + + @Override + public Color getColor() { + return color; + } + + @Override + public int getAlpha() { + return getRawValue(phClr, xmlObject, "alpha"); + } + + @Override + public int getHueOff() { + return getRawValue(phClr, xmlObject, "hueOff"); + } + + @Override + public int getHueMod() { + return getRawValue(phClr, xmlObject, "hueMod"); + } + + @Override + public int getSatOff() { + return getRawValue(phClr, xmlObject, "satOff"); + } + + @Override + public int getSatMod() { + return getRawValue(phClr, xmlObject, "satMod"); + } + + @Override + public int getLumOff() { + return getRawValue(phClr, xmlObject, "lumOff"); + } + + @Override + public int getLumMod() { + return getRawValue(phClr, xmlObject, "lumMod"); + } + + @Override + public int getShade() { + return getRawValue(phClr, xmlObject, "shade"); + } + + @Override + public int getTint() { + return getRawValue(phClr, xmlObject, "tint"); + } + } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGradientPaint.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGradientPaint.java index a39ffd5bcf..f86d2e9035 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGradientPaint.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGradientPaint.java @@ -20,10 +20,12 @@ package org.apache.poi.xslf.usermodel; import java.util.Arrays; import org.apache.poi.sl.usermodel.ColorStyle; +import org.apache.poi.sl.usermodel.Insets2D; 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.CTRelativeRect; import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType; @@ -34,7 +36,7 @@ public class XSLFGradientPaint implements PaintStyle.GradientPaint { final ColorStyle[] cs; final float[] fractions; - public XSLFGradientPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) { + public XSLFGradientPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme, final XSLFSheet sheet) { this.gradFill = gradFill; final CTGradientStop[] gs = gradFill.getGsLst() == null ? @@ -55,7 +57,7 @@ public class XSLFGradientPaint implements PaintStyle.GradientPaint { if (phClrCgs == null && cgs.isSetSchemeClr()) { phClrCgs = cgs.getSchemeClr(); } - cs[i] = new XSLFColor(cgs, theme, phClrCgs).getColorStyle(); + cs[i] = new XSLFColor(cgs, theme, phClrCgs, sheet).getColorStyle(); fractions[i] = cgs.getPos() / 100000.f; i++; } @@ -98,10 +100,21 @@ public class XSLFGradientPaint implements PaintStyle.GradientPaint { return PaintStyle.GradientPaint.GradientType.circular; } else if (ps == STPathShadeType.SHAPE) { return PaintStyle.GradientPaint.GradientType.shape; + } else if (ps == STPathShadeType.RECT) { + return PaintStyle.GradientPaint.GradientType.rectangular; } } return PaintStyle.GradientPaint.GradientType.linear; } + @Override + public Insets2D getFillToInsets() { + if (gradFill.isSetPath() && gradFill.getPath().isSetFillToRect()) { + final double base = 100_000; + CTRelativeRect rect = gradFill.getPath().getFillToRect(); + return new Insets2D(rect.getT()/base, rect.getL()/base, rect.getB()/base, rect.getR()/base); + } + return null; + } } 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 72d19e7aee..19b42c119f 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java @@ -40,7 +40,6 @@ implements Notes { * Create a new notes */ XSLFNotes() { - super(); _notes = prototype(); } @@ -105,4 +104,9 @@ implements Notes { } return tp; } + + @Override + String mapSchemeColor(String schemeColor) { + return mapSchemeColor(_notes.getClrMapOvr(), schemeColor); + } } 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 833ea8f608..6ebe185531 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotesMaster.java @@ -26,7 +26,6 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.sl.usermodel.MasterSheet; import org.apache.poi.util.Beta; import org.apache.xmlbeans.XmlException; -import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMaster; import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument; @@ -65,12 +64,12 @@ import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument; NotesMasterDocument.Factory.parse(getPackagePart().getInputStream(), DEFAULT_XML_OPTIONS); _slide = doc.getNotesMaster(); } - + private static CTNotesMaster prototype() { InputStream is = XSLFNotesMaster.class.getResourceAsStream("notesMaster.xml"); if (is == null) { throw new POIXMLException("Missing resource 'notesMaster.xml'"); - } + } try { try { @@ -78,12 +77,12 @@ import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument; return doc.getNotesMaster(); } finally { is.close(); - } + } } catch (Exception e) { throw new POIXMLException("Can't initialize NotesMaster", e); } } - + @Override public CTNotesMaster getXmlObject() { return _slide; @@ -106,7 +105,8 @@ import org.openxmlformats.schemas.presentationml.x2006.main.NotesMasterDocument; } @Override - CTColorMapping getColorMapping() { - return _slide.getClrMap(); + String mapSchemeColor(String schemeColor) { + String notesMasterColor = mapSchemeColor(_slide.getClrMap(), schemeColor); + return notesMasterColor == null ? schemeColor : notesMasterColor; } } \ 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 619b10f216..9ec4e3e6bc 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java @@ -61,11 +61,11 @@ public class XSLFShadow extends XSLFShape implements Shadow { if (shape instanceof XSLFPictureShape) { CTPicture pic = (CTPicture)shape.getXmlObject(); if (pic.getBlipFill() != null) { - setValue(selectPaint(pic.getBlipFill(), pp)); + setValue(selectPaint(pic.getBlipFill(), pp, null, theme)); return true; } } @@ -360,13 +360,13 @@ public abstract class XSLFShape implements Shape { * @return the applied Paint or null if none was applied */ @SuppressWarnings("WeakerAccess") - protected static PaintStyle selectPaint(XSLFFillProperties fp, final CTSchemeColor phClr, final PackagePart parentPart, final XSLFTheme theme, boolean hasPlaceholder) { + protected 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); + return selectPaint(fp.getBlipFill(), parentPart, phClr, theme); } else if (fp.isSetGradFill()) { return selectPaint(fp.getGradFill(), phClr, theme); } else if (fp.isSetMatrixStyle()) { @@ -377,7 +377,7 @@ public abstract class XSLFShape implements Shape { } @SuppressWarnings("WeakerAccess") - protected static PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr, final XSLFTheme theme) { + protected 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 @@ -389,22 +389,22 @@ public abstract class XSLFShape implements Shape { phClr = solidFill.getSchemeClr(); } } - final XSLFColor c = new XSLFColor(solidFill, theme, phClr); + final XSLFColor c = new XSLFColor(solidFill, theme, phClr, _sheet); return DrawPaint.createSolidPaint(c.getColorStyle()); } @SuppressWarnings("WeakerAccess") - protected static PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) { - return new XSLFTexturePaint(blipFill, parentPart); + protected PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart, CTSchemeColor phClr, final XSLFTheme theme) { + return new XSLFTexturePaint(blipFill, parentPart, phClr, theme, _sheet); } @SuppressWarnings("WeakerAccess") - protected static PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) { - return new XSLFGradientPaint(gradFill, phClr, theme); + protected PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr, final XSLFTheme theme) { + return new XSLFGradientPaint(gradFill, phClr, theme, _sheet); } @SuppressWarnings("WeakerAccess") - protected static PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme, boolean isLineStyle, boolean hasPlaceholder) { + protected PaintStyle selectPaint(CTStyleMatrixReference fillRef, final XSLFTheme theme, boolean isLineStyle, boolean hasPlaceholder) { if (fillRef == null) { return null; } @@ -441,7 +441,7 @@ public abstract class XSLFShape implements Shape { if (res != null || hasPlaceholder) { return res; } - XSLFColor col = new XSLFColor(fillRef, theme, phClr); + XSLFColor col = new XSLFColor(fillRef, theme, phClr, _sheet); return DrawPaint.createSolidPaint(col.getColorStyle()); } 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 97c490d82e..d78a35bee2 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java @@ -29,7 +29,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Optional; import javax.xml.namespace.QName; @@ -60,6 +59,8 @@ import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; +import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMappingOverride; +import org.openxmlformats.schemas.drawingml.x2006.main.STColorSchemeIndex; import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; @@ -497,15 +498,11 @@ implements XSLFShapeContainer, Sheet { return _theme; } - final Optional t = - getRelations().stream().filter((p) -> p instanceof XSLFTheme).map((p) -> (XSLFTheme) p).findAny(); - if (t.isPresent()) { - _theme = t.get(); - final CTColorMapping cmap = getColorMapping(); - if (cmap != null) { - _theme.initColorMap(cmap); - } - } + getRelations().stream() + .filter(p -> p instanceof XSLFTheme) + .findAny() + .ifPresent(p -> _theme = (XSLFTheme)p); + return _theme; } @@ -521,7 +518,7 @@ implements XSLFShapeContainer, Sheet { /** * @return the color mapping for this slide type */ - CTColorMapping getColorMapping() { + String mapSchemeColor(String schemeColor) { return null; } @@ -744,4 +741,60 @@ implements XSLFShapeContainer, Sheet { getDrawing().addChart(rp.getRelationship().getId(), rect2D); } + protected String mapSchemeColor(CTColorMappingOverride cmapOver, String schemeColor) { + String slideColor = mapSchemeColor((cmapOver == null) ? null : cmapOver.getOverrideClrMapping(), schemeColor); + if (slideColor != null) { + return slideColor; + } + XSLFSheet master = (XSLFSheet)getMasterSheet(); + String masterColor = (master == null) ? null : master.mapSchemeColor(schemeColor); + return (masterColor == null) ? schemeColor : masterColor; + } + + protected String mapSchemeColor(CTColorMapping cmap, String schemeColor) { + STColorSchemeIndex.Enum schemeMap = null; + if (cmap != null && schemeColor != null) { + switch (schemeColor) { + case "accent1": + schemeMap = cmap.getAccent1(); + break; + case "accent2": + schemeMap = cmap.getAccent2(); + break; + case "accent3": + schemeMap = cmap.getAccent3(); + break; + case "accent4": + schemeMap = cmap.getAccent4(); + break; + case "accent5": + schemeMap = cmap.getAccent5(); + break; + case "accent6": + schemeMap = cmap.getAccent6(); + break; + case "bg1": + schemeMap = cmap.getBg1(); + break; + case "bg2": + schemeMap = cmap.getBg2(); + break; + case "folHlink": + schemeMap = cmap.getFolHlink(); + break; + case "hlink": + schemeMap = cmap.getHlink(); + break; + case "tx1": + schemeMap = cmap.getTx1(); + break; + case "tx2": + schemeMap = cmap.getTx2(); + break; + default: + break; + } + } + return (schemeMap == null) ? null : schemeMap.toString(); + } } 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 4d98ecb2eb..e77820184e 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java @@ -51,33 +51,7 @@ import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFEffectProperties import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties; import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFGeometryProperties; import org.apache.xmlbeans.XmlObject; -import org.openxmlformats.schemas.drawingml.x2006.main.CTBaseStyles; -import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; -import org.openxmlformats.schemas.drawingml.x2006.main.CTEffectStyleItem; -import org.openxmlformats.schemas.drawingml.x2006.main.CTGeomGuide; -import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties; -import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; -import org.openxmlformats.schemas.drawingml.x2006.main.CTLineStyleList; -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.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.CTTransform2D; -import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine; -import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap; -import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength; -import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType; -import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth; -import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; -import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; +import org.openxmlformats.schemas.drawingml.x2006.main.*; /** * Represents a single (non-group) shape in a .pptx slide show @@ -130,7 +104,7 @@ public abstract class XSLFSimpleShape extends XSLFShape } }; fetchShapeProperty(fetcher); - + CTTransform2D xfrm = fetcher.getValue(); if (!create || xfrm != null) { return xfrm; @@ -286,12 +260,12 @@ public abstract class XSLFSimpleShape extends XSLFShape ln.unsetNoFill(); } - + if (color == null) { ln.addNewNoFill(); } else { CTSolidColorFillProperties fill = ln.addNewSolidFill(); - XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); + XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr(), getSheet()); col.setColor(color); } } @@ -325,7 +299,7 @@ public abstract class XSLFSimpleShape extends XSLFShape setValue(null); return true; } - + PackagePart pp = shape.getSheet().getPackagePart(); PaintStyle paint = selectPaint(fp, null, pp, theme, hasPlaceholder); if (paint != null) { @@ -343,12 +317,12 @@ public abstract class XSLFSimpleShape extends XSLFShape paint = getThemePaint(style, pp); } } - + if (paint != null) { setValue(paint); return true; } - + return false; } @@ -384,7 +358,7 @@ public abstract class XSLFSimpleShape extends XSLFShape if (lnPr == null) { return; } - + if (width == 0.) { if (lnPr.isSetW()) { lnPr.unsetW(); @@ -592,7 +566,7 @@ public abstract class XSLFSimpleShape extends XSLFShape if (ln == null) { return; } - + if (cap == null) { if (ln.isSetCap()) { ln.unsetCap(); @@ -641,7 +615,7 @@ public abstract class XSLFSimpleShape extends XSLFShape if (fp.isSetSolidFill()) { fp.unsetSolidFill(); } - + if (fp.isSetGradFill()) { fp.unsetGradFill(); } @@ -649,11 +623,11 @@ public abstract class XSLFSimpleShape extends XSLFShape if (fp.isSetPattFill()) { fp.unsetGradFill(); } - + if (fp.isSetBlipFill()) { fp.unsetBlipFill(); } - + if (!fp.isSetNoFill()) { fp.addNewNoFill(); } @@ -663,8 +637,8 @@ public abstract class XSLFSimpleShape extends XSLFShape } CTSolidColorFillProperties fill = fp.isSetSolidFill() ? fp.getSolidFill() : fp.addNewSolidFill(); - - XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr()); + + XSLFColor col = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr(), getSheet()); col.setColor(color); } } @@ -720,11 +694,11 @@ public abstract class XSLFSimpleShape extends XSLFShape @Override public CustomGeometry getGeometry() { XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties()); - + if (gp == null) { return null; } - + CustomGeometry geom; PresetGeometries dict = PresetGeometries.getInstance(); if(gp.isSetPrstGeom()){ @@ -798,7 +772,7 @@ public abstract class XSLFSimpleShape extends XSLFShape /** * Specifies the line end decoration, such as a triangle or arrowhead. - * + * * @param style the line end docoration style */ @SuppressWarnings("WeakerAccess") @@ -832,8 +806,8 @@ public abstract class XSLFSimpleShape extends XSLFShape /** * specifies decoration width of the head of a line. - * - * @param style the decoration width + * + * @param style the decoration width */ @SuppressWarnings("WeakerAccess") public void setLineHeadWidth(DecorationSize style) { @@ -873,7 +847,7 @@ public abstract class XSLFSimpleShape extends XSLFShape if (ln == null) { return; } - + CTLineEndProperties lnEnd = ln.isSetHeadEnd() ? ln.getHeadEnd() : ln.addNewHeadEnd(); if (style == null) { if (lnEnd.isSetLen()) { @@ -890,12 +864,12 @@ public abstract class XSLFSimpleShape extends XSLFShape @SuppressWarnings("WeakerAccess") public DecorationSize getLineHeadLength() { CTLineProperties ln = getLn(this, false); - + DecorationSize ds = DecorationSize.MEDIUM; if (ln != null && ln.isSetHeadEnd() && ln.getHeadEnd().isSetLen()) { ds = DecorationSize.fromOoxmlId(ln.getHeadEnd().getLen().intValue()); } - return ds; + return ds; } /** @@ -924,7 +898,7 @@ public abstract class XSLFSimpleShape extends XSLFShape @SuppressWarnings("WeakerAccess") public DecorationShape getLineTailDecoration() { CTLineProperties ln = getLn(this, false); - + DecorationShape ds = DecorationShape.NONE; if (ln != null && ln.isSetTailEnd() && ln.getTailEnd().isSetType()) { ds = DecorationShape.fromOoxmlId(ln.getTailEnd().getType().intValue()); @@ -941,7 +915,7 @@ public abstract class XSLFSimpleShape extends XSLFShape if (ln == null) { return; } - + CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd(); if (style == null) { if (lnEnd.isSetW()) { @@ -974,7 +948,7 @@ public abstract class XSLFSimpleShape extends XSLFShape if (ln == null) { return; } - + CTLineEndProperties lnEnd = ln.isSetTailEnd() ? ln.getTailEnd() : ln.addNewTailEnd(); if (style == null) { if (lnEnd.isSetLen()) { @@ -991,18 +965,18 @@ public abstract class XSLFSimpleShape extends XSLFShape @SuppressWarnings("WeakerAccess") public DecorationSize getLineTailLength() { CTLineProperties ln = getLn(this, false); - + DecorationSize ds = DecorationSize.MEDIUM; if (ln != null && ln.isSetTailEnd() && ln.getTailEnd().isSetLen()) { ds = DecorationSize.fromOoxmlId(ln.getTailEnd().getLen().intValue()); } - return ds; + return ds; } @Override public Guide getAdjustValue(String name) { XSLFGeometryProperties gp = XSLFPropertiesDelegate.getGeometryDelegate(getShapeProperties()); - + if (gp != null && gp.isSetPrstGeom() && gp.getPrstGeom().isSetAvLst()) { //noinspection deprecation for (CTGeomGuide g : gp.getPrstGeom().getAvLst().getGdArray()) { @@ -1098,7 +1072,7 @@ public abstract class XSLFSimpleShape extends XSLFShape setLineColor(null); return; } - + // TODO: handle PaintStyle for (Object st : styles) { if (st instanceof Number) { @@ -1114,7 +1088,7 @@ public abstract class XSLFSimpleShape extends XSLFShape } } } - + @Override public XSLFHyperlink getHyperlink() { CTNonVisualDrawingProps cNvPr = getCNvPr(); @@ -1123,7 +1097,7 @@ public abstract class XSLFSimpleShape extends XSLFShape } return new XSLFHyperlink(cNvPr.getHlinkClick(), getSheet()); } - + @Override public XSLFHyperlink createHyperlink() { XSLFHyperlink hl = getHyperlink(); @@ -1140,7 +1114,7 @@ public abstract class XSLFSimpleShape extends XSLFShape LOG.log(POILogger.WARN, shape.getClass() +" doesn't have line properties"); return null; } - + CTShapeProperties spr = (CTShapeProperties)pr; return (spr.isSetLn() || !create) ? spr.getLn() : spr.addNewLn(); } 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 33baa4c173..32456a3aa2 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ooxml.util.DocumentHelper; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.Drawable; @@ -31,7 +32,6 @@ import org.apache.poi.sl.usermodel.Notes; import org.apache.poi.sl.usermodel.Placeholder; import org.apache.poi.sl.usermodel.Slide; import org.apache.poi.util.Beta; -import org.apache.poi.ooxml.util.DocumentHelper; import org.apache.poi.util.NotImplemented; import org.apache.xmlbeans.XmlException; import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties; @@ -283,7 +283,7 @@ implements Slide { public boolean getFollowMasterObjects() { return getFollowMasterGraphics(); } - + @Override public void setFollowMasterObjects(boolean follow) { setFollowMasterGraphics(follow); @@ -328,7 +328,7 @@ implements Slide { public boolean getFollowMasterBackground() { return false; } - + @Override @NotImplemented public void setFollowMasterBackground(boolean follow) { @@ -340,7 +340,7 @@ implements Slide { public boolean getFollowMasterColourScheme() { return false; } - + @Override @NotImplemented public void setFollowMasterColourScheme(boolean follow) { @@ -378,7 +378,7 @@ implements Slide { return false; } - + @Override public void setHidden(boolean hidden) { CTSlide sld = getXmlObject(); @@ -391,7 +391,7 @@ implements Slide { } } } - + @Override public boolean isHidden() { CTSlide sld = getXmlObject(); @@ -403,4 +403,9 @@ implements Slide { final CTCommonSlideData cSld = getXmlObject().getCSld(); return cSld.isSetName() ? cSld.getName() : "Slide"+getSlideNumber(); } + + @Override + String mapSchemeColor(String schemeColor) { + return mapSchemeColor(_slide.getClrMapOvr(), schemeColor); + } } 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 569c6c2489..17f66bec0a 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java @@ -145,4 +145,10 @@ implements MasterSheet { int ordinal = _layout.getType().intValue() - 1; return SlideLayout.values()[ordinal]; } + + + @Override + String mapSchemeColor(String schemeColor) { + return mapSchemeColor(_layout.getClrMapOvr(), schemeColor); + } } \ 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 558e6b5cda..7a20d04d1d 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java @@ -29,7 +29,6 @@ import org.apache.poi.sl.usermodel.MasterSheet; import org.apache.poi.sl.usermodel.Placeholder; 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.CTBackground; import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMaster; @@ -66,7 +65,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument; SldMasterDocument.Factory.parse(getPackagePart().getInputStream(), DEFAULT_XML_OPTIONS); _slide = doc.getSldMaster(); } - + @Override public CTSlideMaster getXmlObject() { return _slide; @@ -169,7 +168,8 @@ import org.openxmlformats.schemas.presentationml.x2006.main.SldMasterDocument; } @Override - CTColorMapping getColorMapping() { - return _slide.getClrMap(); + String mapSchemeColor(String schemeColor) { + String masterColor = mapSchemeColor(_slide.getClrMap(), schemeColor); + return masterColor == null ? schemeColor : masterColor; } } 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 011914f16e..76f5a0d92b 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java @@ -37,33 +37,7 @@ import org.apache.poi.xddf.usermodel.text.XDDFTextBody; import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties; import org.apache.poi.xslf.usermodel.XSLFTableStyle.TablePartStyle; import org.apache.xmlbeans.XmlObject; -import org.openxmlformats.schemas.drawingml.x2006.main.CTFontReference; -import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties; -import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; -import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; -import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; -import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; -import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTable; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCellProperties; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTablePartStyle; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTableProperties; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyleCellStyle; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyleTextStyle; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; -import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; -import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine; -import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap; -import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength; -import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType; -import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth; -import org.openxmlformats.schemas.drawingml.x2006.main.STOnOffStyleType; -import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment; -import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal; -import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; -import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType; +import org.openxmlformats.schemas.drawingml.x2006.main.*; /** * Represents a cell of a table in a .pptx presentation @@ -319,7 +293,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell getDuoTone() { + if (blip.sizeOfDuotoneArray() == 0) { + return null; + } + List colors = new ArrayList<>(); + CTDuotoneEffect duoEff = blip.getDuotoneArray(0); + for (CTSchemeColor phClrDuo : duoEff.getSchemeClrArray()) { + colors.add(new XSLFColor(phClrDuo, theme, phClr, sheet).getColorStyle()); + } + return colors; + } + + private static Insets2D getRectVal(CTRelativeRect rect) { return rect == null ? null : new Insets2D( getRectVal(rect::isSetT, rect::getT), 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 929839b96d..8744b80690 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTheme.java @@ -20,8 +20,6 @@ import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; import java.io.IOException; import java.io.OutputStream; -import java.util.HashMap; -import java.util.Map; import javax.xml.namespace.QName; @@ -30,27 +28,21 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.util.Beta; import org.apache.poi.util.Internal; import org.apache.xmlbeans.XmlException; -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; /** * A shared style sheet in a .pptx slide show - * - * @author Yegor Kozlov */ @Beta public class XSLFTheme extends POIXMLDocumentPart { private CTOfficeStyleSheet _theme; - private Map _schemeColors; XSLFTheme() { - super(); _theme = CTOfficeStyleSheet.Factory.newInstance(); } @@ -62,37 +54,11 @@ public class XSLFTheme extends POIXMLDocumentPart { ThemeDocument doc = ThemeDocument.Factory.parse(getPackagePart().getInputStream(), DEFAULT_XML_OPTIONS); _theme = doc.getTheme(); - initialize(); } @SuppressWarnings("WeakerAccess") public void importTheme(XSLFTheme theme) { _theme = theme.getXmlObject(); - _schemeColors = theme._schemeColors; - } - - private void initialize(){ - CTBaseStyles elems = _theme.getThemeElements(); - CTColorScheme scheme = elems.getClrScheme(); - // The color scheme is responsible for defining a list of twelve colors. - _schemeColors = new HashMap<>(12); - for(XmlObject o : scheme.selectPath("*")){ - CTColor c = (CTColor)o; - String name = c.getDomNode().getLocalName(); - _schemeColors.put(name, c); - } - } - - /** - * 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())); } /** @@ -118,8 +84,45 @@ public class XSLFTheme extends POIXMLDocumentPart { * @return a theme color or null if not found */ @Internal - public CTColor getCTColor(String name){ - return _schemeColors.get(name); + public CTColor getCTColor(String name) { + CTBaseStyles elems = _theme.getThemeElements(); + CTColorScheme scheme = (elems == null) ? null : elems.getClrScheme(); + return getMapColor(name, scheme); + } + + + private static CTColor getMapColor(String mapName, CTColorScheme scheme) { + if (mapName == null || scheme == null) { + return null; + } + switch (mapName) { + case "accent1": + return scheme.getAccent1(); + case "accent2": + return scheme.getAccent2(); + case "accent3": + return scheme.getAccent3(); + case "accent4": + return scheme.getAccent4(); + case "accent5": + return scheme.getAccent5(); + case "accent6": + return scheme.getAccent6(); + case "dk1": + return scheme.getDk1(); + case "dk2": + return scheme.getDk2(); + case "folHlink": + return scheme.getFolHlink(); + case "hlink": + return scheme.getHlink(); + case "lt1": + return scheme.getLt1(); + case "lt2": + return scheme.getLt2(); + default: + return null; + } } /** 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 a862c16b44..cfadb58cc0 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java @@ -40,7 +40,7 @@ public class TestXSLFColor { CTSRgbColor c = xml.addNewSrgbClr(); c.setVal(new byte[]{(byte)0xFF, 0, 0}); - XSLFColor color = new XSLFColor(xml, null, null); + XSLFColor color = new XSLFColor(xml, null, null, null); assertEquals(-1, color.getAlpha()); c.addNewAlpha().setVal(50000); @@ -103,7 +103,7 @@ public class TestXSLFColor { c.setSat2(100000); c.setLum2(50000); - XSLFColor color = new XSLFColor(xml, null, null); + XSLFColor color = new XSLFColor(xml, null, null, null); assertEquals(Color.BLUE, color.getColor()); } @@ -112,31 +112,32 @@ public class TestXSLFColor { CTColor xml = CTColor.Factory.newInstance(); xml.addNewSrgbClr().setVal(new byte[]{ (byte)0xFF, (byte)0xFF, 0}); - XSLFColor color = new XSLFColor(xml, null, null); + XSLFColor color = new XSLFColor(xml, null, null, null); assertEquals(new Color(0xFF, 0xFF, 0), color.getColor()); } @Test public void testSchemeColor() throws IOException { XMLSlideShow ppt = new XMLSlideShow(); - XSLFTheme theme = ppt.createSlide().getTheme(); + XSLFSheet slide = ppt.createSlide(); + XSLFTheme theme = slide.getTheme(); CTColor xml = CTColor.Factory.newInstance(); xml.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_2); - XSLFColor color = new XSLFColor(xml, theme, null); + XSLFColor color = new XSLFColor(xml, theme, null, slide); // 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, null); + color = new XSLFColor(xml, theme, null, slide); // assertEquals(Color.decode("0xFFFFFF"), color.getColor()); xml = CTColor.Factory.newInstance(); xml.addNewSchemeClr().setVal(STSchemeColorVal.DK_1); - color = new XSLFColor(xml, theme, null); + color = new XSLFColor(xml, theme, null, slide); // assertEquals(Color.decode("0x000000"), color.getColor()); @@ -147,7 +148,7 @@ public class TestXSLFColor { public void testPresetColor() { CTColor xml = CTColor.Factory.newInstance(); xml.addNewPrstClr().setVal(STPresetColorVal.AQUAMARINE); - XSLFColor color = new XSLFColor(xml, null, null); + XSLFColor color = new XSLFColor(xml, null, null, null); assertEquals(new Color(127, 255, 212), color.getColor()); @@ -162,7 +163,7 @@ public class TestXSLFColor { } else { xml.addNewSysClr().setVal(sysVal); } - color = new XSLFColor(xml, null, null); + color = new XSLFColor(xml, null, null, null); assertEquals(pc.color, color.getColor()); } } @@ -172,13 +173,13 @@ public class TestXSLFColor { CTColor xml = CTColor.Factory.newInstance(); CTSystemColor sys = xml.addNewSysClr(); sys.setVal(STSystemColorVal.CAPTION_TEXT); - XSLFColor color = new XSLFColor(xml, null, null); + XSLFColor color = new XSLFColor(xml, null, null, null); assertEquals(Color.black, color.getColor()); xml = CTColor.Factory.newInstance(); sys = xml.addNewSysClr(); sys.setLastClr(new byte[]{(byte)0xFF, 0, 0}); - color = new XSLFColor(xml, null, null); + color = new XSLFColor(xml, null, null, null); assertEquals(Color.red, color.getColor()); } } \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java index 7923ced34a..ba9d1495bc 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java @@ -41,7 +41,25 @@ import org.apache.poi.hslf.model.textproperties.TextPFException9; import org.apache.poi.hslf.model.textproperties.TextProp; import org.apache.poi.hslf.model.textproperties.TextPropCollection; import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType; -import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.record.ColorSchemeAtom; +import org.apache.poi.hslf.record.EscherTextboxWrapper; +import org.apache.poi.hslf.record.InteractiveInfo; +import org.apache.poi.hslf.record.MasterTextPropAtom; +import org.apache.poi.hslf.record.OutlineTextRefAtom; +import org.apache.poi.hslf.record.PPDrawing; +import org.apache.poi.hslf.record.RecordContainer; +import org.apache.poi.hslf.record.RecordTypes; +import org.apache.poi.hslf.record.RoundTripHFPlaceholder12; +import org.apache.poi.hslf.record.SlideListWithText; +import org.apache.poi.hslf.record.SlidePersistAtom; +import org.apache.poi.hslf.record.StyleTextProp9Atom; +import org.apache.poi.hslf.record.StyleTextPropAtom; +import org.apache.poi.hslf.record.TextBytesAtom; +import org.apache.poi.hslf.record.TextCharsAtom; +import org.apache.poi.hslf.record.TextHeaderAtom; +import org.apache.poi.hslf.record.TextRulerAtom; +import org.apache.poi.hslf.record.TextSpecInfoAtom; +import org.apache.poi.hslf.record.TxInteractiveInfoAtom; import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.usermodel.AutoNumberingScheme; import org.apache.poi.sl.usermodel.PaintStyle; @@ -141,7 +159,7 @@ public final class HSLFTextParagraph implements TextParagraph