#62949 - SlideShow rendering - keyframe fractions must be increasing
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1847428 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
43e30f090b
commit
8b781ed03e
@ -29,7 +29,10 @@ import java.awt.geom.Rectangle2D;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import org.apache.poi.sl.usermodel.AbstractColorStyle;
|
import org.apache.poi.sl.usermodel.AbstractColorStyle;
|
||||||
import org.apache.poi.sl.usermodel.ColorStyle;
|
import org.apache.poi.sl.usermodel.ColorStyle;
|
||||||
@ -197,28 +200,17 @@ public class DrawPaint {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getShade() {
|
public int getShade() {
|
||||||
int shade = orig.getShade();
|
return scale(orig.getShade(), PaintModifier.DARKEN_LESS, PaintModifier.DARKEN);
|
||||||
switch (modifier) {
|
|
||||||
case DARKEN:
|
|
||||||
return Math.min(100000, Math.max(0,shade)+40000);
|
|
||||||
case DARKEN_LESS:
|
|
||||||
return Math.min(100000, Math.max(0,shade)+20000);
|
|
||||||
default:
|
|
||||||
return shade;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTint() {
|
public int getTint() {
|
||||||
int tint = orig.getTint();
|
return scale(orig.getTint(), PaintModifier.LIGHTEN_LESS, PaintModifier.LIGHTEN);
|
||||||
switch (modifier) {
|
}
|
||||||
case LIGHTEN:
|
|
||||||
return Math.min(100000, Math.max(0,tint)+40000);
|
private int scale(int value, PaintModifier lessModifier, PaintModifier moreModifier) {
|
||||||
case LIGHTEN_LESS:
|
int delta = (modifier == lessModifier ? 20000 : (modifier == moreModifier ? 40000 : 0));
|
||||||
return Math.min(100000, Math.max(0,tint)+20000);
|
return Math.min(100000, Math.max(0,value)+delta);
|
||||||
default:
|
|
||||||
return tint;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -300,7 +292,7 @@ public class DrawPaint {
|
|||||||
Color result = color.getColor();
|
Color result = color.getColor();
|
||||||
|
|
||||||
double alpha = getAlpha(result, color);
|
double alpha = getAlpha(result, color);
|
||||||
double hsl[] = RGB2HSL(result); // values are in the range [0..100] (usually ...)
|
double[] hsl = RGB2HSL(result); // values are in the range [0..100] (usually ...)
|
||||||
applyHslModOff(hsl, 0, color.getHueMod(), color.getHueOff());
|
applyHslModOff(hsl, 0, color.getHueMod(), color.getHueOff());
|
||||||
applyHslModOff(hsl, 1, color.getSatMod(), color.getSatOff());
|
applyHslModOff(hsl, 1, color.getSatMod(), color.getSatOff());
|
||||||
applyHslModOff(hsl, 2, color.getLumMod(), color.getLumOff());
|
applyHslModOff(hsl, 2, color.getLumMod(), color.getLumOff());
|
||||||
@ -344,7 +336,7 @@ public class DrawPaint {
|
|||||||
* @param mod the modulation adjustment
|
* @param mod the modulation adjustment
|
||||||
* @param off the offset adjustment
|
* @param off the offset adjustment
|
||||||
*/
|
*/
|
||||||
private static void applyHslModOff(double hsl[], int hslPart, int mod, int off) {
|
private static void applyHslModOff(double[] hsl, int hslPart, int mod, int off) {
|
||||||
if (mod == -1) {
|
if (mod == -1) {
|
||||||
mod = 100000;
|
mod = 100000;
|
||||||
}
|
}
|
||||||
@ -363,7 +355,7 @@ public class DrawPaint {
|
|||||||
*
|
*
|
||||||
* For a shade, the equation is luminance * %tint.
|
* For a shade, the equation is luminance * %tint.
|
||||||
*/
|
*/
|
||||||
private static void applyShade(double hsl[], ColorStyle fc) {
|
private static void applyShade(double[] hsl, ColorStyle fc) {
|
||||||
int shade = fc.getShade();
|
int shade = fc.getShade();
|
||||||
if (shade == -1) {
|
if (shade == -1) {
|
||||||
return;
|
return;
|
||||||
@ -380,7 +372,7 @@ public class DrawPaint {
|
|||||||
* For a tint, the equation is luminance * %tint + (1-%tint).
|
* For a tint, the equation is luminance * %tint + (1-%tint).
|
||||||
* (Note that 1-%tint is equal to the lumOff value in DrawingML.)
|
* (Note that 1-%tint is equal to the lumOff value in DrawingML.)
|
||||||
*/
|
*/
|
||||||
private static void applyTint(double hsl[], ColorStyle fc) {
|
private static void applyTint(double[] hsl, ColorStyle fc) {
|
||||||
int tint = fc.getTint();
|
int tint = fc.getTint();
|
||||||
if (tint == -1) {
|
if (tint == -1) {
|
||||||
return;
|
return;
|
||||||
@ -403,70 +395,63 @@ public class DrawPaint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
|
Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
|
||||||
final double h = anchor.getHeight(), w = anchor.getWidth(), x = anchor.getX(), y = anchor.getY();
|
|
||||||
|
|
||||||
AffineTransform at = AffineTransform.getRotateInstance(Math.toRadians(angle), anchor.getCenterX(), anchor.getCenterY());
|
AffineTransform at = AffineTransform.getRotateInstance(Math.toRadians(angle), anchor.getCenterX(), anchor.getCenterY());
|
||||||
|
|
||||||
double diagonal = Math.sqrt(h * h + w * w);
|
double diagonal = Math.sqrt(Math.pow(anchor.getWidth(),2) + Math.pow(anchor.getHeight(),2));
|
||||||
Point2D p1 = new Point2D.Double(x + w / 2 - diagonal / 2, y + h / 2);
|
final Point2D p1 = at.transform(new Point2D.Double(anchor.getCenterX() - diagonal / 2, anchor.getCenterY()), null);
|
||||||
p1 = at.transform(p1, null);
|
final Point2D p2 = at.transform(new Point2D.Double(anchor.getMaxX(), anchor.getCenterY()), null);
|
||||||
|
|
||||||
Point2D p2 = new Point2D.Double(x + w, y + h / 2);
|
|
||||||
p2 = at.transform(p2, null);
|
|
||||||
|
|
||||||
// snapToAnchor(p1, anchor);
|
// snapToAnchor(p1, anchor);
|
||||||
// snapToAnchor(p2, anchor);
|
// snapToAnchor(p2, anchor);
|
||||||
|
|
||||||
if (p1.equals(p2)) {
|
// gradient paint on the same point throws an exception ... and doesn't make sense
|
||||||
// gradient paint on the same point throws an exception ... and doesn't make sense
|
return (p1.equals(p2)) ? null : safeFractions((f,c)->new LinearGradientPaint(p1,p2,f,c), fill);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
float[] fractions = fill.getGradientFractions();
|
|
||||||
Color[] colors = new Color[fractions.length];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (ColorStyle fc : fill.getGradientColors()) {
|
|
||||||
// if fc is null, use transparent color to get color of background
|
|
||||||
colors[i++] = (fc == null) ? TRANSPARENT : applyColorTransform(fc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LinearGradientPaint(p1, p2, fractions, colors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
protected Paint createRadialGradientPaint(GradientPaint fill, Graphics2D graphics) {
|
protected Paint createRadialGradientPaint(GradientPaint fill, Graphics2D graphics) {
|
||||||
Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
|
Rectangle2D anchor = DrawShape.getAnchor(graphics, shape);
|
||||||
|
|
||||||
Point2D pCenter = new Point2D.Double(anchor.getX() + anchor.getWidth()/2,
|
final Point2D pCenter = new Point2D.Double(anchor.getCenterX(), anchor.getCenterY());
|
||||||
anchor.getY() + anchor.getHeight()/2);
|
|
||||||
|
|
||||||
float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight());
|
final float radius = (float)Math.max(anchor.getWidth(), anchor.getHeight());
|
||||||
|
|
||||||
float[] fractions = fill.getGradientFractions();
|
return safeFractions((f,c)->new RadialGradientPaint(pCenter,radius,f,c), fill);
|
||||||
Color[] colors = new Color[fractions.length];
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
for (ColorStyle fc : fill.getGradientColors()) {
|
|
||||||
colors[i++] = applyColorTransform(fc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RadialGradientPaint(pCenter, radius, fractions, colors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||||
protected Paint createPathGradientPaint(GradientPaint fill, Graphics2D graphics) {
|
protected Paint createPathGradientPaint(GradientPaint fill, Graphics2D graphics) {
|
||||||
// currently we ignore an eventually center setting
|
// currently we ignore an eventually center setting
|
||||||
|
|
||||||
float[] fractions = fill.getGradientFractions();
|
return safeFractions(PathGradientPaint::new, fill);
|
||||||
Color[] colors = new Color[fractions.length];
|
}
|
||||||
|
|
||||||
int i=0;
|
private Paint safeFractions(BiFunction<float[],Color[],Paint> init, GradientPaint fill) {
|
||||||
for (ColorStyle fc : fill.getGradientColors()) {
|
float[] fractions = fill.getGradientFractions();
|
||||||
colors[i++] = applyColorTransform(fc);
|
final ColorStyle[] styles = fill.getGradientColors();
|
||||||
|
|
||||||
|
// 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])));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PathGradientPaint(colors, fractions);
|
final Color[] colors = new Color[m.size()];
|
||||||
|
if (fractions.length != m.size()) {
|
||||||
|
fractions = new float[m.size()];
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,21 +23,24 @@ import java.awt.MultipleGradientPaint.CycleMethod;
|
|||||||
import java.awt.geom.*;
|
import java.awt.geom.*;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
|
@Internal
|
||||||
class PathGradientPaint implements Paint {
|
class PathGradientPaint implements Paint {
|
||||||
|
|
||||||
// http://asserttrue.blogspot.de/2010/01/how-to-iimplement-custom-paint-in-50.html
|
// http://asserttrue.blogspot.de/2010/01/how-to-iimplement-custom-paint-in-50.html
|
||||||
protected final Color colors[];
|
private final Color[] colors;
|
||||||
protected final float fractions[];
|
private final float[] fractions;
|
||||||
protected final int capStyle;
|
private final int capStyle;
|
||||||
protected final int joinStyle;
|
private final int joinStyle;
|
||||||
protected final int transparency;
|
private final int transparency;
|
||||||
|
|
||||||
|
|
||||||
public PathGradientPaint(Color colors[], float fractions[]) {
|
PathGradientPaint(float[] fractions, Color[] colors) {
|
||||||
this(colors,fractions,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
|
this(fractions,colors,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PathGradientPaint(Color colors[], float fractions[], int capStyle, int joinStyle) {
|
private PathGradientPaint(float[] fractions, Color[] colors, int capStyle, int joinStyle) {
|
||||||
this.colors = colors.clone();
|
this.colors = colors.clone();
|
||||||
this.fractions = fractions.clone();
|
this.fractions = fractions.clone();
|
||||||
this.capStyle = capStyle;
|
this.capStyle = capStyle;
|
||||||
@ -66,26 +69,26 @@ class PathGradientPaint implements Paint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PathGradientContext implements PaintContext {
|
class PathGradientContext implements PaintContext {
|
||||||
protected final Rectangle deviceBounds;
|
final Rectangle deviceBounds;
|
||||||
protected final Rectangle2D userBounds;
|
final Rectangle2D userBounds;
|
||||||
protected final AffineTransform xform;
|
protected final AffineTransform xform;
|
||||||
protected final RenderingHints hints;
|
final RenderingHints hints;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for POI: the shape will be only known when the subclasses determines the concrete implementation
|
* for POI: the shape will be only known when the subclasses determines the concrete implementation
|
||||||
* in the draw/-content method, so we need to postpone the setting/creation as long as possible
|
* in the draw/-content method, so we need to postpone the setting/creation as long as possible
|
||||||
**/
|
**/
|
||||||
protected final Shape shape;
|
protected final Shape shape;
|
||||||
protected final PaintContext pCtx;
|
final PaintContext pCtx;
|
||||||
protected final int gradientSteps;
|
final int gradientSteps;
|
||||||
WritableRaster raster;
|
WritableRaster raster;
|
||||||
|
|
||||||
public PathGradientContext(
|
PathGradientContext(
|
||||||
ColorModel cm
|
ColorModel cm
|
||||||
, Rectangle deviceBounds
|
, Rectangle deviceBounds
|
||||||
, Rectangle2D userBounds
|
, Rectangle2D userBounds
|
||||||
, AffineTransform xform
|
, AffineTransform xform
|
||||||
, RenderingHints hints
|
, RenderingHints hints
|
||||||
) {
|
) {
|
||||||
shape = (Shape)hints.get(Drawable.GRADIENT_SHAPE);
|
shape = (Shape)hints.get(Drawable.GRADIENT_SHAPE);
|
||||||
if (shape == null) {
|
if (shape == null) {
|
||||||
@ -139,7 +142,7 @@ class PathGradientPaint implements Paint {
|
|||||||
return childRaster;
|
return childRaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getGradientSteps(Shape gradientShape) {
|
int getGradientSteps(Shape gradientShape) {
|
||||||
Rectangle rect = gradientShape.getBounds();
|
Rectangle rect = gradientShape.getBounds();
|
||||||
int lower = 1;
|
int lower = 1;
|
||||||
int upper = (int)(Math.max(rect.getWidth(),rect.getHeight())/2.0);
|
int upper = (int)(Math.max(rect.getWidth(),rect.getHeight())/2.0);
|
||||||
@ -158,7 +161,7 @@ class PathGradientPaint implements Paint {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected void createRaster() {
|
void createRaster() {
|
||||||
ColorModel cm = getColorModel();
|
ColorModel cm = getColorModel();
|
||||||
raster = cm.createCompatibleWritableRaster((int)deviceBounds.getWidth(), (int)deviceBounds.getHeight());
|
raster = cm.createCompatibleWritableRaster((int)deviceBounds.getWidth(), (int)deviceBounds.getHeight());
|
||||||
BufferedImage img = new BufferedImage(cm, raster, false, null);
|
BufferedImage img = new BufferedImage(cm, raster, false, null);
|
||||||
@ -168,7 +171,7 @@ class PathGradientPaint implements Paint {
|
|||||||
graphics.transform(xform);
|
graphics.transform(xform);
|
||||||
|
|
||||||
Raster img2 = pCtx.getRaster(0, 0, gradientSteps, 1);
|
Raster img2 = pCtx.getRaster(0, 0, gradientSteps, 1);
|
||||||
int rgb[] = new int[cm.getNumComponents()];
|
int[] rgb = new int[cm.getNumComponents()];
|
||||||
|
|
||||||
for (int i = gradientSteps-1; i>=0; i--) {
|
for (int i = gradientSteps-1; i>=0; i--) {
|
||||||
img2.getPixel(i, 0, rgb);
|
img2.getPixel(i, 0, rgb);
|
||||||
|
@ -47,7 +47,7 @@ public class TestPPTX2PNG {
|
|||||||
private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
|
private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
|
||||||
private static final File basedir = null;
|
private static final File basedir = null;
|
||||||
private static final String files =
|
private static final String files =
|
||||||
"53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt";
|
"53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.ppt";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BIN
test-data/slideshow/keyframes.ppt
Normal file
BIN
test-data/slideshow/keyframes.ppt
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user