mirror of https://github.com/apache/poi.git
#64088 - SlideShow rendering fixes
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1872984 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5927fd37f2
commit
0fb322bb92
|
@ -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<ImageTypeSpecifier> 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);
|
||||
|
|
|
@ -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<ColorStyle> 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<redSample.length; i++) {
|
||||
redSample[i] = gradSample[redSample[i] & 0xFF];
|
||||
}
|
||||
|
||||
DirectColorModel dcm = new DirectColorModel(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
|
||||
DataBufferInt dbi = new DataBufferInt(redSample, redSample.length);
|
||||
WritableRaster raster = Raster.createPackedRaster(dbi, pattern.getWidth(), pattern.getHeight(), pattern.getWidth(), new int[]{0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}, new Point());
|
||||
return new BufferedImage(dcm, raster, true, null);
|
||||
}
|
||||
|
||||
private static int[] linearBlendedColors(List<ColorStyle> 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 (mod != -1) {
|
||||
hsl[hslPart] *= mod / 100_000d;
|
||||
}
|
||||
if (off == -1) {
|
||||
off = 0;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
final Point2D pCenter = new Point2D.Double(anchor.getCenterX(), anchor.getCenterY());
|
||||
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 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<float[],Color[],Paint> 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<Color> 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<Float,Color> m = new TreeMap<>();
|
||||
for (int i = 0; i<fractions.length; i++) {
|
||||
// if fc is null, use transparent color to get color of background
|
||||
m.put(fractions[i], (styles[i] == null ? TRANSPARENT : applyColorTransform(styles[i])));
|
||||
for (float fraction : fill.getGradientFractions()) {
|
||||
m.put(fraction, styles.next());
|
||||
}
|
||||
|
||||
final Color[] colors = new Color[m.size()];
|
||||
if (fractions.length != m.size()) {
|
||||
fractions = new float[m.size()];
|
||||
}
|
||||
return init.apply(toArray(m.keySet()), m.values().toArray(new Color[0]));
|
||||
}
|
||||
|
||||
int i=0;
|
||||
for (Map.Entry<Float,Color> me : m.entrySet()) {
|
||||
fractions[i] = me.getKey();
|
||||
colors[i] = me.getValue();
|
||||
i++;
|
||||
}
|
||||
|
||||
return init.apply(fractions, colors);
|
||||
private static float[] toArray(Collection<Float> floatList) {
|
||||
int[] idx = { 0 };
|
||||
float[] ret = new float[floatList.size()];
|
||||
floatList.forEach(f -> ret[idx[0]++] = f);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<ColorStyle> getDuoTone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
return new XSLFColorStyle(_xmlObject, _color, _phClr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlpha() {
|
||||
return getRawValue("alpha");
|
||||
}
|
||||
private Color toColor(CTHslColor hsl) {
|
||||
return DrawPaint.HSL2RGB(
|
||||
hsl.getHue2() / 60000d,
|
||||
hsl.getSat2() / 1000d,
|
||||
hsl.getLum2() / 1000d,
|
||||
1d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHueOff() {
|
||||
return getRawValue("hueOff");
|
||||
}
|
||||
private Color toColor(CTPresetColor prst) {
|
||||
String colorName = prst.getVal().toString();
|
||||
PresetColor pc = PresetColor.valueOfOoxmlId(colorName);
|
||||
return (pc != null) ? pc.color : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHueMod() {
|
||||
return getRawValue("hueMod");
|
||||
}
|
||||
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 getSatOff() {
|
||||
return getRawValue("satOff");
|
||||
}
|
||||
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 getSatMod() {
|
||||
return getRawValue("satMod");
|
||||
}
|
||||
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 getLumOff() {
|
||||
return getRawValue("lumOff");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLumMod() {
|
||||
return getRawValue("lumMod");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getShade() {
|
||||
return getRawValue("shade");
|
||||
}
|
||||
|
||||
@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<XmlObject> 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ implements Notes<XSLFShape,XSLFTextParagraph> {
|
|||
* Create a new notes
|
||||
*/
|
||||
XSLFNotes() {
|
||||
super();
|
||||
_notes = prototype();
|
||||
}
|
||||
|
||||
|
@ -105,4 +104,9 @@ implements Notes<XSLFShape,XSLFTextParagraph> {
|
|||
}
|
||||
return tp;
|
||||
}
|
||||
|
||||
@Override
|
||||
String mapSchemeColor(String schemeColor) {
|
||||
return mapSchemeColor(_notes.getClrMapOvr(), schemeColor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -61,11 +61,11 @@ public class XSLFShadow extends XSLFShape implements Shadow<XSLFShape,XSLFTextPa
|
|||
*/
|
||||
public double getDistance(){
|
||||
CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
|
||||
return ct.isSetDist() ? Units.toPoints(ct.getDist()) : 0;
|
||||
return ct.isSetDist() ? Units.toPoints(ct.getDist()) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return the direction to offset the shadow in angles
|
||||
*/
|
||||
public double getAngle(){
|
||||
|
@ -74,9 +74,9 @@ public class XSLFShadow extends XSLFShape implements Shadow<XSLFShape,XSLFTextPa
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return the blur radius of the shadow
|
||||
* TODO: figure out how to make sense of this property when rendering shadows
|
||||
* TODO: figure out how to make sense of this property when rendering shadows
|
||||
*/
|
||||
public double getBlur(){
|
||||
CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
|
||||
|
@ -84,7 +84,7 @@ public class XSLFShadow extends XSLFShape implements Shadow<XSLFShape,XSLFTextPa
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the color of this shadow.
|
||||
* @return the color of this shadow.
|
||||
* Depending whether the parent shape is filled or stroked, this color is used to fill or stroke this shadow
|
||||
*/
|
||||
public Color getFillColor() {
|
||||
|
@ -98,9 +98,9 @@ public class XSLFShadow extends XSLFShape implements Shadow<XSLFShape,XSLFTextPa
|
|||
XSLFTheme theme = getSheet().getTheme();
|
||||
CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
|
||||
if(ct == null) return null;
|
||||
|
||||
|
||||
CTSchemeColor phClr = ct.getSchemeClr();
|
||||
final XSLFColor xc = new XSLFColor(ct, theme, phClr);
|
||||
final XSLFColor xc = new XSLFColor(ct, theme, phClr, getSheet());
|
||||
return DrawPaint.createSolidPaint(xc.getColorStyle());
|
||||
}
|
||||
}
|
|
@ -144,7 +144,7 @@ public abstract class XSLFShape implements Shape<XSLFShape,XSLFTextParagraph> {
|
|||
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<XSLFShape,XSLFTextParagraph> {
|
|||
* @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<XSLFShape,XSLFTextParagraph> {
|
|||
}
|
||||
|
||||
@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<XSLFShape,XSLFTextParagraph> {
|
|||
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<XSLFShape,XSLFTextParagraph> {
|
|||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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<XSLFShape,XSLFTextParagraph> {
|
|||
return _theme;
|
||||
}
|
||||
|
||||
final Optional<XSLFTheme> 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<XSLFShape,XSLFTextParagraph> {
|
|||
/**
|
||||
* @return the color mapping for this slide type
|
||||
*/
|
||||
CTColorMapping getColorMapping() {
|
||||
String mapSchemeColor(String schemeColor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -744,4 +741,60 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<XSLFShape,XSLFTextParagraph> {
|
|||
public boolean getFollowMasterObjects() {
|
||||
return getFollowMasterGraphics();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setFollowMasterObjects(boolean follow) {
|
||||
setFollowMasterGraphics(follow);
|
||||
|
@ -328,7 +328,7 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
|
|||
public boolean getFollowMasterBackground() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotImplemented
|
||||
public void setFollowMasterBackground(boolean follow) {
|
||||
|
@ -340,7 +340,7 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
|
|||
public boolean getFollowMasterColourScheme() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@NotImplemented
|
||||
public void setFollowMasterColourScheme(boolean follow) {
|
||||
|
@ -378,7 +378,7 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void setHidden(boolean hidden) {
|
||||
CTSlide sld = getXmlObject();
|
||||
|
@ -391,7 +391,7 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
CTSlide sld = getXmlObject();
|
||||
|
@ -403,4 +403,9 @@ implements Slide<XSLFShape,XSLFTextParagraph> {
|
|||
final CTCommonSlideData cSld = getXmlObject().getCSld();
|
||||
return cSld.isSetName() ? cSld.getName() : "Slide"+getSlideNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
String mapSchemeColor(String schemeColor) {
|
||||
return mapSchemeColor(_slide.getClrMapOvr(), schemeColor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,4 +145,10 @@ implements MasterSheet<XSLFShape,XSLFTextParagraph> {
|
|||
int ordinal = _layout.getType().intValue() - 1;
|
||||
return SlideLayout.values()[ordinal];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
String mapSchemeColor(String schemeColor) {
|
||||
return mapSchemeColor(_layout.getClrMapOvr(), schemeColor);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<XSLFShape,
|
|||
|
||||
CTLineProperties ln = setBorderDefaults(edge);
|
||||
CTSolidColorFillProperties fill = ln.addNewSolidFill();
|
||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
|
||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr(), getSheet());
|
||||
c.setColor(color);
|
||||
}
|
||||
|
||||
|
@ -331,7 +305,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
|
|||
}
|
||||
|
||||
CTSolidColorFillProperties fill = ln.getSolidFill();
|
||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
|
||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr(), getSheet());
|
||||
return c.getColor();
|
||||
}
|
||||
|
||||
|
@ -415,7 +389,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
|
|||
}
|
||||
} else {
|
||||
CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill();
|
||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr());
|
||||
XSLFColor c = new XSLFColor(fill, getSheet().getTheme(), fill.getSchemeClr(), getSheet());
|
||||
c.setColor(color);
|
||||
}
|
||||
}
|
||||
|
@ -470,7 +444,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
|
|||
|
||||
fp = XSLFPropertiesDelegate.getFillDelegate(props);
|
||||
if (fp != null) {
|
||||
PaintStyle paint = XSLFShape.selectPaint(fp, null, slideShow.getPackagePart(), theme, hasPlaceholder);
|
||||
PaintStyle paint = selectPaint(fp, null, slideShow.getPackagePart(), theme, hasPlaceholder);
|
||||
if (paint != null) {
|
||||
return paint;
|
||||
}
|
||||
|
@ -758,7 +732,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
|
|||
}
|
||||
|
||||
XSLFTheme theme = getSheet().getTheme();
|
||||
final XSLFColor c = new XSLFColor(txStyle, theme, phClr);
|
||||
final XSLFColor c = new XSLFColor(txStyle, theme, phClr, getSheet());
|
||||
return DrawPaint.createSolidPaint(c.getColorStyle());
|
||||
}
|
||||
|
||||
|
|
|
@ -279,7 +279,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
|
|||
@Override
|
||||
public boolean fetch(CTTextParagraphProperties props){
|
||||
if(props.isSetBuClr()){
|
||||
XSLFColor c = new XSLFColor(props.getBuClr(), theme, null);
|
||||
XSLFColor c = new XSLFColor(props.getBuClr(), theme, null, _shape.getSheet());
|
||||
setValue(c.getColor());
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -123,7 +123,8 @@ public class XSLFTextRun implements TextRun {
|
|||
CTTextCharacterProperties rPr = getRPr(true);
|
||||
CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill();
|
||||
|
||||
XSLFColor col = new XSLFColor(fill, getParentParagraph().getParentShape().getSheet().getTheme(), fill.getSchemeClr());
|
||||
XSLFSheet sheet = getParentParagraph().getParentShape().getSheet();
|
||||
XSLFColor col = new XSLFColor(fill, sheet.getTheme(), fill.getSchemeClr(), sheet);
|
||||
col.setColor(c);
|
||||
}
|
||||
|
||||
|
@ -148,7 +149,7 @@ public class XSLFTextRun implements TextRun {
|
|||
XSLFSheet sheet = shape.getSheet();
|
||||
PackagePart pp = sheet.getPackagePart();
|
||||
XSLFTheme theme = sheet.getTheme();
|
||||
PaintStyle ps = XSLFShape.selectPaint(fp, phClr, pp, theme, hasPlaceholder);
|
||||
PaintStyle ps = shape.selectPaint(fp, phClr, pp, theme, hasPlaceholder);
|
||||
|
||||
if (ps != null) {
|
||||
setValue(ps);
|
||||
|
|
|
@ -21,11 +21,14 @@ import java.awt.geom.Dimension2D;
|
|||
import java.awt.geom.Point2D;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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.ColorStyle;
|
||||
import org.apache.poi.sl.usermodel.Insets2D;
|
||||
import org.apache.poi.sl.usermodel.PaintStyle;
|
||||
import org.apache.poi.util.Dimension2DDouble;
|
||||
|
@ -33,7 +36,9 @@ 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.CTDuotoneEffect;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTRelativeRect;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTileInfoProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTileFlipMode;
|
||||
|
||||
|
@ -42,11 +47,17 @@ public class XSLFTexturePaint implements PaintStyle.TexturePaint {
|
|||
private final CTBlipFillProperties blipFill;
|
||||
private final PackagePart parentPart;
|
||||
private final CTBlip blip;
|
||||
private final CTSchemeColor phClr;
|
||||
private final XSLFTheme theme;
|
||||
private final XSLFSheet sheet;
|
||||
|
||||
public XSLFTexturePaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) {
|
||||
public XSLFTexturePaint(final CTBlipFillProperties blipFill, final PackagePart parentPart, CTSchemeColor phClr, final XSLFTheme theme, final XSLFSheet sheet) {
|
||||
this.blipFill = blipFill;
|
||||
this.parentPart = parentPart;
|
||||
blip = blipFill.getBlip();
|
||||
this.phClr = phClr;
|
||||
this.theme = theme;
|
||||
this.sheet = sheet;
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,6 +150,20 @@ public class XSLFTexturePaint implements PaintStyle.TexturePaint {
|
|||
return getRectVal(blipFill.isSetStretch() ? blipFill.getStretch().getFillRect() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ColorStyle> getDuoTone() {
|
||||
if (blip.sizeOfDuotoneArray() == 0) {
|
||||
return null;
|
||||
}
|
||||
List<ColorStyle> 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),
|
||||
|
|
|
@ -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<String, CTColor> _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 <code>null</code> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 <a:srgbClr val="C0504D"/>
|
||||
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);
|
||||
// <a:sysClr val="window" lastClr="FFFFFF"/>
|
||||
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);
|
||||
// <a:sysClr val="windowText" lastClr="000000"/>
|
||||
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());
|
||||
}
|
||||
}
|
|
@ -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<HSLFShape,HSLFText
|
|||
_byteAtom = tba;
|
||||
_charAtom = tca;
|
||||
this.parentList = parentList;
|
||||
_paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
|
||||
setParagraphStyle(new TextPropCollection(1, TextPropType.paragraph));
|
||||
}
|
||||
|
||||
/* package */HSLFTextParagraph(HSLFTextParagraph other) {
|
||||
|
@ -152,8 +170,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
_sheet = other._sheet;
|
||||
_ruler = other._ruler;
|
||||
shapeId = other.shapeId;
|
||||
_paragraphStyle = other._paragraphStyle;
|
||||
parentList = other.parentList;
|
||||
setParagraphStyle(other._paragraphStyle);
|
||||
}
|
||||
|
||||
public void addTextRun(HSLFTextRun run) {
|
||||
|
|
Loading…
Reference in New Issue