#56519 - XSLFSlide.draw is not working with text embeded in PPTX

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1694925 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-08-09 22:44:13 +00:00
parent bdb00633a3
commit 750558d8d9
41 changed files with 1237 additions and 504 deletions

View File

@ -17,25 +17,31 @@
package org.apache.poi.sl.draw; package org.apache.poi.sl.draw;
import static org.apache.poi.sl.usermodel.PaintStyle.TRANSPARENT_PAINT; import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.*; import java.awt.LinearGradientPaint;
import java.awt.MultipleGradientPaint.ColorSpaceType; import java.awt.MultipleGradientPaint.ColorSpaceType;
import java.awt.MultipleGradientPaint.CycleMethod; import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.geom.*; import java.awt.Paint;
import java.awt.RadialGradientPaint;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.apache.poi.sl.usermodel.*; import org.apache.poi.sl.usermodel.ColorStyle;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
/** /**
* This class handles color transformations * This class handles color transformations.
* *
* @see <a href="https://tips4java.wordpress.com/2009/07/05/hsl-color/">HSL code taken from Java Tips Weblog</a> * @see <a href="https://tips4java.wordpress.com/2009/07/05/hsl-color/">HSL code taken from Java Tips Weblog</a>
*/ */
@ -50,19 +56,45 @@ public class DrawPaint {
this.shape = shape; this.shape = shape;
} }
public static SolidPaint createSolidPaint(final Color color) { private static class SimpleSolidPaint implements SolidPaint {
return new SolidPaint() { private final ColorStyle solidColor;
public ColorStyle getSolidColor() {
return new ColorStyle(){ SimpleSolidPaint(final Color color) {
if (color == null) {
throw new NullPointerException("Color needs to be specified");
}
this.solidColor = new ColorStyle(){
public Color getColor() { return color; } public Color getColor() { return color; }
public int getAlpha() { return -1; } public int getAlpha() { return -1; }
public int getHueOff() { return -1; }
public int getHueMod() { return -1; }
public int getSatOff() { return -1; }
public int getSatMod() { return -1; }
public int getLumOff() { return -1; } public int getLumOff() { return -1; }
public int getLumMod() { return -1; } public int getLumMod() { return -1; }
public int getShade() { return -1; } public int getShade() { return -1; }
public int getTint() { return -1; } public int getTint() { return -1; }
}; };
} }
};
SimpleSolidPaint(ColorStyle color) {
if (color == null) {
throw new NullPointerException("Color needs to be specified");
}
this.solidColor = color;
}
public ColorStyle getSolidColor() {
return solidColor;
}
}
public static SolidPaint createSolidPaint(final Color color) {
return (color == null) ? null : new SimpleSolidPaint(color);
}
public static SolidPaint createSolidPaint(final ColorStyle color) {
return (color == null) ? null : new SimpleSolidPaint(color);
} }
public Paint getPaint(Graphics2D graphics, PaintStyle paint) { public Paint getPaint(Graphics2D graphics, PaintStyle paint) {
@ -95,26 +127,26 @@ public class DrawPaint {
protected Paint getTexturePaint(TexturePaint fill, Graphics2D graphics) { protected Paint getTexturePaint(TexturePaint fill, Graphics2D graphics) {
InputStream is = fill.getImageData(); InputStream is = fill.getImageData();
if (is == null) return TRANSPARENT_PAINT.getSolidColor().getColor(); if (is == null) return null;
assert(graphics != null); assert(graphics != null);
ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER); ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);
if (renderer == null) renderer = new ImageRenderer(); if (renderer == null) renderer = new ImageRenderer();
try { try {
renderer.loadImage(fill.getImageData(), fill.getContentType()); renderer.loadImage(is, fill.getContentType());
is.close();
} catch (IOException e) { } catch (IOException e) {
LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e); LOG.log(POILogger.ERROR, "Can't load image data - using transparent color", e);
return TRANSPARENT_PAINT.getSolidColor().getColor(); return null;
} }
int alpha = fill.getAlpha(); int alpha = fill.getAlpha();
if (alpha != -1) { if (0 <= alpha && alpha < 100000) {
renderer.setAlpha(alpha/100000.f); renderer.setAlpha(alpha/100000.f);
} }
Dimension dim = renderer.getDimension(); Rectangle2D textAnchor = shape.getAnchor();
Rectangle2D textAnchor = new Rectangle2D.Double(0, 0, dim.getWidth(), dim.getHeight());
Paint paint = new java.awt.TexturePaint(renderer.getImage(), textAnchor); Paint paint = new java.awt.TexturePaint(renderer.getImage(), textAnchor);
return paint; return paint;
@ -122,106 +154,102 @@ public class DrawPaint {
/** /**
* Convert color transformations in {@link ColorStyle} to a {@link Color} instance * Convert color transformations in {@link ColorStyle} to a {@link Color} instance
*
* @see <a href="https://msdn.microsoft.com/en-us/library/dd560821%28v=office.12%29.aspx">Using Office Open XML to Customize Document Formatting in the 2007 Office System</a>
* @see <a href="https://social.msdn.microsoft.com/Forums/office/en-US/040e0a1f-dbfe-4ce5-826b-38b4b6f6d3f7/saturation-modulation-satmod">saturation modulation (satMod)</a>
* @see <a href="http://stackoverflow.com/questions/6754127/office-open-xml-satmod-results-in-more-than-100-saturation">Office Open XML satMod results in more than 100% saturation</a>
*/ */
public static Color applyColorTransform(ColorStyle color){ public static Color applyColorTransform(ColorStyle color){
// TODO: The colors don't match 100% the results of Powerpoint, maybe because we still
// operate in sRGB and not scRGB ... work in progress ...
Color result = color.getColor(); Color result = color.getColor();
if (result == null) return null;
if (result == null || color.getAlpha() == 100) { double alpha = getAlpha(result, color);
return TRANSPARENT_PAINT.getSolidColor().getColor(); double hsl[] = RGB2HSL(result); // values are in the range [0..100] (usually ...)
} applyHslModOff(hsl, 0, color.getHueMod(), color.getHueOff());
applyHslModOff(hsl, 1, color.getSatMod(), color.getSatOff());
applyHslModOff(hsl, 2, color.getLumMod(), color.getLumOff());
applyShade(hsl, color);
applyTint(hsl, color);
result = applyAlpha(result, color); result = HSL2RGB(hsl[0], hsl[1], hsl[2], alpha);
result = applyLuminance(result, color);
result = applyShade(result, color);
result = applyTint(result, color);
return result; return result;
} }
protected static Color applyAlpha(Color c, ColorStyle fc) { private static double getAlpha(Color c, ColorStyle fc) {
int alpha = c.getAlpha(); double alpha = c.getAlpha()/255d;
return (alpha == 255) ? c : new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha); int fcAlpha = fc.getAlpha();
if (fcAlpha != -1) {
alpha *= fcAlpha/100000d;
}
return Math.min(1, Math.max(0, alpha));
} }
/** /**
* Apply lumMod / lumOff adjustments * Apply the modulation and offset adjustments to the given HSL part
* *
* @param c the color to modify * Example for lumMod/lumOff:
* @param fc the color style containing the lumMod / lumOff adjustments * The lumMod value is the percent luminance. A lumMod value of "60000",
* @return modified color * is 60% of the luminance of the original color.
* When the color is a shade of the original theme color, the lumMod
* attribute is the only one of the tags shown here that appears.
* The <a:lumOff> tag appears after the <a:lumMod> tag when the color is a
* tint of the original. The lumOff value always equals 1-lumMod, which is used in the tint calculation
*
* Despite having different ways to display the tint and shade percentages,
* all of the programs use the same method to calculate the resulting color.
* Convert the original RGB value to HSL ... and then adjust the luminance (L)
* with one of the following equations before converting the HSL value back to RGB.
* (The % tint in the following equations refers to the tint, themetint, themeshade,
* or lumMod values, as applicable.)
*
* @param hsl the hsl values
* @param hslPart the hsl part to modify [0..2]
* @param mod the modulation adjustment
* @param off the offset adjustment
* @return the modified hsl value
* *
* @see <a href="https://msdn.microsoft.com/en-us/library/dd560821%28v=office.12%29.aspx">Using Office Open XML to Customize Document Formatting in the 2007 Office System</a>
*/ */
protected static Color applyLuminance(Color c, ColorStyle fc) { private static void applyHslModOff(double hsl[], int hslPart, int mod, int off) {
int lumMod = fc.getLumMod(); if (mod == -1) mod = 100000;
if (lumMod == -1) lumMod = 100000; if (off == -1) off = 0;
if (!(mod == 100000 && off == 0)) {
int lumOff = fc.getLumOff(); double fOff = off / 1000d;
if (lumOff == -1) lumOff = 0; double fMod = mod / 100000d;
hsl[hslPart] = hsl[hslPart]*fMod+fOff;
if (lumMod == 100000 && lumOff == 0) return c; }
// The lumMod value is the percent luminance. A lumMod value of "60000",
// is 60% of the luminance of the original color.
// When the color is a shade of the original theme color, the lumMod
// attribute is the only one of the tags shown here that appears.
// The <a:lumOff> tag appears after the <a:lumMod> tag when the color is a
// tint of the original. The lumOff value always equals 1-lumMod, which is used in the tint calculation
//
// Despite having different ways to display the tint and shade percentages,
// all of the programs use the same method to calculate the resulting color.
// Convert the original RGB value to HSL ... and then adjust the luminance (L)
// with one of the following equations before converting the HSL value back to RGB.
// (The % tint in the following equations refers to the tint, themetint, themeshade,
// or lumMod values, as applicable.)
//
// For a shade, the equation is luminance * %tint.
//
// For a tint, the equation is luminance * %tint + (1-%tint).
// (Note that 1-%tint is equal to the lumOff value in DrawingML.)
double fLumOff = lumOff / 100000d;
double fLumMod = lumMod / 100000d;
double hsl[] = RGB2HSL(c);
hsl[2] = hsl[2]*fLumMod+fLumOff;
Color c2 = HSL2RGB(hsl[0], hsl[1], hsl[2], c.getAlpha()/255d);
return c2;
} }
/** /**
* This algorithm returns result different from PowerPoint. * Apply the shade
* TODO: revisit and improve *
* For a shade, the equation is luminance * %tint.
*/ */
protected static Color applyShade(Color c, ColorStyle fc) { private static void applyShade(double hsl[], ColorStyle fc) {
int shade = fc.getShade(); int shade = fc.getShade();
if (shade == -1) return c; if (shade == -1) return;
float fshade = shade / 100000.f; double fshade = shade / 100000.d;
float red = c.getRed() * fshade; hsl[2] *= fshade;
float green = c.getGreen() * fshade;
float blue = c.getGreen() * fshade;
return new Color(Math.round(red), Math.round(green), Math.round(blue), c.getAlpha());
} }
/** /**
* This algorithm returns result different from PowerPoint. * Apply the tint
* TODO: revisit and improve *
* For a tint, the equation is luminance * %tint + (1-%tint).
* (Note that 1-%tint is equal to the lumOff value in DrawingML.)
*/ */
protected static Color applyTint(Color c, ColorStyle fc) { private static void applyTint(double hsl[], ColorStyle fc) {
int tint = fc.getTint(); int tint = fc.getTint();
if (tint == -1) return c; if (tint == -1) return;
float ftint = tint / 100000.f; double ftint = tint / 100000.f;
float red = ftint * c.getRed() + (1.f - ftint) * 255.f; hsl[2] = hsl[2] * ftint + (100 - ftint*100.);
float green = ftint * c.getGreen() + (1.f - ftint) * 255.f;
float blue = ftint * c.getBlue() + (1.f - ftint) * 255.f;
return new Color(Math.round(red), Math.round(green), Math.round(blue), c.getAlpha());
} }

View File

@ -47,9 +47,6 @@ public class DrawSimpleShape<T extends SimpleShape> extends DrawShape<T> {
@Override @Override
public void draw(Graphics2D graphics) { public void draw(Graphics2D graphics) {
// RenderableShape rShape = new RenderableShape(this);
// rShape.render(graphics);
DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(shape); DrawPaint drawPaint = DrawFactory.getInstance(graphics).getPaint(shape);
Paint fill = drawPaint.getPaint(graphics, shape.getFillStyle().getPaint()); Paint fill = drawPaint.getPaint(graphics, shape.getFillStyle().getPaint());
Paint line = drawPaint.getPaint(graphics, shape.getStrokeStyle().getPaint()); Paint line = drawPaint.getPaint(graphics, shape.getStrokeStyle().getPaint());

View File

@ -17,18 +17,32 @@
package org.apache.poi.sl.draw; package org.apache.poi.sl.draw;
import java.awt.Color;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.font.*; import java.awt.Paint;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.text.*; import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute; import java.text.AttributedCharacterIterator.Attribute;
import java.util.*; import java.text.AttributedString;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.poi.sl.usermodel.*; import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.apache.poi.sl.usermodel.Insets2D;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle; import org.apache.poi.sl.usermodel.TextParagraph.BulletStyle;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.sl.usermodel.TextRun.TextCap; import org.apache.poi.sl.usermodel.TextRun.TextCap;
import org.apache.poi.sl.usermodel.TextShape;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;
public class DrawTextParagraph<T extends TextRun> implements Drawable { public class DrawTextParagraph<T extends TextRun> implements Drawable {
@ -69,9 +83,6 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
public void draw(Graphics2D graphics){ public void draw(Graphics2D graphics){
if (lines.isEmpty()) return; if (lines.isEmpty()) return;
Insets2D insets = paragraph.getParentShape().getInsets();
double leftInset = insets.left;
double rightInset = insets.right;
double penY = y; double penY = y;
boolean firstLine = true; boolean firstLine = true;
@ -79,12 +90,17 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
Double leftMargin = paragraph.getLeftMargin(); Double leftMargin = paragraph.getLeftMargin();
if (leftMargin == null) { if (leftMargin == null) {
// if the marL attribute is omitted, then a value of 347663 is implied // if the marL attribute is omitted, then a value of 347663 is implied
leftMargin = Units.toPoints(347663*(indentLevel+1)); leftMargin = Units.toPoints(347663*indentLevel);
} }
Double indent = paragraph.getIndent(); Double indent = paragraph.getIndent();
if (indent == null) { if (indent == null) {
indent = Units.toPoints(347663*indentLevel); indent = Units.toPoints(347663*indentLevel);
} }
if (paragraph.getClass().getName().contains("HSLF")) {
// special handling for HSLF
indent -= leftMargin;
}
Double rightMargin = paragraph.getRightMargin(); Double rightMargin = paragraph.getRightMargin();
if (rightMargin == null) { if (rightMargin == null) {
rightMargin = 0d; rightMargin = 0d;
@ -104,25 +120,30 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
} }
if (bullet != null){ if (bullet != null){
bullet.setPosition(x + indent, penY); bullet.setPosition(x+leftMargin+indent, penY);
bullet.draw(graphics); bullet.draw(graphics);
// don't let text overlay the bullet and advance by the bullet width // don't let text overlay the bullet and advance by the bullet width
double bulletWidth = bullet.getLayout().getAdvance() + 1; double bulletWidth = bullet.getLayout().getAdvance() + 1;
penX = x + Math.max(leftMargin, indent+bulletWidth); penX = x + Math.max(leftMargin, leftMargin+indent+bulletWidth);
} else { } else {
penX = x + indent; penX = x + leftMargin;
} }
} else { } else {
penX = x + leftMargin; penX = x + leftMargin;
} }
Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape()); Rectangle2D anchor = DrawShape.getAnchor(graphics, paragraph.getParentShape());
// Insets are already applied on DrawTextShape.drawContent
// but (outer) anchor need to be adjusted
Insets2D insets = paragraph.getParentShape().getInsets();
double leftInset = insets.left;
double rightInset = insets.right;
TextAlign ta = paragraph.getTextAlign(); TextAlign ta = paragraph.getTextAlign();
if (ta == null) ta = TextAlign.LEFT; if (ta == null) ta = TextAlign.LEFT;
switch (ta) { switch (ta) {
case CENTER: case CENTER:
penX += (anchor.getWidth() - leftMargin - line.getWidth() - leftInset - rightInset) / 2; penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset - leftMargin) / 2;
break; break;
case RIGHT: case RIGHT:
penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset); penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset);
@ -245,8 +266,14 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
if (buFont == null) buFont = paragraph.getDefaultFontFamily(); if (buFont == null) buFont = paragraph.getDefaultFontFamily();
assert(buFont != null); assert(buFont != null);
Color buColor = bulletStyle.getBulletFontColor(); PlaceableShape ps = getParagraphShape();
if (buColor == null) buColor = (Color)firstLineAttr.getAttribute(TextAttribute.FOREGROUND); PaintStyle fgPaintStyle = bulletStyle.getBulletFontColor();
Paint fgPaint;
if (fgPaintStyle == null) {
fgPaint = (Paint)firstLineAttr.getAttribute(TextAttribute.FOREGROUND);
} else {
fgPaint = new DrawPaint(ps).getPaint(graphics, fgPaintStyle);
}
float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE); float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE);
Double buSz = bulletStyle.getBulletFontSize(); Double buSz = bulletStyle.getBulletFontSize();
@ -256,7 +283,7 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
AttributedString str = new AttributedString(buCharacter); AttributedString str = new AttributedString(buCharacter);
str.addAttribute(TextAttribute.FOREGROUND, buColor); str.addAttribute(TextAttribute.FOREGROUND, fgPaint);
str.addAttribute(TextAttribute.FAMILY, buFont); str.addAttribute(TextAttribute.FAMILY, buFont);
str.addAttribute(TextAttribute.SIZE, fontSize); str.addAttribute(TextAttribute.SIZE, fontSize);
@ -383,10 +410,30 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
} }
} }
/**
* Helper method for paint style relative to bounds, e.g. gradient paint
*/
private PlaceableShape getParagraphShape() {
PlaceableShape ps = new PlaceableShape(){
public ShapeContainer<? extends Shape> getParent() { return null; }
public Rectangle2D getAnchor() { return paragraph.getParentShape().getAnchor(); }
public void setAnchor(Rectangle2D anchor) {}
public double getRotation() { return 0; }
public void setRotation(double theta) {}
public void setFlipHorizontal(boolean flip) {}
public void setFlipVertical(boolean flip) {}
public boolean getFlipHorizontal() { return false; }
public boolean getFlipVertical() { return false; }
};
return ps;
}
protected AttributedString getAttributedString(Graphics2D graphics, StringBuilder text){ protected AttributedString getAttributedString(Graphics2D graphics, StringBuilder text){
List<AttributedStringData> attList = new ArrayList<AttributedStringData>(); List<AttributedStringData> attList = new ArrayList<AttributedStringData>();
if (text == null) text = new StringBuilder(); if (text == null) text = new StringBuilder();
PlaceableShape ps = getParagraphShape();
DrawFontManager fontHandler = (DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER); DrawFontManager fontHandler = (DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER);
for (TextRun run : paragraph){ for (TextRun run : paragraph){
@ -398,9 +445,9 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
text.append(runText); text.append(runText);
int endIndex = text.length(); int endIndex = text.length();
Color fgColor = run.getFontColor(); PaintStyle fgPaintStyle = run.getFontColor();
if (fgColor == null) fgColor = Color.BLACK; Paint fgPaint = new DrawPaint(ps).getPaint(graphics, fgPaintStyle);
attList.add(new AttributedStringData(TextAttribute.FOREGROUND, fgColor, beginIndex, endIndex)); attList.add(new AttributedStringData(TextAttribute.FOREGROUND, fgPaint, beginIndex, endIndex));
// user can pass an custom object to convert fonts // user can pass an custom object to convert fonts
String fontFamily = run.getFontFamily(); String fontFamily = run.getFontFamily();

View File

@ -102,7 +102,6 @@ public class DrawTextShape<T extends TextShape<? extends TextParagraph<? extends
*/ */
public double drawParagraphs(Graphics2D graphics, double x, double y) { public double drawParagraphs(Graphics2D graphics, double x, double y) {
DrawFactory fact = DrawFactory.getInstance(graphics); DrawFactory fact = DrawFactory.getInstance(graphics);
Insets2D shapePadding = shape.getInsets();
double y0 = y; double y0 = y;
Iterator<? extends TextParagraph<? extends TextRun>> paragraphs = shape.iterator(); Iterator<? extends TextParagraph<? extends TextRun>> paragraphs = shape.iterator();

View File

@ -32,17 +32,55 @@ public interface ColorStyle {
int getAlpha(); int getAlpha();
/** /**
* the luminance shift as expressed by a percentage relative to the input color * the hue shift as expressed by a percentage relative to the input color.
* Be aware that OOXML also returns values greater than 100%
* *
* @return luminance shift in percents in the range [0..100000] * @return hue shift in percents in the range [0..100000] (usually ...)
* or -1 if the value is not set
*/
int getHueOff();
/**
* the hue as expressed by a percentage relative to the input color.
* Be aware that OOXML also returns values greater than 100%
*
* @return hue in percents in the range [0..100000] (usually ...)
* or -1 if the value is not set
*/
int getHueMod();
/**
* the saturation shift as expressed by a percentage relative to the input color.
* Be aware that OOXML also returns values greater than 100%
*
* @return saturation shift in percents in the range [0..100000] (usually ...)
* or -1 if the value is not set
*/
int getSatOff();
/**
* the saturation as expressed by a percentage relative to the input color.
* Be aware that OOXML also returns values greater than 100%
*
* @return saturation in percents in the range [0..100000] (usually ...)
* or -1 if the value is not set
*/
int getSatMod();
/**
* the luminance shift as expressed by a percentage relative to the input color.
* Be aware that OOXML also returns values greater than 100%
*
* @return luminance shift in percents in the range [0..100000] (usually ...)
* or -1 if the value is not set * or -1 if the value is not set
*/ */
int getLumOff(); int getLumOff();
/** /**
* the luminance as expressed by a percentage relative to the input color * the luminance as expressed by a percentage relative to the input color.
* Be aware that OOXML also returns values greater than 100%.
* *
* @return luminance in percents in the range [0..100000] * @return luminance in percents in the range [0..100000] (usually ...)
* or -1 if the value is not set * or -1 if the value is not set
*/ */
int getLumMod(); int getLumMod();
@ -50,8 +88,9 @@ public interface ColorStyle {
/** /**
* specifies a darker version of its input color. * specifies a darker version of its input color.
* A 10% shade is 10% of the input color combined with 90% black. * A 10% shade is 10% of the input color combined with 90% black.
* Be aware that OOXML also returns values greater than 100%.
* *
* @return the value of the shade specified as percents in the range [0..100000] * @return the value of the shade specified as percents in the range [0..100000] (usually ...)
* with 0% indicating minimal shade and 100% indicating maximum * with 0% indicating minimal shade and 100% indicating maximum
* or -1 if the value is not set * or -1 if the value is not set
*/ */
@ -60,8 +99,9 @@ public interface ColorStyle {
/** /**
* specifies a lighter version of its input color. * specifies a lighter version of its input color.
* A 10% tint is 10% of the input color combined with 90% white. * A 10% tint is 10% of the input color combined with 90% white.
* Be aware that OOXML also returns values greater than 100%
* *
* @return the value of the tint specified as percents in the range [0..100000] * @return the value of the tint specified as percents in the range [0..100000] (usually ...)
* with 0% indicating minimal tint and 100% indicating maximum * with 0% indicating minimal tint and 100% indicating maximum
* or -1 if the value is not set * or -1 if the value is not set
*/ */

View File

@ -17,14 +17,12 @@
package org.apache.poi.sl.usermodel; package org.apache.poi.sl.usermodel;
import java.awt.Color;
import java.io.InputStream; import java.io.InputStream;
import org.apache.poi.sl.draw.DrawPaint;
public interface PaintStyle { public interface PaintStyle {
public interface SolidPaint extends PaintStyle { public interface SolidPaint extends PaintStyle {
ColorStyle getSolidColor(); ColorStyle getSolidColor();
} }
@ -58,6 +56,4 @@ public interface PaintStyle {
*/ */
int getAlpha(); int getAlpha();
} }
SolidPaint TRANSPARENT_PAINT = DrawPaint.createSolidPaint(new Color(0xFF, 0xFF, 0xFF, 0));
} }

View File

@ -34,4 +34,10 @@ public interface Slide<T extends Shape, SS extends SlideShow, N extends Notes<T,
* @return the 1-based slide no. * @return the 1-based slide no.
*/ */
int getSlideNumber(); int getSlideNumber();
/**
* @return title of this slide or null if title is not set
*/
String getTitle();
} }

View File

@ -21,7 +21,6 @@ import java.awt.Dimension;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.sl.usermodel.PictureData.PictureType;
public interface SlideShow { public interface SlideShow {

View File

@ -20,6 +20,7 @@ package org.apache.poi.sl.usermodel;
import java.awt.Color; import java.awt.Color;
public interface TextParagraph<T extends TextRun> extends Iterable<T> { public interface TextParagraph<T extends TextRun> extends Iterable<T> {
/** /**
@ -113,7 +114,20 @@ public interface TextParagraph<T extends TextRun> extends Iterable<T> {
* @return the bullet point font size * @return the bullet point font size
*/ */
Double getBulletFontSize(); Double getBulletFontSize();
Color getBulletFontColor();
/**
* Convenience function to set a solid color
*/
void setBulletFontColor(Color color);
void setBulletFontColor(PaintStyle color);
/**
*
* @return the color of bullet characters within a given paragraph.
* A {@code null} value means to use the text font color.
*/
PaintStyle getBulletFontColor();
AutoNumberingScheme getAutoNumberingScheme(); AutoNumberingScheme getAutoNumberingScheme();
/** /**

View File

@ -19,6 +19,8 @@ package org.apache.poi.sl.usermodel;
import java.awt.Color; import java.awt.Color;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
/** /**
* Some text. * Some text.
*/ */
@ -34,9 +36,34 @@ public interface TextRun {
TextCap getTextCap(); TextCap getTextCap();
Color getFontColor(); /**
* Returns the font color.
* This usually returns a {@link SolidPaint}, but but also other classes are possible
*
* @return the font color/paint
*
* @see org.apache.poi.sl.draw.DrawPaint#getPaint(java.awt.Graphics2D, PaintStyle)
* @see SolidPaint#getSolidColor()
* @see org.apache.poi.sl.draw.DrawPaint#applyColorTransform(ColorStyle)
*/
PaintStyle getFontColor();
/**
* Sets the (solid) font color - convenience function
*
* @param color the color
*/
void setFontColor(Color color); void setFontColor(Color color);
/**
* Sets the font color
*
* @param color the color
*
* @see org.apache.poi.sl.draw.DrawPaint#createSolidPaint(Color)
*/
void setFontColor(PaintStyle color);
/** /**
* @return font size in points or null if font size is not set. * @return font size in points or null if font size is not set.

View File

@ -0,0 +1,298 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.sl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.security.GeneralSecurityException;
import org.apache.poi.EmptyFileException;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.poifs.crypt.Decryptor;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
public class SlideShowFactory {
/**
* Creates a HSLFSlideShow from the given POIFSFileSystem
* <p>Note that in order to properly release resources the
* SlideShow should be closed after use.
*/
public static SlideShow create(POIFSFileSystem fs) throws IOException {
return new HSLFSlideShow(fs);
}
/**
* Creates a HSLFSlideShow from the given NPOIFSFileSystem
* <p>Note that in order to properly release resources the
* SlideShow should be closed after use.
*/
public static SlideShow create(NPOIFSFileSystem fs) throws IOException {
try {
return create(fs, null);
} catch (InvalidFormatException e) {
// Special case of OOXML-in-POIFS which is broken
throw new IOException(e);
}
}
/**
* Creates a SlideShow from the given NPOIFSFileSystem, which may
* be password protected
*
* @param fs The {@link NPOIFSFileSystem} to read the document from
* @param password The password that should be used or null if no password is necessary.
*
* @return The created SlideShow
*
* @throws IOException if an error occurs while reading the data
* @throws InvalidFormatException if the contents of the file cannot be parsed into a {@link SlideShow}
*/
private static SlideShow create(NPOIFSFileSystem fs, String password) throws IOException, InvalidFormatException {
DirectoryNode root = fs.getRoot();
// Encrypted OOXML files go inside OLE2 containers, is this one?
if (root.hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
EncryptionInfo info = new EncryptionInfo(fs);
Decryptor d = Decryptor.getInstance(info);
boolean passwordCorrect = false;
InputStream stream = null;
try {
if (password != null && d.verifyPassword(password)) {
passwordCorrect = true;
}
if (!passwordCorrect && d.verifyPassword(Decryptor.DEFAULT_PASSWORD)) {
passwordCorrect = true;
}
if (passwordCorrect) {
stream = d.getDataStream(root);
}
} catch (GeneralSecurityException e) {
throw new IOException(e);
}
if (! passwordCorrect) {
if (password != null)
throw new EncryptedDocumentException("Password incorrect");
else
throw new EncryptedDocumentException("The supplied spreadsheet is protected, but no password was supplied");
}
OPCPackage pkg = OPCPackage.open(stream);
return create(pkg);
}
// If we get here, it isn't an encrypted PPTX file
// So, treat it as a regular HSLF PPT one
if (password != null) {
Biff8EncryptionKey.setCurrentUserPassword(password);
}
SlideShow wb = new HSLFSlideShow(root);
Biff8EncryptionKey.setCurrentUserPassword(null);
return wb;
}
/**
* Creates a XMLSlideShow from the given OOXML Package
*
* <p>Note that in order to properly release resources the
* SlideShow should be closed after use.</p>
*
* @param pkg The {@link OPCPackage} opened for reading data.
*
* @return The created SlideShow
*
* @throws IOException if an error occurs while reading the data
*/
public static SlideShow create(OPCPackage pkg) throws IOException {
return new XMLSlideShow(pkg);
}
/**
* Creates the appropriate HSLFSlideShow / XMLSlideShow from
* the given InputStream.
*
* <p>Your input stream MUST either support mark/reset, or
* be wrapped as a {@link PushbackInputStream}! Note that
* using an {@link InputStream} has a higher memory footprint
* than using a {@link File}.</p>
*
* <p>Note that in order to properly release resources the
* SlideShow should be closed after use. Note also that loading
* from an InputStream requires more memory than loading
* from a File, so prefer {@link #create(File)} where possible.
*
* @param inp The {@link InputStream} to read data from.
*
* @return The created SlideShow
*
* @throws IOException if an error occurs while reading the data
* @throws InvalidFormatException if the contents of the file cannot be parsed into a {@link SlideShow}
* @throws EncryptedDocumentException If the SlideShow given is password protected
*/
public static SlideShow create(InputStream inp) throws IOException, InvalidFormatException, EncryptedDocumentException {
return create(inp, null);
}
/**
* Creates the appropriate HSLFSlideShow / XMLSlideShow from
* the given InputStream, which may be password protected.
* <p>Your input stream MUST either support mark/reset, or
* be wrapped as a {@link PushbackInputStream}! Note that
* using an {@link InputStream} has a higher memory footprint
* than using a {@link File}.</p>
*
* <p>Note that in order to properly release resources the
* SlideShow should be closed after use. Note also that loading
* from an InputStream requires more memory than loading
* from a File, so prefer {@link #create(File)} where possible.</p>
*
* @param inp The {@link InputStream} to read data from.
* @param password The password that should be used or null if no password is necessary.
*
* @return The created SlideShow
*
* @throws IOException if an error occurs while reading the data
* @throws InvalidFormatException if the contents of the file cannot be parsed into a {@link SlideShow}
* @throws EncryptedDocumentException If the wrong password is given for a protected file
* @throws EmptyFileException If an empty stream is given
*/
public static SlideShow create(InputStream inp, String password) throws IOException, InvalidFormatException, EncryptedDocumentException {
// If clearly doesn't do mark/reset, wrap up
if (! inp.markSupported()) {
inp = new PushbackInputStream(inp, 8);
}
// Ensure that there is at least some data there
byte[] header8 = IOUtils.peekFirst8Bytes(inp);
// Try to create
if (NPOIFSFileSystem.hasPOIFSHeader(header8)) {
NPOIFSFileSystem fs = new NPOIFSFileSystem(inp);
return create(fs, password);
}
if (POIXMLDocument.hasOOXMLHeader(inp)) {
return new XMLSlideShow(OPCPackage.open(inp));
}
throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");
}
/**
* Creates the appropriate HSLFSlideShow / XMLSlideShow from
* the given File, which must exist and be readable.
* <p>Note that in order to properly release resources the
* SlideShow should be closed after use.
*
* @param file The file to read data from.
*
* @return The created SlideShow
*
* @throws IOException if an error occurs while reading the data
* @throws InvalidFormatException if the contents of the file cannot be parsed into a {@link SlideShow}
* @throws EncryptedDocumentException If the SlideShow given is password protected
*/
public static SlideShow create(File file) throws IOException, InvalidFormatException, EncryptedDocumentException {
return create(file, null);
}
/**
* Creates the appropriate HSLFSlideShow / XMLSlideShow from
* the given File, which must exist and be readable, and
* may be password protected
* <p>Note that in order to properly release resources the
* SlideShow should be closed after use.
*
* @param file The file to read data from.
* @param password The password that should be used or null if no password is necessary.
*
* @return The created SlideShow
*
* @throws IOException if an error occurs while reading the data
* @throws InvalidFormatException if the contents of the file cannot be parsed into a {@link SlideShow}
* @throws EncryptedDocumentException If the wrong password is given for a protected file
* @throws EmptyFileException If an empty stream is given
*/
public static SlideShow create(File file, String password) throws IOException, InvalidFormatException, EncryptedDocumentException {
return create(file, password, false);
}
/**
* Creates the appropriate HSLFSlideShow / XMLSlideShow from
* the given File, which must exist and be readable, and
* may be password protected
* <p>Note that in order to properly release resources the
* SlideShow should be closed after use.
*
* @param file The file to read data from.
* @param password The password that should be used or null if no password is necessary.
* @param readOnly If the SlideShow should be opened in read-only mode to avoid writing back
* changes when the document is closed.
*
* @return The created SlideShow
*
* @throws IOException if an error occurs while reading the data
* @throws InvalidFormatException if the contents of the file cannot be parsed into a {@link SlideShow}
* @throws EncryptedDocumentException If the wrong password is given for a protected file
* @throws EmptyFileException If an empty stream is given
*/
public static SlideShow create(File file, String password, boolean readOnly) throws IOException, InvalidFormatException, EncryptedDocumentException {
if (! file.exists()) {
throw new FileNotFoundException(file.toString());
}
try {
NPOIFSFileSystem fs = new NPOIFSFileSystem(file, readOnly);
return create(fs, password);
} catch(OfficeXmlFileException e) {
// opening as .ppt failed => try opening as .pptx
OPCPackage pkg = OPCPackage.open(file, readOnly ? PackageAccess.READ : PackageAccess.READ_WRITE);
try {
return new XMLSlideShow(pkg);
// } catch (IOException ioe) {
// // ensure that file handles are closed (use revert() to not re-write the file)
// pkg.revert();
// //pkg.close();
//
// // rethrow exception
// throw ioe;
} catch (IllegalArgumentException ioe) {
// ensure that file handles are closed (use revert() to not re-write the file)
pkg.revert();
//pkg.close();
// rethrow exception
throw ioe;
}
}
}
}

View File

@ -27,8 +27,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public abstract class CharacterPropertyFetcher<T> extends ParagraphPropertyFetcher<T> { public abstract class CharacterPropertyFetcher<T> extends ParagraphPropertyFetcher<T> {
public boolean isFetchingFromMaster = false;
public CharacterPropertyFetcher(int level) { public CharacterPropertyFetcher(int level) {
super(level); super(level);
} }

View File

@ -78,6 +78,22 @@ public class XSLFColor {
return getRawValue("alpha"); return getRawValue("alpha");
} }
public int getHueOff() {
return getRawValue("hueOff");
}
public int getHueMod() {
return getRawValue("hueMod");
}
public int getSatOff() {
return getRawValue("satOff");
}
public int getSatMod() {
return getRawValue("satMod");
}
public int getLumOff() { public int getLumOff() {
return getRawValue("lumOff"); return getRawValue("lumOff");
} }

View File

@ -44,10 +44,14 @@ public class XSLFDrawing {
XmlObject[] cNvPr = sheet.getSpTree().selectPath( XmlObject[] cNvPr = sheet.getSpTree().selectPath(
"declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:cNvPr"); "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:cNvPr");
for(XmlObject o : cNvPr) { for(XmlObject o : cNvPr) {
// powerpoint generates AlternateContent elements which cNvPr elements aren't recognized
// ignore them for now
if (o instanceof CTNonVisualDrawingProps) {
CTNonVisualDrawingProps p = (CTNonVisualDrawingProps)o; CTNonVisualDrawingProps p = (CTNonVisualDrawingProps)o;
_shapeId = (int)Math.max(_shapeId, p.getId()); _shapeId = (int)Math.max(_shapeId, p.getId());
} }
} }
}
public XSLFAutoShape createAutoShape(){ public XSLFAutoShape createAutoShape(){
CTShape sp = _spTree.addNewSp(); CTShape sp = _spTree.addNewSp();

View File

@ -21,8 +21,6 @@ import java.awt.Color;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.ColorStyle;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.Shadow; import org.apache.poi.sl.usermodel.Shadow;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;
@ -90,7 +88,7 @@ public class XSLFShadow extends XSLFShape implements Shadow {
*/ */
public Color getFillColor() { public Color getFillColor() {
SolidPaint ps = getFillStyle(); SolidPaint ps = getFillStyle();
if (ps == PaintStyle.TRANSPARENT_PAINT) return null; if (ps == null) return null;
Color col = DrawPaint.applyColorTransform(ps.getSolidColor()); Color col = DrawPaint.applyColorTransform(ps.getSolidColor());
return col; return col;
} }
@ -99,14 +97,10 @@ public class XSLFShadow extends XSLFShape implements Shadow {
public SolidPaint getFillStyle() { public SolidPaint getFillStyle() {
XSLFTheme theme = getSheet().getTheme(); XSLFTheme theme = getSheet().getTheme();
CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject(); CTOuterShadowEffect ct = (CTOuterShadowEffect)getXmlObject();
if(ct == null) return PaintStyle.TRANSPARENT_PAINT; if(ct == null) return null;
CTSchemeColor phClr = ct.getSchemeClr(); CTSchemeColor phClr = ct.getSchemeClr();
final XSLFColor xc = new XSLFColor(ct, theme, phClr); final XSLFColor xc = new XSLFColor(ct, theme, phClr);
return new SolidPaint(){ return DrawPaint.createSolidPaint(xc.getColorStyle());
public ColorStyle getSolidColor() {
return xc.getColorStyle();
}
};
} }
} }

View File

@ -27,10 +27,10 @@ import java.util.Comparator;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.ColorStyle; import org.apache.poi.sl.usermodel.ColorStyle;
import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
import org.apache.poi.sl.usermodel.PlaceableShape; import org.apache.poi.sl.usermodel.PlaceableShape;
import org.apache.poi.sl.usermodel.Shape; import org.apache.poi.sl.usermodel.Shape;
@ -38,7 +38,20 @@ import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.xslf.model.PropertyFetcher; import org.apache.poi.xslf.model.PropertyFetcher;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.*; import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientStop;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNoFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrix;
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference;
import org.openxmlformats.schemas.drawingml.x2006.main.STPathShadeType;
import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps; import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground;
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties; import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
@ -139,7 +152,7 @@ public abstract class XSLFShape implements Shape {
try { try {
pr = shape.getSpPr(); pr = shape.getSpPr();
if (((CTShapeProperties)pr).isSetNoFill()) { if (((CTShapeProperties)pr).isSetNoFill()) {
setValue(PaintStyle.TRANSPARENT_PAINT); setValue(null);
return true; return true;
} }
} catch (IllegalStateException e) {} } catch (IllegalStateException e) {}
@ -156,21 +169,19 @@ public abstract class XSLFShape implements Shape {
} }
} }
if (pr == null) { if (pr == null) return false;
setValue(PaintStyle.TRANSPARENT_PAINT);
return true;
}
PaintStyle paint = null; PaintStyle paint = null;
PackagePart pp = getSheet().getPackagePart();
for (XmlObject obj : pr.selectPath("*")) { for (XmlObject obj : pr.selectPath("*")) {
paint = selectPaint(obj, null, getSheet().getPackagePart()); paint = selectPaint(obj, null, pp);
if (paint != null) break; if (paint != null) {
}
if (paint == null) return false;
setValue(paint); setValue(paint);
return true; return true;
};
}
return false;
} }
}; };
fetchShapeProperty(fetcher); fetchShapeProperty(fetcher);
@ -190,7 +201,7 @@ public abstract class XSLFShape implements Shape {
} }
paint = selectPaint(fillRef); paint = selectPaint(fillRef);
return paint == null ? PaintStyle.TRANSPARENT_PAINT : paint; return paint;
} }
protected CTBackgroundProperties getBgPr() { protected CTBackgroundProperties getBgPr() {
@ -347,7 +358,7 @@ public abstract class XSLFShape implements Shape {
paint = selectPaint(obj, phClr, pp); paint = selectPaint(obj, phClr, pp);
if(paint != null) break; if(paint != null) break;
} }
return paint == null ? PaintStyle.TRANSPARENT_PAINT : paint; return paint;
} }
/** /**
@ -371,13 +382,13 @@ public abstract class XSLFShape implements Shape {
*/ */
protected PaintStyle selectPaint(XmlObject obj, final CTSchemeColor phClr, final PackagePart parentPart) { protected PaintStyle selectPaint(XmlObject obj, final CTSchemeColor phClr, final PackagePart parentPart) {
if (obj instanceof CTNoFillProperties) { if (obj instanceof CTNoFillProperties) {
return PaintStyle.TRANSPARENT_PAINT; return null;
} else if (obj instanceof CTSolidColorFillProperties) { } else if (obj instanceof CTSolidColorFillProperties) {
return selectPaint((CTSolidColorFillProperties)obj, phClr, parentPart); return selectPaint((CTSolidColorFillProperties)obj, phClr);
} else if (obj instanceof CTBlipFillProperties) { } else if (obj instanceof CTBlipFillProperties) {
return selectPaint((CTBlipFillProperties)obj, phClr, parentPart); return selectPaint((CTBlipFillProperties)obj, parentPart);
} else if (obj instanceof CTGradientFillProperties) { } else if (obj instanceof CTGradientFillProperties) {
return selectPaint((CTGradientFillProperties) obj, phClr, parentPart); return selectPaint((CTGradientFillProperties) obj, phClr);
} else if (obj instanceof CTStyleMatrixReference) { } else if (obj instanceof CTStyleMatrixReference) {
return selectPaint((CTStyleMatrixReference)obj); return selectPaint((CTStyleMatrixReference)obj);
} else { } else {
@ -385,17 +396,16 @@ public abstract class XSLFShape implements Shape {
} }
} }
protected PaintStyle selectPaint(final CTSolidColorFillProperties solidFill, final CTSchemeColor phClr, final PackagePart parentPart) { protected PaintStyle selectPaint(CTSolidColorFillProperties solidFill, CTSchemeColor phClr) {
final XSLFTheme theme = getSheet().getTheme(); final XSLFTheme theme = getSheet().getTheme();
final XSLFColor c = new XSLFColor(solidFill, theme, phClr); if (phClr == null && solidFill.isSetSchemeClr()) {
return new SolidPaint() { phClr = solidFill.getSchemeClr();
public ColorStyle getSolidColor() {
return c.getColorStyle();
} }
}; final XSLFColor c = new XSLFColor(solidFill, theme, phClr);
return DrawPaint.createSolidPaint(c.getColorStyle());
} }
protected PaintStyle selectPaint(final CTBlipFillProperties blipFill, final CTSchemeColor phClr, final PackagePart parentPart) { protected PaintStyle selectPaint(final CTBlipFillProperties blipFill, final PackagePart parentPart) {
final CTBlip blip = blipFill.getBlip(); final CTBlip blip = blipFill.getBlip();
return new TexturePaint() { return new TexturePaint() {
private PackagePart getPart() { private PackagePart getPart() {
@ -424,12 +434,12 @@ public abstract class XSLFShape implements Shape {
public int getAlpha() { public int getAlpha() {
return (blip.sizeOfAlphaModFixArray() > 0) return (blip.sizeOfAlphaModFixArray() > 0)
? blip.getAlphaModFixArray(0).getAmt() ? blip.getAlphaModFixArray(0).getAmt()
: 0; : 100000;
} }
}; };
} }
protected PaintStyle selectPaint(final CTGradientFillProperties gradFill, final CTSchemeColor phClr, final PackagePart parentPart) { protected PaintStyle selectPaint(final CTGradientFillProperties gradFill, CTSchemeColor phClr) {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
final CTGradientStop[] gs = gradFill.getGsLst().getGsArray(); final CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
@ -448,7 +458,11 @@ public abstract class XSLFShape implements Shape {
int i=0; int i=0;
for (CTGradientStop cgs : gs) { for (CTGradientStop cgs : gs) {
cs[i] = new XSLFColor(cgs, theme, phClr).getColorStyle(); CTSchemeColor phClrCgs = phClr;
if (phClrCgs == null && cgs.isSetSchemeClr()) {
phClrCgs = cgs.getSchemeClr();
}
cs[i] = new XSLFColor(cgs, theme, phClrCgs).getColorStyle();
fractions[i] = cgs.getPos() / 100000.f; fractions[i] = cgs.getPos() / 100000.f;
i++; i++;
} }

View File

@ -19,8 +19,6 @@
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.apache.poi.sl.usermodel.PaintStyle.TRANSPARENT_PAINT;
import java.awt.Color; import java.awt.Color;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
@ -31,10 +29,15 @@ import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.sl.draw.geom.CustomGeometry; import org.apache.poi.sl.draw.geom.CustomGeometry;
import org.apache.poi.sl.draw.geom.Guide; import org.apache.poi.sl.draw.geom.Guide;
import org.apache.poi.sl.draw.geom.PresetGeometries; import org.apache.poi.sl.draw.geom.PresetGeometries;
import org.apache.poi.sl.usermodel.*; import org.apache.poi.sl.usermodel.FillStyle;
import org.apache.poi.sl.usermodel.LineDecoration;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape; import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape;
import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize; import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.SimpleShape;
import org.apache.poi.sl.usermodel.StrokeStyle;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCap; import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;
import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
@ -219,7 +222,6 @@ public abstract class XSLFSimpleShape extends XSLFShape implements SimpleShape {
*/ */
public Color getLineColor() { public Color getLineColor() {
PaintStyle ps = getLinePaint(); PaintStyle ps = getLinePaint();
if (ps == null || ps == TRANSPARENT_PAINT) return null;
if (ps instanceof SolidPaint) { if (ps instanceof SolidPaint) {
return ((SolidPaint)ps).getSolidColor().getColor(); return ((SolidPaint)ps).getSolidColor().getColor();
} }
@ -232,7 +234,7 @@ public abstract class XSLFSimpleShape extends XSLFShape implements SimpleShape {
CTLineProperties spPr = shape.getSpPr().getLn(); CTLineProperties spPr = shape.getSpPr().getLn();
if (spPr != null) { if (spPr != null) {
if (spPr.isSetNoFill()) { if (spPr.isSetNoFill()) {
setValue(TRANSPARENT_PAINT); // use it as 'nofill' value setValue(null); // use it as 'nofill' value
return true; return true;
} }
@ -266,7 +268,7 @@ public abstract class XSLFSimpleShape extends XSLFShape implements SimpleShape {
// line color was not found, check if it is defined in the theme // line color was not found, check if it is defined in the theme
CTShapeStyle style = getSpStyle(); CTShapeStyle style = getSpStyle();
if (style == null) return TRANSPARENT_PAINT; if (style == null) return null;
// get a reference to a line style within the style matrix. // get a reference to a line style within the style matrix.
CTStyleMatrixReference lnRef = style.getLnRef(); CTStyleMatrixReference lnRef = style.getLnRef();
@ -279,7 +281,7 @@ public abstract class XSLFSimpleShape extends XSLFShape implements SimpleShape {
paint = getPaint(lnProps, phClr); paint = getPaint(lnProps, phClr);
} }
return paint == null ? TRANSPARENT_PAINT : paint; return paint;
} }
/** /**
@ -524,7 +526,6 @@ public abstract class XSLFSimpleShape extends XSLFShape implements SimpleShape {
*/ */
public Color getFillColor() { public Color getFillColor() {
PaintStyle ps = getFillPaint(); PaintStyle ps = getFillPaint();
if (ps == null || ps == TRANSPARENT_PAINT) return null;
if (ps instanceof SolidPaint) { if (ps instanceof SolidPaint) {
return ((SolidPaint)ps).getSolidColor().getColor(); return ((SolidPaint)ps).getSolidColor().getColor();
} }

View File

@ -168,13 +168,10 @@ public final class XSLFSlide extends XSLFSheet implements Slide<XSLFShape, XMLSl
return _notes; return _notes;
} }
/** @Override
*
* @return title of this slide or empty string if title is not set
*/
public String getTitle(){ public String getTitle(){
XSLFTextShape txt = getTextShapeByType(Placeholder.TITLE); XSLFTextShape txt = getTextShapeByType(Placeholder.TITLE);
return txt == null ? "" : txt.getText(); return txt == null ? null : txt.getText();
} }
@Override @Override

View File

@ -21,7 +21,10 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.AutoNumberingScheme; import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.TextParagraph; import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
@ -264,7 +267,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
* @return the color of bullet characters within a given paragraph. * @return the color of bullet characters within a given paragraph.
* A <code>null</code> value means to use the text font color. * A <code>null</code> value means to use the text font color.
*/ */
public Color getBulletFontColor(){ public PaintStyle getBulletFontColor(){
final XSLFTheme theme = getParentShape().getSheet().getTheme(); final XSLFTheme theme = getParentShape().getSheet().getTheme();
ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getIndentLevel()){ ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getIndentLevel()){
public boolean fetch(CTTextParagraphProperties props){ public boolean fetch(CTTextParagraphProperties props){
@ -277,19 +280,33 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
} }
}; };
fetchParagraphProperty(fetcher); fetchParagraphProperty(fetcher);
return fetcher.getValue(); Color col = fetcher.getValue();
return (col == null) ? null : DrawPaint.createSolidPaint(col);
} }
public void setBulletFontColor(Color color) {
setBulletFontColor(DrawPaint.createSolidPaint(color));
}
/** /**
* Set the color to be used on bullet characters within a given paragraph. * Set the color to be used on bullet characters within a given paragraph.
* *
* @param color the bullet color * @param color the bullet color
*/ */
public void setBulletFontColor(Color color){ public void setBulletFontColor(PaintStyle color) {
if (!(color instanceof SolidPaint)) {
throw new IllegalArgumentException("Currently XSLF only supports SolidPaint");
}
// TODO: implement setting bullet color to null
SolidPaint sp = (SolidPaint)color;
Color col = DrawPaint.applyColorTransform(sp.getSolidColor());
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
CTColor c = pr.isSetBuClr() ? pr.getBuClr() : pr.addNewBuClr(); CTColor c = pr.isSetBuClr() ? pr.getBuClr() : pr.addNewBuClr();
CTSRgbColor clr = c.isSetSrgbClr() ? c.getSrgbClr() : c.addNewSrgbClr(); CTSRgbColor clr = c.isSetSrgbClr() ? c.getSrgbClr() : c.addNewSrgbClr();
clr.setVal(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()}); clr.setVal(new byte[]{(byte) col.getRed(), (byte) col.getGreen(), (byte) col.getBlue()});
} }
/** /**
@ -729,7 +746,6 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
XSLFSheet masterSheet = _shape.getSheet(); XSLFSheet masterSheet = _shape.getSheet();
for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) { for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {
masterSheet = m; masterSheet = m;
XmlObject xo = masterSheet.getXmlObject(); XmlObject xo = masterSheet.getXmlObject();
for (String xpath : xpaths) { for (String xpath : xpaths) {
XmlObject[] o = xo.selectPath(xpath); XmlObject[] o = xo.selectPath(xpath);
@ -767,32 +783,35 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){ private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){
boolean ok = false; boolean ok = false;
XSLFTextShape shape = getParentShape();
XSLFSheet sheet = shape.getSheet();
if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr()); if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());
if (ok) return true;
if(!ok) {
XSLFTextShape shape = getParentShape();
ok = shape.fetchShapeProperty(visitor); ok = shape.fetchShapeProperty(visitor);
if(!ok){ if (ok) return true;
CTPlaceholder ph = shape.getCTPlaceholder(); CTPlaceholder ph = shape.getCTPlaceholder();
if(ph == null){ if(ph == null){
// if it is a plain text box then take defaults from presentation.xml // if it is a plain text box then take defaults from presentation.xml
XMLSlideShow ppt = getParentShape().getSheet().getSlideShow(); XMLSlideShow ppt = sheet.getSlideShow();
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel()); CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel());
if (themeProps != null) ok = visitor.fetch(themeProps); if (themeProps != null) ok = visitor.fetch(themeProps);
} }
if (ok) return true;
if(!ok){
// defaults for placeholders are defined in the slide master // defaults for placeholders are defined in the slide master
CTTextParagraphProperties defaultProps = getDefaultMasterStyle(); CTTextParagraphProperties defaultProps = getDefaultMasterStyle();
// TODO: determine master shape
if(defaultProps != null) ok = visitor.fetch(defaultProps); if(defaultProps != null) ok = visitor.fetch(defaultProps);
} if (ok) return true;
}
} return false;
return ok;
} }
@SuppressWarnings("deprecation")
void copy(XSLFTextParagraph other){ void copy(XSLFTextParagraph other){
if (other == this) return; if (other == this) return;
@ -848,7 +867,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
if(buChar != null && !buChar.equals(getBulletCharacter())){ if(buChar != null && !buChar.equals(getBulletCharacter())){
setBulletCharacter(buChar); setBulletCharacter(buChar);
} }
Color buColor = other.getBulletFontColor(); PaintStyle buColor = other.getBulletFontColor();
if(buColor != null && !buColor.equals(getBulletFontColor())){ if(buColor != null && !buColor.equals(getBulletFontColor())){
setBulletFontColor(buColor); setBulletFontColor(buColor);
} }
@ -920,10 +939,20 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
} }
@Override @Override
public Color getBulletFontColor() { public PaintStyle getBulletFontColor() {
return XSLFTextParagraph.this.getBulletFontColor(); return XSLFTextParagraph.this.getBulletFontColor();
} }
@Override
public void setBulletFontColor(Color color) {
setBulletFontColor(DrawPaint.createSolidPaint(color));
}
@Override
public void setBulletFontColor(PaintStyle color) {
XSLFTextParagraph.this.setBulletFontColor(color);
}
@Override @Override
public AutoNumberingScheme getAutoNumberingScheme() { public AutoNumberingScheme getAutoNumberingScheme() {
return XSLFTextParagraph.this.getAutoNumberingScheme(); return XSLFTextParagraph.this.getAutoNumberingScheme();

View File

@ -18,6 +18,9 @@ package org.apache.poi.xslf.usermodel;
import java.awt.Color; import java.awt.Color;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.TextRun; import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.xslf.model.CharacterPropertyFetcher; import org.apache.poi.xslf.model.CharacterPropertyFetcher;
@ -84,10 +87,21 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public void setFontColor(Color color) { public void setFontColor(Color color) {
setFontColor(DrawPaint.createSolidPaint(color));
}
@Override
public void setFontColor(PaintStyle color) {
if (!(color instanceof SolidPaint)) {
throw new IllegalArgumentException("Currently only SolidPaint is supported!");
}
SolidPaint sp = (SolidPaint)color;
CTTextCharacterProperties rPr = getRPr(); CTTextCharacterProperties rPr = getRPr();
CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill(); CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill();
CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr(); CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();
clr.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()}); Color c = DrawPaint.applyColorTransform(sp.getSolidColor());
clr.setVal(new byte[]{(byte)c.getRed(), (byte)c.getGreen(), (byte)c.getBlue()});
if(fill.isSetHslClr()) fill.unsetHslClr(); if(fill.isSetHslClr()) fill.unsetHslClr();
if(fill.isSetPrstClr()) fill.unsetPrstClr(); if(fill.isSetPrstClr()) fill.unsetPrstClr();
@ -98,22 +112,22 @@ public class XSLFTextRun implements TextRun {
} }
@Override @Override
public Color getFontColor(){ public PaintStyle getFontColor(){
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme(); CharacterPropertyFetcher<PaintStyle> fetcher = new CharacterPropertyFetcher<PaintStyle>(_p.getIndentLevel()){
CTShapeStyle style = _p.getParentShape().getSpStyle();
final CTSchemeColor phClr = style == null ? null : style.getFontRef().getSchemeClr();
CharacterPropertyFetcher<Color> fetcher = new CharacterPropertyFetcher<Color>(_p.getIndentLevel()){
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
CTSolidColorFillProperties solidFill = props.getSolidFill(); XSLFShape shape = _p.getParentShape();
if(solidFill != null) { CTShapeStyle style = shape.getSpStyle();
boolean useCtxColor = CTSchemeColor phClr = null;
(solidFill.isSetSchemeClr() && solidFill.getSchemeClr().getVal() == STSchemeColorVal.PH_CLR) if (style != null && style.getFontRef() != null) {
|| isFetchingFromMaster; phClr = style.getFontRef().getSchemeClr();
Color c = new XSLFColor(solidFill, theme, useCtxColor ? phClr : null).getColor(); }
setValue(c);
PaintStyle ps = shape.getPaint(props, phClr);
if (ps != null) {
setValue(ps);
return true; return true;
} }
return false; return false;
} }
}; };
@ -250,7 +264,7 @@ public class XSLFTextRun implements TextRun {
} }
public byte getPitchAndFamily(){ public byte getPitchAndFamily(){
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme(); // final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
CharacterPropertyFetcher<Byte> visitor = new CharacterPropertyFetcher<Byte>(_p.getIndentLevel()){ CharacterPropertyFetcher<Byte> visitor = new CharacterPropertyFetcher<Byte>(_p.getIndentLevel()){
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
@ -474,35 +488,36 @@ public class XSLFTextRun implements TextRun {
} }
private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){ private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){
XSLFTextShape shape = _p.getParentShape();
XSLFSheet sheet = shape.getSheet();
boolean ok = false; boolean ok = false;
if (_r.isSetRPr()) ok = fetcher.fetch(getRPr()); if (_r.isSetRPr()) ok = fetcher.fetch(getRPr());
if (ok) return true;
if(!ok) {
XSLFTextShape shape = _p.getParentShape();
ok = shape.fetchShapeProperty(fetcher); ok = shape.fetchShapeProperty(fetcher);
if(!ok){ if (ok) return true;
CTPlaceholder ph = shape.getCTPlaceholder(); CTPlaceholder ph = shape.getCTPlaceholder();
if (ph == null){ if (ph == null){
// if it is a plain text box then take defaults from presentation.xml // if it is a plain text box then take defaults from presentation.xml
XMLSlideShow ppt = shape.getSheet().getSlideShow(); XMLSlideShow ppt = sheet.getSlideShow();
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel()); CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel());
if (themeProps != null) { if (themeProps != null) {
fetcher.isFetchingFromMaster = true; // TODO: determine master shape
ok = fetcher.fetch(themeProps); ok = fetcher.fetch(themeProps);
} }
} }
if (!ok) { if (ok) return true;
CTTextParagraphProperties defaultProps = _p.getDefaultMasterStyle(); CTTextParagraphProperties defaultProps = _p.getDefaultMasterStyle();
if(defaultProps != null) { if(defaultProps != null) {
fetcher.isFetchingFromMaster = true; // TODO: determine master shape
ok = fetcher.fetch(defaultProps); ok = fetcher.fetch(defaultProps);
} }
} if (ok) return true;
}
}
return ok; return false;
} }
void copy(XSLFTextRun r){ void copy(XSLFTextRun r){
@ -511,7 +526,7 @@ public class XSLFTextRun implements TextRun {
setFontFamily(srcFontFamily); setFontFamily(srcFontFamily);
} }
Color srcFontColor = r.getFontColor(); PaintStyle srcFontColor = r.getFontColor();
if(srcFontColor != null && !srcFontColor.equals(getFontColor())){ if(srcFontColor != null && !srcFontColor.equals(getFontColor())){
setFontColor(srcFontColor); setFontColor(srcFontColor);
} }

View File

@ -19,19 +19,22 @@
package org.apache.poi.xslf.util; package org.apache.poi.xslf.util;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import javax.imageio.ImageIO;
import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.FileOutputStream; import java.io.File;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import org.apache.poi.sl.SlideShowFactory;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.util.JvmBugs;
/** /**
* An utulity to convert slides of a .pptx slide show to a PNG image * An utulity to convert slides of a .pptx slide show to a PNG image
@ -40,22 +43,33 @@ import java.util.List;
*/ */
public class PPTX2PNG { public class PPTX2PNG {
static void usage(){ static void usage(String error){
System.out.println("Usage: PPTX2PNG [options] <pptx file>"); String msg =
System.out.println("Options:"); "Usage: PPTX2PNG [options] <ppt or pptx file>\n" +
System.out.println(" -scale <float> scale factor"); (error == null ? "" : ("Error: "+error+"\n")) +
System.out.println(" -slide <integer> 1-based index of a slide to render"); "Options:\n" +
" -scale <float> scale factor\n" +
" -slide <integer> 1-based index of a slide to render\n" +
" -format <type> png,gif,jpg (,null for testing)" +
" -outdir <dir> output directory, defaults to origin of the ppt/pptx file" +
" -quite do not write to console (for normal processing)";
System.out.println(msg);
// no System.exit here, as we also run in junit tests!
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
if (args.length == 0) { if (args.length == 0) {
usage(); usage(null);
return; return;
} }
int slidenum = -1; int slidenum = -1;
float scale = 1; float scale = 1;
String file = null; File file = null;
String format = "png";
File outdir = null;
boolean quite = false;
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-")) { if (args[i].startsWith("-")) {
@ -63,33 +77,69 @@ public class PPTX2PNG {
scale = Float.parseFloat(args[++i]); scale = Float.parseFloat(args[++i]);
} else if ("-slide".equals(args[i])) { } else if ("-slide".equals(args[i])) {
slidenum = Integer.parseInt(args[++i]); slidenum = Integer.parseInt(args[++i]);
} else if ("-format".equals(args[i])) {
format = args[++i];
} else if ("-outdir".equals(args[i])) {
outdir = new File(args[++i]);
} else if ("-quite".equals(args[i])) {
quite = true;
} }
} else { } else {
file = args[i]; file = new File(args[i]);
} }
} }
if(file == null){ if (file == null || !file.exists()) {
usage(); usage("File not specified or it doesn't exist");
return; return;
} }
System.out.println("Processing " + file); if (outdir == null) {
XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file)); outdir = file.getParentFile();
}
Dimension pgsize = ppt.getPageSize(); if (outdir == null || !outdir.exists() || !outdir.isDirectory()) {
usage("Output directory doesn't exist");
return;
}
if (scale < 0) {
usage("Invalid scale given");
return;
}
if (format == null || !format.matches("^(png|gif|jpg|null)$")) {
usage("Invalid format given");
return;
}
if (!quite) {
System.out.println("Processing " + file);
}
SlideShow ss = SlideShowFactory.create(file, null, true);
List<? extends Slide<?,?,?>> slides = ss.getSlides();
if (slidenum < -1 || slidenum == 0 || slidenum > slides.size()) {
usage("slidenum must be either -1 (for all) or within range: [1.."+slides.size()+"] for "+file);
return;
}
Dimension pgsize = ss.getPageSize();
int width = (int) (pgsize.width * scale); int width = (int) (pgsize.width * scale);
int height = (int) (pgsize.height * scale); int height = (int) (pgsize.height * scale);
List<XSLFSlide> slide = ppt.getSlides(); int slideNo=1;
for (int i = 0; i < slide.size(); i++) { for(Slide<?,?,?> slide : slides) {
if (slidenum != -1 && slidenum != (i + 1)) continue; if (slidenum == -1 || slideNo == slidenum) {
String title = slide.getTitle();
if (!quite) {
System.out.println("Rendering slide " + slideNo + (title == null ? "" : ": " + title));
}
String title = slide.get(i).getTitle(); BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
System.out.println("Rendering slide " + (i + 1) + (title == null ? "" : ": " + title));
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics(); Graphics2D graphics = img.createGraphics();
fixFonts(graphics);
// default rendering options // default rendering options
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
@ -97,21 +147,34 @@ public class PPTX2PNG {
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics.setColor(Color.white);
graphics.clearRect(0, 0, width, height);
graphics.scale(scale, scale); graphics.scale(scale, scale);
// draw stuff // draw stuff
slide.get(i).draw(graphics); slide.draw(graphics);
// save the result // save the result
int sep = file.lastIndexOf("."); if (!"null".equals(format)) {
String fname = file.substring(0, sep == -1 ? file.length() : sep) + "-" + (i + 1) +".png"; String outname = file.getName().replaceFirst(".pptx?", "");
FileOutputStream out = new FileOutputStream(fname); outname = String.format("%1$s-%2$04d.%3$s", outname, slideNo, format);
ImageIO.write(img, "png", out); File outfile = new File(outdir, outname);
out.close(); ImageIO.write(img, format, outfile);
} }
}
slideNo++;
}
if (!quite) {
System.out.println("Done"); System.out.println("Done");
} }
} }
@SuppressWarnings("unchecked")
private static void fixFonts(Graphics2D graphics) {
if (!JvmBugs.hasLineBreakMeasurerBug()) return;
Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
if (fontMap == null) fontMap = new HashMap<String,String>();
fontMap.put("Calibri", "Lucida Sans");
fontMap.put("Cambria", "Lucida Bright");
graphics.setRenderingHint(Drawable.FONT_MAP, fontMap);
}
}

View File

@ -19,16 +19,11 @@
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import java.awt.Dimension; import java.io.File;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.sl.draw.Drawable; import org.apache.poi.POIDataSamples;
import org.apache.poi.util.JvmBugs; import org.apache.poi.xslf.util.PPTX2PNG;
import org.apache.poi.xslf.XSLFTestDataSamples;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -44,7 +39,6 @@ public class TestPPTX2PNG {
@BeforeClass @BeforeClass
public static void activateJaxpDebug() { public static void activateJaxpDebug() {
jaxpDebugEnable = setDebugFld(true); jaxpDebugEnable = setDebugFld(true);
// setXmlInputFactory();
} }
@AfterClass @AfterClass
@ -67,47 +61,25 @@ public class TestPPTX2PNG {
} }
} }
// private static void setXmlInputFactory() {
// String propName = "javax.xml.stream.XMLInputFactory";
// String propVal = "com.sun.xml.internal.stream.XMLInputFactoryImpl";
// try {
// Class.forName(propVal);
// System.setProperty(propName, propVal);
// } catch (Exception e){
// // ignore
// }
// }
@Test @Test
public void render() throws Exception { public void render() throws Exception {
String[] testFiles = {"backgrounds.pptx","layouts.pptx", "sample.pptx", "shapes.pptx", "themes.pptx",}; POIDataSamples samples = POIDataSamples.getSlideShowInstance();
String[] testFiles = {"alterman_security.ppt","alterman_security.pptx","KEY02.pptx","themes.pptx","backgrounds.pptx","layouts.pptx", "sample.pptx", "shapes.pptx",};
String[] args = {
"-format", "null", // png,gif,jpg or null for test
"-slide", "-1", // -1 for all
"-outdir", new File("build/tmp/").getCanonicalPath(),
"-quite",
"dummyfile"
};
for(String sampleFile : testFiles){ for(String sampleFile : testFiles){
args[args.length-1] = samples.getFile(sampleFile).getCanonicalPath();
try { try {
XMLSlideShow pptx = XSLFTestDataSamples.openSampleDocument(sampleFile); PPTX2PNG.main(args);
Dimension pg = pptx.getPageSize();
//int slideNo=1;
for(XSLFSlide slide : pptx.getSlides()){
BufferedImage img = new BufferedImage(pg.width, pg.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics();
fixFonts(graphics);
slide.draw(graphics);
// ImageIO.write(img, "PNG", new File("build/tmp/"+sampleFile.replaceFirst(".pptx?", "-")+slideNo+".png"));
//slideNo++;
}
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw new IllegalStateException("While reading file " + sampleFile, e); throw new IllegalStateException("While reading file " + sampleFile, e);
} }
} }
} }
@SuppressWarnings("unchecked")
private void fixFonts(Graphics2D graphics) {
if (!JvmBugs.hasLineBreakMeasurerBug()) return;
Map<String,String> fontMap = (Map<String,String>)graphics.getRenderingHint(Drawable.FONT_MAP);
if (fontMap == null) fontMap = new HashMap<String,String>();
fontMap.put("Calibri", "Lucida Sans");
fontMap.put("Cambria", "Lucida Bright");
graphics.setRenderingHint(Drawable.FONT_MAP, fontMap);
}
} }

View File

@ -16,7 +16,12 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.awt.Color; import java.awt.Color;
import java.io.IOException; import java.io.IOException;

View File

@ -16,9 +16,15 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.junit.Assert.*; import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.awt.Color; import java.awt.Color;
import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.poi.xslf.XSLFTestDataSamples; import org.apache.poi.xslf.XSLFTestDataSamples;
@ -98,7 +104,7 @@ public class TestXSLFSlide {
} }
@Test @Test
public void testCreateSlide(){ public void testCreateSlide() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
assertEquals(0, ppt.getSlides().size()); assertEquals(0, ppt.getSlides().size());
@ -108,10 +114,12 @@ public class TestXSLFSlide {
assertFalse(slide.getFollowMasterGraphics()); assertFalse(slide.getFollowMasterGraphics());
slide.setFollowMasterGraphics(true); slide.setFollowMasterGraphics(true);
assertTrue(slide.getFollowMasterGraphics()); assertTrue(slide.getFollowMasterGraphics());
ppt.close();
} }
@Test @Test
public void testImportContent(){ public void testImportContent() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
XMLSlideShow src = XSLFTestDataSamples.openSampleDocument("themes.pptx"); XMLSlideShow src = XSLFTestDataSamples.openSampleDocument("themes.pptx");
@ -128,7 +136,7 @@ public class TestXSLFSlide {
assertEquals(40.0, r1.getFontSize(), 0); assertEquals(40.0, r1.getFontSize(), 0);
assertTrue(r1.isBold()); assertTrue(r1.isBold());
assertTrue(r1.isItalic()); assertTrue(r1.isItalic());
assertEquals(new Color(148, 198, 0), r1.getFontColor()); assertTrue(sameColor(new Color(148, 198, 0), r1.getFontColor()));
assertNull(sh1.getFillColor()); assertNull(sh1.getFillColor());
assertNull(sh1.getLineColor()); assertNull(sh1.getLineColor());
@ -141,7 +149,7 @@ public class TestXSLFSlide {
assertEquals(18.0, r2.getFontSize(), 0); assertEquals(18.0, r2.getFontSize(), 0);
assertFalse(r2.isBold()); assertFalse(r2.isBold());
assertFalse(r2.isItalic()); assertFalse(r2.isItalic());
assertEquals(Color.white, r2.getFontColor()); assertTrue(sameColor(Color.white, r2.getFontColor()));
assertEquals(new Color(148, 198, 0), sh2.getFillColor()); assertEquals(new Color(148, 198, 0), sh2.getFillColor());
assertEquals(new Color(148, 198, 0), sh2.getLineColor()); // slightly different from PowerPoint! assertEquals(new Color(148, 198, 0), sh2.getLineColor()); // slightly different from PowerPoint!
@ -157,17 +165,19 @@ public class TestXSLFSlide {
//assertEquals(32.4.0, r3.getFontSize()); //assertEquals(32.4.0, r3.getFontSize());
assertTrue(r3.isBold()); assertTrue(r3.isBold());
assertTrue(r3.isItalic()); assertTrue(r3.isItalic());
assertEquals(new Color(148, 198, 0), r3.getFontColor()); assertTrue(sameColor(new Color(148, 198, 0), r3.getFontColor()));
assertNull(sh3.getFillColor()); assertNull(sh3.getFillColor());
assertNull(sh3.getLineColor()); assertNull(sh3.getLineColor());
XSLFPictureShape sh4 = (XSLFPictureShape)shapes2.get(1); XSLFPictureShape sh4 = (XSLFPictureShape)shapes2.get(1);
XSLFPictureShape srcPic = (XSLFPictureShape)src.getSlides().get(4).getShapes().get(1); XSLFPictureShape srcPic = (XSLFPictureShape)src.getSlides().get(4).getShapes().get(1);
assertArrayEquals(sh4.getPictureData().getData(), srcPic.getPictureData().getData()); assertArrayEquals(sh4.getPictureData().getData(), srcPic.getPictureData().getData());
ppt.close();
} }
@Test @Test
public void testMergeSlides(){ public void testMergeSlides() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
String[] pptx = {"shapes.pptx", "themes.pptx", "layouts.pptx", "backgrounds.pptx"}; String[] pptx = {"shapes.pptx", "themes.pptx", "layouts.pptx", "backgrounds.pptx"};
@ -179,5 +189,7 @@ public class TestXSLFSlide {
} }
} }
assertEquals(30, ppt.getSlides().size()); assertEquals(30, ppt.getSlides().size());
ppt.close();
} }
} }

View File

@ -16,19 +16,24 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.junit.Assert.*; import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.awt.*; import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.poi.sl.draw.DrawTextFragment; import org.apache.poi.sl.draw.DrawTextFragment;
import org.apache.poi.sl.draw.DrawTextParagraph; import org.apache.poi.sl.draw.DrawTextParagraph;
import org.apache.poi.sl.usermodel.AutoNumberingScheme; import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.xslf.XSLFTestDataSamples; import org.apache.poi.xslf.XSLFTestDataSamples;
import org.junit.Assume; import org.junit.Assume;
import org.junit.Test; import org.junit.Test;
@ -37,7 +42,7 @@ import org.junit.Test;
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public class TestXSLFTextParagraph { public class TestXSLFTextParagraph {
private static POILogger _logger = POILogFactory.getLogger(XSLFTextParagraph.class); // private static POILogger _logger = POILogFactory.getLogger(XSLFTextParagraph.class);
static class DrawTextParagraphProxy extends DrawTextParagraph<XSLFTextRun> { static class DrawTextParagraphProxy extends DrawTextParagraph<XSLFTextRun> {
DrawTextParagraphProxy(XSLFTextParagraph p) { DrawTextParagraphProxy(XSLFTextParagraph p) {
@ -58,7 +63,7 @@ public class TestXSLFTextParagraph {
} }
@Test @Test
public void testWrappingWidth() throws Exception { public void testWrappingWidth() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide(); XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape(); XSLFTextShape sh = slide.createAutoShape();
@ -142,6 +147,8 @@ public class TestXSLFTextParagraph {
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;
assertEquals(244.0, expectedWidth, 0); // 300 - 10 - 10 - 36 assertEquals(244.0, expectedWidth, 0); // 300 - 10 - 10 - 36
assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0); assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0);
ppt.close();
} }
/** /**
@ -149,7 +156,7 @@ public class TestXSLFTextParagraph {
* This test requires that the Arial font is available and will run only on windows * This test requires that the Arial font is available and will run only on windows
*/ */
@Test @Test
public void testBreakLines(){ public void testBreakLines() throws IOException {
String os = System.getProperty("os.name"); String os = System.getProperty("os.name");
Assume.assumeTrue("Skipping testBreakLines(), it is executed only on Windows machines", (os != null && os.contains("Windows"))); Assume.assumeTrue("Skipping testBreakLines(), it is executed only on Windows machines", (os != null && os.contains("Windows")));
@ -237,10 +244,11 @@ public class TestXSLFTextParagraph {
// the first line is at least two times higher than the second // the first line is at least two times higher than the second
assertTrue(lines.get(0).getHeight() > lines.get(1).getHeight()*2); assertTrue(lines.get(0).getHeight() > lines.get(1).getHeight()*2);
ppt.close();
} }
@Test @Test
public void testThemeInheritance(){ public void testThemeInheritance() throws IOException {
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("prProps.pptx"); XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("prProps.pptx");
List<XSLFShape> shapes = ppt.getSlides().get(0).getShapes(); List<XSLFShape> shapes = ppt.getSlides().get(0).getShapes();
XSLFTextShape sh1 = (XSLFTextShape)shapes.get(0); XSLFTextShape sh1 = (XSLFTextShape)shapes.get(0);
@ -252,10 +260,11 @@ public class TestXSLFTextParagraph {
XSLFTextShape sh3 = (XSLFTextShape)shapes.get(2); XSLFTextShape sh3 = (XSLFTextShape)shapes.get(2);
assertEquals("Foundation", sh3.getText()); assertEquals("Foundation", sh3.getText());
assertEquals(TextAlign.CENTER, sh3.getTextParagraphs().get(0).getTextAlign()); assertEquals(TextAlign.CENTER, sh3.getTextParagraphs().get(0).getTextAlign());
ppt.close();
} }
@Test @Test
public void testParagraphProperties(){ public void testParagraphProperties() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide(); XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape(); XSLFTextShape sh = slide.createAutoShape();
@ -275,7 +284,7 @@ public class TestXSLFTextParagraph {
assertEquals(null, p.getBulletFontColor()); assertEquals(null, p.getBulletFontColor());
p.setBulletFontColor(Color.red); p.setBulletFontColor(Color.red);
assertEquals(Color.red, p.getBulletFontColor()); assertTrue(sameColor(Color.red, p.getBulletFontColor()));
assertNull(p.getBulletFontSize()); assertNull(p.getBulletFontSize());
p.setBulletFontSize(200.); p.setBulletFontSize(200.);
@ -342,11 +351,13 @@ public class TestXSLFTextParagraph {
assertEquals(72.0, p.getDefaultTabSize(), 0); assertEquals(72.0, p.getDefaultTabSize(), 0);
ppt.close();
} }
@Test @Test(expected = IllegalStateException.class)
public void testLineBreak(){ public void testLineBreak() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
try {
XSLFSlide slide = ppt.createSlide(); XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape(); XSLFTextShape sh = slide.createAutoShape();
@ -365,11 +376,10 @@ public class TestXSLFTextParagraph {
assertEquals("Hello,\nWorld!\n",sh.getText()); assertEquals("Hello,\nWorld!\n",sh.getText());
try { // "You cannot change text of a line break, it is always '\\n'"
r2.setText("aaa"); r2.setText("aaa");
fail("Expected IllegalStateException"); } finally {
} catch (IllegalStateException e){ ppt.close();
assertEquals("You cannot change text of a line break, it is always '\\n'", e.getMessage());
} }
} }
} }

View File

@ -18,16 +18,23 @@
*/ */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import junit.framework.TestCase; import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.awt.*; import java.awt.Color;
import java.io.IOException;
import org.junit.Test;
/** /**
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public class TestXSLFTextRun extends TestCase { public class TestXSLFTextRun {
public void testRunProperties(){ @Test
public void testRunProperties() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide(); XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape(); XSLFTextShape sh = slide.createAutoShape();
@ -35,26 +42,26 @@ public class TestXSLFTextRun extends TestCase {
XSLFTextRun r = sh.addNewTextParagraph().addNewTextRun(); XSLFTextRun r = sh.addNewTextParagraph().addNewTextRun();
assertEquals("en-US", r.getRPr().getLang()); assertEquals("en-US", r.getRPr().getLang());
assertEquals(0., r.getCharacterSpacing()); assertEquals(0., r.getCharacterSpacing(), 0);
r.setCharacterSpacing(3); r.setCharacterSpacing(3);
assertEquals(3., r.getCharacterSpacing()); assertEquals(3., r.getCharacterSpacing(), 0);
r.setCharacterSpacing(-3); r.setCharacterSpacing(-3);
assertEquals(-3., r.getCharacterSpacing()); assertEquals(-3., r.getCharacterSpacing(), 0);
r.setCharacterSpacing(0); r.setCharacterSpacing(0);
assertEquals(0., r.getCharacterSpacing()); assertEquals(0., r.getCharacterSpacing(), 0);
assertFalse(r.getRPr().isSetSpc()); assertFalse(r.getRPr().isSetSpc());
assertEquals(Color.black, r.getFontColor()); assertTrue(sameColor(Color.black, r.getFontColor()));
r.setFontColor(Color.red); r.setFontColor(Color.red);
assertEquals(Color.red, r.getFontColor()); assertTrue(sameColor(Color.red, r.getFontColor()));
assertEquals("Calibri", r.getFontFamily()); assertEquals("Calibri", r.getFontFamily());
r.setFontFamily("Arial"); r.setFontFamily("Arial");
assertEquals("Arial", r.getFontFamily()); assertEquals("Arial", r.getFontFamily());
assertEquals(18.0, r.getFontSize()); assertEquals(18.0, r.getFontSize(), 0);
r.setFontSize(13.0); r.setFontSize(13.0);
assertEquals(13.0, r.getFontSize()); assertEquals(13.0, r.getFontSize(), 0);
assertEquals(false, r.isSuperscript()); assertEquals(false, r.isSuperscript());
r.setSuperscript(true); r.setSuperscript(true);
@ -67,5 +74,7 @@ public class TestXSLFTextRun extends TestCase {
assertEquals(true, r.isSubscript()); assertEquals(true, r.isSubscript());
r.setSubscript(false); r.setSubscript(false);
assertEquals(false, r.isSubscript()); assertEquals(false, r.isSubscript());
ppt.close();
} }
} }

View File

@ -16,16 +16,26 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.junit.Assert.*; import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.awt.Color; import java.awt.Color;
import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.xslf.XSLFTestDataSamples; import org.apache.poi.xslf.XSLFTestDataSamples;
import org.junit.Test; import org.junit.Test;
import org.openxmlformats.schemas.drawingml.x2006.main.*; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder; import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
@ -82,7 +92,7 @@ public class TestXSLFTextShape {
XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals("Calibri", r1.getFontFamily()); assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0); assertEquals(44.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor()); assertTrue(sameColor(Color.black, r1.getFontColor()));
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
CTPlaceholder ph2 = shape2.getCTPlaceholder(); CTPlaceholder ph2 = shape2.getCTPlaceholder();
@ -151,7 +161,7 @@ public class TestXSLFTextShape {
XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals("Calibri", r1.getFontFamily()); assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0); assertEquals(44.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor()); assertTrue(sameColor(Color.black, r1.getFontColor()));
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
CTPlaceholder ph2 = shape2.getCTPlaceholder(); CTPlaceholder ph2 = shape2.getCTPlaceholder();
@ -262,7 +272,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.LEFT, r1.getParentParagraph().getTextAlign()); assertEquals(TextAlign.LEFT, r1.getParentParagraph().getTextAlign());
assertEquals("Calibri", r1.getFontFamily()); assertEquals("Calibri", r1.getFontFamily());
assertEquals(40.0, r1.getFontSize(), 0); assertEquals(40.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor()); assertTrue(sameColor(Color.black, r1.getFontColor()));
assertTrue(r1.isBold()); assertTrue(r1.isBold());
assertFalse(r1.isItalic()); assertFalse(r1.isItalic());
assertFalse(r1.isUnderlined()); assertFalse(r1.isUnderlined());
@ -336,7 +346,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign()); assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign());
assertEquals("Calibri", r1.getFontFamily()); assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0); assertEquals(44.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor()); assertTrue(sameColor(Color.black, r1.getFontColor()));
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
CTPlaceholder ph2 = shape2.getCTPlaceholder(); CTPlaceholder ph2 = shape2.getCTPlaceholder();
@ -404,7 +414,7 @@ public class TestXSLFTextShape {
assertEquals(0, pr5.getParentParagraph().getIndentLevel()); assertEquals(0, pr5.getParentParagraph().getIndentLevel());
assertEquals("Right", pr5.getRawText()); assertEquals("Right", pr5.getRawText());
assertEquals("Calibri", pr5.getFontFamily()); assertEquals("Calibri", pr5.getFontFamily());
assertEquals(Color.black, pr5.getFontColor()); assertTrue(sameColor(Color.black, pr5.getFontColor()));
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -444,7 +454,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign()); assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign());
assertEquals("Calibri", r1.getFontFamily()); assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0); assertEquals(44.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor()); assertTrue(sameColor(Color.black, r1.getFontColor()));
assertFalse(r1.isBold()); assertFalse(r1.isBold());
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
@ -517,7 +527,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.LEFT, r1.getParentParagraph().getTextAlign()); assertEquals(TextAlign.LEFT, r1.getParentParagraph().getTextAlign());
assertEquals("Calibri", r1.getFontFamily()); assertEquals("Calibri", r1.getFontFamily());
assertEquals(20.0, r1.getFontSize(), 0); assertEquals(20.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor()); assertTrue(sameColor(Color.black, r1.getFontColor()));
assertTrue(r1.isBold()); assertTrue(r1.isBold());
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
@ -605,7 +615,7 @@ public class TestXSLFTextShape {
assertEquals("Calibri", r1.getFontFamily()); assertEquals("Calibri", r1.getFontFamily());
assertEquals(12.0, r1.getFontSize(), 0); assertEquals(12.0, r1.getFontSize(), 0);
// TODO calculation of tint is incorrect // TODO calculation of tint is incorrect
assertEquals(new Color(64,64,64), r1.getFontColor()); assertTrue(sameColor(new Color(64,64,64), r1.getFontColor()));
XSLFTextShape dt = (XSLFTextShape)slide.getPlaceholderByType(STPlaceholderType.INT_DT); XSLFTextShape dt = (XSLFTextShape)slide.getPlaceholderByType(STPlaceholderType.INT_DT);
assertEquals("Friday, October 21, 2011", dt.getText()); assertEquals("Friday, October 21, 2011", dt.getText());
@ -615,7 +625,7 @@ public class TestXSLFTextShape {
} }
@Test @Test
public void testTitleStyles(){ public void testTitleStyles() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
XSLFSlideMaster master = ppt.getSlideMasters().get(0); XSLFSlideMaster master = ppt.getSlideMasters().get(0);
@ -693,10 +703,12 @@ public class TestXSLFTextShape {
assertEquals("Calibri", textRun.getFontFamily()); assertEquals("Calibri", textRun.getFontFamily());
lv5PPr.setAlgn(STTextAlignType.CTR); lv5PPr.setAlgn(STTextAlignType.CTR);
assertEquals(TextAlign.CENTER, paragraph.getTextAlign()); assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
ppt.close();
} }
@Test @Test
public void testBodyStyles(){ public void testBodyStyles() throws IOException {
XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow ppt = new XMLSlideShow();
XSLFSlideMaster master = ppt.getSlideMasters().get(0); XSLFSlideMaster master = ppt.getSlideMasters().get(0);
@ -896,6 +908,6 @@ public class TestXSLFTextShape {
lv3PPr.setAlgn(STTextAlignType.CTR); lv3PPr.setAlgn(STTextAlignType.CTR);
assertEquals(TextAlign.CENTER, p3.getTextAlign()); assertEquals(TextAlign.CENTER, p3.getTextAlign());
ppt.close();
} }
} }

View File

@ -16,6 +16,7 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.awt.Color; import java.awt.Color;
@ -66,7 +67,7 @@ public class TestXSLFTheme {
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 3"); XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 3");
XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals(Color.white, run1.getFontColor()); assertTrue(sameColor(Color.white, run1.getFontColor()));
assertEquals(new Color(79, 129, 189), sh1.getFillColor()); assertEquals(new Color(79, 129, 189), sh1.getFillColor());
assertTrue(sh1.getFillStyle().getPaint() instanceof SolidPaint) ; // solid fill assertTrue(sh1.getFillStyle().getPaint() instanceof SolidPaint) ; // solid fill
@ -89,13 +90,13 @@ public class TestXSLFTheme {
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 4"); XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 4");
XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals(Color.white, run1.getFontColor()); assertTrue(sameColor(Color.white, run1.getFontColor()));
assertEquals(new Color(148, 198, 0), sh1.getFillColor()); assertEquals(new Color(148, 198, 0), sh1.getFillColor());
assertTrue(sh1.getFillStyle().getPaint() instanceof SolidPaint) ; // solid fill assertTrue(sh1.getFillStyle().getPaint() instanceof SolidPaint) ; // solid fill
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 3"); XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 3");
XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals(new Color(148, 198, 0), run2.getFontColor()); assertTrue(sameColor(new Color(148, 198, 0), run2.getFontColor()));
assertNull(sh2.getFillColor()); // no fill assertNull(sh2.getFillColor()); // no fill
assertTrue(slide.getSlideLayout().getFollowMasterGraphics()); assertTrue(slide.getSlideLayout().getFollowMasterGraphics());
@ -107,7 +108,7 @@ public class TestXSLFTheme {
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 1"); XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 1");
XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals(new Color(148, 198, 0), run2.getFontColor()); assertTrue(sameColor(new Color(148, 198, 0), run2.getFontColor()));
assertNull(sh2.getFillColor()); // no fill assertNull(sh2.getFillColor()); // no fill
// font size is 40pt and scale factor is 90% // font size is 40pt and scale factor is 90%
assertEquals(36.0, run2.getFontSize(), 0); assertEquals(36.0, run2.getFontSize(), 0);
@ -119,12 +120,12 @@ public class TestXSLFTheme {
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Subtitle 3"); XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Subtitle 3");
XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals(new Color(66, 66, 66), run1.getFontColor()); assertTrue(sameColor(new Color(66, 66, 66), run1.getFontColor()));
assertNull(sh1.getFillColor()); // no fill assertNull(sh1.getFillColor()); // no fill
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 2"); XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 2");
XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals(new Color(148, 198, 0), run2.getFontColor()); assertTrue(sameColor(new Color(148, 198, 0), run2.getFontColor()));
assertNull(sh2.getFillColor()); // no fill assertNull(sh2.getFillColor()); // no fill
assertFalse(slide.getSlideLayout().getFollowMasterGraphics()); assertFalse(slide.getSlideLayout().getFollowMasterGraphics());
@ -154,12 +155,12 @@ public class TestXSLFTheme {
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Title 3"); XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Title 3");
XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals(Color.white, run1.getFontColor()); assertTrue(sameColor(Color.white, run1.getFontColor()));
assertNull(sh1.getFillColor()); // no fill assertNull(sh1.getFillColor()); // no fill
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Subtitle 4"); XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Subtitle 4");
XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals(Color.white, run2.getFontColor()); assertTrue(sameColor(Color.white, run2.getFontColor()));
assertNull(sh2.getFillColor()); // no fill assertNull(sh2.getFillColor()); // no fill
} }
} }

View File

@ -17,8 +17,14 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.hslf.usermodel.*; import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hslf.usermodel.HSLFGroupShape;
import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
import org.apache.poi.hslf.usermodel.HSLFTextShape;
import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.ShapeType;
@ -27,7 +33,7 @@ import org.apache.poi.sl.usermodel.ShapeType;
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public final class Line extends HSLFSimpleShape { public final class Line extends HSLFTextShape implements org.apache.poi.sl.usermodel.Line<HSLFTextParagraph> {
public Line(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape> parent){ public Line(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape> parent){
super(escherRecord, parent); super(escherRecord, parent);
} }
@ -64,23 +70,23 @@ public final class Line extends HSLFSimpleShape {
return _escherContainer; return _escherContainer;
} }
/** // /**
* Sets the orientation of the line, if inverse is false, then line goes // * Sets the orientation of the line, if inverse is false, then line goes
* from top-left to bottom-right, otherwise use inverse equals true // * from top-left to bottom-right, otherwise use inverse equals true
* // *
* @param inverse the orientation of the line // * @param inverse the orientation of the line
*/ // */
public void setInverse(boolean inverse) { // public void setInverse(boolean inverse) {
setShapeType(inverse ? ShapeType.LINE_INV : ShapeType.LINE); // setShapeType(inverse ? ShapeType.LINE_INV : ShapeType.LINE);
} // }
//
/** // /**
* Gets the orientation of the line, if inverse is false, then line goes // * Gets the orientation of the line, if inverse is false, then line goes
* from top-left to bottom-right, otherwise inverse equals true // * from top-left to bottom-right, otherwise inverse equals true
* // *
* @return inverse the orientation of the line // * @return inverse the orientation of the line
*/ // */
public boolean isInverse() { // public boolean isInverse() {
return (getShapeType() == ShapeType.LINE_INV); // return (getShapeType() == ShapeType.LINE_INV);
} // }
} }

View File

@ -18,19 +18,49 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import java.awt.*; import java.awt.BasicStroke;
import java.awt.font.*; import java.awt.Color;
import java.awt.geom.*; import java.awt.Composite;
import java.awt.image.*; import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage; import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
import java.util.Map; import java.util.Map;
import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hslf.usermodel.HSLFFreeformShape;
import org.apache.poi.hslf.usermodel.HSLFGroupShape;
import org.apache.poi.hslf.usermodel.HSLFSimpleShape;
import org.apache.poi.hslf.usermodel.HSLFTextBox;
import org.apache.poi.hslf.usermodel.HSLFTextRun;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.StrokeStyle; import org.apache.poi.sl.usermodel.StrokeStyle;
import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
@ -259,7 +289,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable {
rt.setFontSize((double)_font.getSize()); rt.setFontSize((double)_font.getSize());
rt.setFontFamily(_font.getFamily()); rt.setFontFamily(_font.getFamily());
if (getColor() != null) rt.setFontColor(getColor()); if (getColor() != null) rt.setFontColor(DrawPaint.createSolidPaint(getColor()));
if (_font.isBold()) rt.setBold(true); if (_font.isBold()) rt.setBold(true);
if (_font.isItalic()) rt.setItalic(true); if (_font.isItalic()) rt.setItalic(true);

View File

@ -22,10 +22,16 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import org.apache.poi.ddf.*; import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.hslf.record.Document; import org.apache.poi.hslf.record.Document;
import org.apache.poi.sl.usermodel.*; import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.FillStyle;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
@ -113,20 +119,8 @@ public final class HSLFFill {
return new FillStyle() { return new FillStyle() {
public PaintStyle getPaint() { public PaintStyle getPaint() {
switch (getFillType()) { switch (getFillType()) {
case FILL_SOLID: { case FILL_SOLID:
return new SolidPaint() { return DrawPaint.createSolidPaint(getForegroundColor());
public ColorStyle getSolidColor() {
return new ColorStyle() {
public Color getColor() { return getForegroundColor(); }
public int getAlpha() { return -1; }
public int getLumOff() { return -1; }
public int getLumMod() { return -1; }
public int getShade() { return -1; }
public int getTint() { return -1; }
};
}
};
}
case FILL_PICTURE: { case FILL_PICTURE: {
final HSLFPictureData pd = getPictureData(); final HSLFPictureData pd = getPictureData();
if (pd == null) break; if (pd == null) break;
@ -149,7 +143,7 @@ public final class HSLFFill {
logger.log(POILogger.WARN, "unsuported fill type: " + getFillType()); logger.log(POILogger.WARN, "unsuported fill type: " + getFillType());
break; break;
} }
return PaintStyle.TRANSPARENT_PAINT; return null;
} }
}; };
} }

View File

@ -188,16 +188,14 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFSl
// Complex Accesser methods follow // Complex Accesser methods follow
/** /**
* Return title of this slide or <code>null</code> if the slide does not have title.
* <p> * <p>
* The title is a run of text of type <code>TextHeaderAtom.CENTER_TITLE_TYPE</code> or * The title is a run of text of type <code>TextHeaderAtom.CENTER_TITLE_TYPE</code> or
* <code>TextHeaderAtom.TITLE_TYPE</code> * <code>TextHeaderAtom.TITLE_TYPE</code>
* </p> * </p>
* *
* @see TextHeaderAtom * @see TextHeaderAtom
*
* @return title of this slide
*/ */
@Override
public String getTitle(){ public String getTitle(){
for (List<HSLFTextParagraph> tp : getTextParagraphs()) { for (List<HSLFTextParagraph> tp : getTextParagraphs()) {
if (tp.isEmpty()) continue; if (tp.isEmpty()) continue;

View File

@ -132,6 +132,20 @@ public final class HSLFSlideShow implements SlideShow {
this(new HSLFSlideShowImpl(inputStream)); this(new HSLFSlideShowImpl(inputStream));
} }
/**
* Constructs a Powerpoint document from an POIFSFileSystem.
*/
public HSLFSlideShow(POIFSFileSystem inputStream) throws IOException {
this(new HSLFSlideShowImpl(inputStream));
}
/**
* Constructs a Powerpoint document from an DirectoryNode.
*/
public HSLFSlideShow(DirectoryNode root) throws IOException {
this(new HSLFSlideShowImpl(root));
}
/** /**
* Use the PersistPtrHolder entries to figure out what is the "most recent" * Use the PersistPtrHolder entries to figure out what is the "most recent"
* version of all the core records (Document, Notes, Slide etc), and save a * version of all the core records (Document, Notes, Slide etc), and save a

View File

@ -27,7 +27,10 @@ import org.apache.poi.hslf.model.PPFont;
import org.apache.poi.hslf.model.textproperties.*; import org.apache.poi.hslf.model.textproperties.*;
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType; import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.*;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.AutoNumberingScheme; import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.TextParagraph; import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.util.*; import org.apache.poi.util.*;
@ -403,8 +406,24 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
} }
@Override @Override
public Color getBulletFontColor() { public void setBulletFontColor(Color color) {
return HSLFTextParagraph.this.getBulletColor(); setBulletFontColor(DrawPaint.createSolidPaint(color));
}
@Override
public void setBulletFontColor(PaintStyle color) {
if (!(color instanceof SolidPaint)) {
throw new IllegalArgumentException("HSLF only supports SolidPaint");
}
SolidPaint sp = (SolidPaint)color;
Color col = DrawPaint.applyColorTransform(sp.getSolidColor());
HSLFTextParagraph.this.setBulletColor(col);
}
@Override
public PaintStyle getBulletFontColor() {
Color col = HSLFTextParagraph.this.getBulletColor();
return DrawPaint.createSolidPaint(col);
} }
@Override @Override
@ -497,7 +516,9 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
TextProp tp = getPropVal(_paragraphStyle, "bullet.color", this); TextProp tp = getPropVal(_paragraphStyle, "bullet.color", this);
if (tp == null) { if (tp == null) {
// if bullet color is undefined, return color of first run // if bullet color is undefined, return color of first run
return (_runs.isEmpty()) ? null : _runs.get(0).getFontColor(); if (_runs.isEmpty()) return null;
SolidPaint sp = _runs.get(0).getFontColor();
return DrawPaint.applyColorTransform(sp.getSolidColor());
} }
return getColorFromColorIndexStruct(tp.getValue(), _sheet); return getColorFromColorIndexStruct(tp.getValue(), _sheet);

View File

@ -21,8 +21,14 @@ import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.getPropVal;
import java.awt.Color; import java.awt.Color;
import org.apache.poi.hslf.model.textproperties.*; import org.apache.poi.hslf.model.textproperties.BitMaskTextProp;
import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
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.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.TextRun; import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
@ -315,13 +321,15 @@ public final class HSLFTextRun implements TextRun {
} }
/** /**
* @return font color as RGB value * @return font color as PaintStyle
* @see java.awt.Color
*/ */
public Color getFontColor() { @Override
public SolidPaint getFontColor() {
TextProp tp = getPropVal(characterStyle, "font.color", parentParagraph); TextProp tp = getPropVal(characterStyle, "font.color", parentParagraph);
return (tp == null) ? null if (tp == null) return null;
: HSLFTextParagraph.getColorFromColorIndexStruct(tp.getValue(), parentParagraph.getSheet()); Color color = HSLFTextParagraph.getColorFromColorIndexStruct(tp.getValue(), parentParagraph.getSheet());
SolidPaint ps = DrawPaint.createSolidPaint(color);
return ps;
} }
/** /**
@ -334,12 +342,21 @@ public final class HSLFTextRun implements TextRun {
setCharTextPropVal("font.color", bgr); setCharTextPropVal("font.color", bgr);
} }
/**
* Sets color of the text, as a java.awt.Color @Override
*/
public void setFontColor(Color color) { public void setFontColor(Color color) {
setFontColor(DrawPaint.createSolidPaint(color));
}
@Override
public void setFontColor(PaintStyle color) {
if (!(color instanceof SolidPaint)) {
throw new IllegalArgumentException("HSLF only supports solid paint");
}
// In PowerPont RGB bytes are swapped, as BGR // In PowerPont RGB bytes are swapped, as BGR
int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB(); SolidPaint sp = (SolidPaint)color;
Color c = DrawPaint.applyColorTransform(sp.getSolidColor());
int rgb = new Color(c.getBlue(), c.getGreen(), c.getRed(), 254).getRGB();
setFontColor(rgb); setFontColor(rgb);
} }

View File

@ -17,6 +17,7 @@
package org.apache.poi.hslf.model; package org.apache.poi.hslf.model;
import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@ -53,9 +54,9 @@ import org.apache.poi.hslf.usermodel.HSLFTextBox;
import org.apache.poi.hslf.usermodel.HSLFTextParagraph; import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
import org.apache.poi.hslf.usermodel.HSLFTextRun; import org.apache.poi.hslf.usermodel.HSLFTextRun;
import org.apache.poi.hslf.usermodel.HSLFTextShape; import org.apache.poi.hslf.usermodel.HSLFTextShape;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -189,16 +190,16 @@ public final class TestShapes {
List<HSLFTextParagraph> para = tb.getTextParagraphs(); List<HSLFTextParagraph> para = tb.getTextParagraphs();
HSLFTextRun tr = para.get(0).getTextRuns().get(0); HSLFTextRun tr = para.get(0).getTextRuns().get(0);
assertEquals("para 1 run 1. ", tr.getRawText()); assertEquals("para 1 run 1. ", tr.getRawText());
assertEquals(Color.black, tr.getFontColor()); assertTrue(sameColor(Color.black, tr.getFontColor()));
tr = para.get(0).getTextRuns().get(1); tr = para.get(0).getTextRuns().get(1);
assertEquals("para 1 run 2.\r", tr.getRawText()); assertEquals("para 1 run 2.\r", tr.getRawText());
assertEquals(Color.red, tr.getFontColor()); assertTrue(sameColor(Color.red, tr.getFontColor()));
tr = para.get(1).getTextRuns().get(0); tr = para.get(1).getTextRuns().get(0);
assertEquals("para 2 run 1. ", tr.getRawText()); assertEquals("para 2 run 1. ", tr.getRawText());
assertEquals(Color.yellow, tr.getFontColor()); assertTrue(sameColor(Color.yellow, tr.getFontColor()));
tr = para.get(1).getTextRuns().get(1); tr = para.get(1).getTextRuns().get(1);
assertEquals("para 2 run 2. para 2 run 3.", tr.getRawText()); assertEquals("para 2 run 2. para 2 run 3.", tr.getRawText());
assertEquals(Color.black, tr.getFontColor()); assertTrue(sameColor(Color.black, tr.getFontColor()));
assertTrue(tr.isStrikethrough()); assertTrue(tr.isStrikethrough());
} }
@ -235,7 +236,7 @@ public final class TestShapes {
assertTrue(rt.isItalic()); assertTrue(rt.isItalic());
assertFalse(rt.isUnderlined()); assertFalse(rt.isUnderlined());
assertEquals("Arial", rt.getFontFamily()); assertEquals("Arial", rt.getFontFamily());
assertEquals(Color.red, rt.getFontColor()); assertTrue(sameColor(Color.red, rt.getFontColor()));
// Serialize and read again // Serialize and read again
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
@ -255,7 +256,7 @@ public final class TestShapes {
assertTrue(rt.isItalic()); assertTrue(rt.isItalic());
assertFalse(rt.isUnderlined()); assertFalse(rt.isUnderlined());
assertEquals("Arial", rt.getFontFamily()); assertEquals("Arial", rt.getFontFamily());
assertEquals(Color.red, rt.getFontColor()); assertTrue(sameColor(Color.red, rt.getFontColor()));
} }
/** /**

View File

@ -17,15 +17,26 @@
package org.apache.poi.hslf.usermodel; package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.*; import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.awt.Color; import java.awt.Color;
import java.io.*; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.model.textproperties.TextPropCollection; import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.TextBytesAtom;
import org.apache.poi.hslf.record.TextCharsAtom;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -539,7 +550,7 @@ public final class TestTextRun {
List<HSLFTextParagraph> run = tx.getTextParagraphs(); List<HSLFTextParagraph> run = tx.getTextParagraphs();
HSLFTextRun rt = run.get(0).getTextRuns().get(0); HSLFTextRun rt = run.get(0).getTextRuns().get(0);
assertTrue(rt.isBold()); assertTrue(rt.isBold());
assertEquals(rt.getFontColor(), Color.RED); assertTrue(sameColor(Color.RED, rt.getFontColor()));
} }
} }
} }

View File

@ -0,0 +1,38 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.sl;
import java.awt.Color;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.junit.Ignore;
/**
* Currently only contains helper methods
*/
@Ignore
public class TestCommonSL {
public static boolean sameColor(Color colorExpected, PaintStyle paintActual) {
if (!(paintActual instanceof SolidPaint)) return false;
Color thisC = DrawPaint.applyColorTransform(((SolidPaint)paintActual).getSolidColor());
return thisC.equals(colorExpected);
}
}

Binary file not shown.

Binary file not shown.