#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;
import static org.apache.poi.sl.usermodel.PaintStyle.TRANSPARENT_PAINT;
import java.awt.*;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.MultipleGradientPaint.ColorSpaceType;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.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.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.SolidPaint;
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.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>
*/
@ -50,19 +56,45 @@ public class DrawPaint {
this.shape = shape;
}
public static SolidPaint createSolidPaint(final Color color) {
return new SolidPaint() {
public ColorStyle getSolidColor() {
return new ColorStyle(){
private static class SimpleSolidPaint implements SolidPaint {
private final ColorStyle solidColor;
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 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 getLumMod() { return -1; }
public int getShade() { 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) {
@ -95,26 +127,26 @@ public class DrawPaint {
protected Paint getTexturePaint(TexturePaint fill, Graphics2D graphics) {
InputStream is = fill.getImageData();
if (is == null) return TRANSPARENT_PAINT.getSolidColor().getColor();
if (is == null) return null;
assert(graphics != null);
ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);
if (renderer == null) renderer = new ImageRenderer();
try {
renderer.loadImage(fill.getImageData(), fill.getContentType());
renderer.loadImage(is, fill.getContentType());
is.close();
} catch (IOException 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();
if (alpha != -1) {
if (0 <= alpha && alpha < 100000) {
renderer.setAlpha(alpha/100000.f);
}
Dimension dim = renderer.getDimension();
Rectangle2D textAnchor = new Rectangle2D.Double(0, 0, dim.getWidth(), dim.getHeight());
Rectangle2D textAnchor = shape.getAnchor();
Paint paint = new java.awt.TexturePaint(renderer.getImage(), textAnchor);
return paint;
@ -122,106 +154,102 @@ public class DrawPaint {
/**
* 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){
// 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();
if (result == null) return null;
if (result == null || color.getAlpha() == 100) {
return TRANSPARENT_PAINT.getSolidColor().getColor();
}
double alpha = getAlpha(result, color);
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 = HSL2RGB(hsl[0], hsl[1], hsl[2], alpha);
result = applyAlpha(result, color);
result = applyLuminance(result, color);
result = applyShade(result, color);
result = applyTint(result, color);
return result;
}
protected static Color applyAlpha(Color c, ColorStyle fc) {
int alpha = c.getAlpha();
return (alpha == 255) ? c : new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha);
private static double getAlpha(Color c, ColorStyle fc) {
double alpha = c.getAlpha()/255d;
int fcAlpha = fc.getAlpha();
if (fcAlpha != -1) {
alpha *= fcAlpha/100000d;
}
return Math.min(1, Math.max(0, alpha));
}
/**
* Apply lumMod / lumOff adjustments
*
* @param c the color to modify
* @param fc the color style containing the lumMod / lumOff adjustments
* @return modified color
* Apply the modulation and offset adjustments to the given HSL part
*
* Example for lumMod/lumOff:
* 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.)
*
* @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) {
int lumMod = fc.getLumMod();
if (lumMod == -1) lumMod = 100000;
int lumOff = fc.getLumOff();
if (lumOff == -1) lumOff = 0;
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;
private static void applyHslModOff(double hsl[], int hslPart, int mod, int off) {
if (mod == -1) mod = 100000;
if (off == -1) off = 0;
if (!(mod == 100000 && off == 0)) {
double fOff = off / 1000d;
double fMod = mod / 100000d;
hsl[hslPart] = hsl[hslPart]*fMod+fOff;
}
}
/**
* This algorithm returns result different from PowerPoint.
* TODO: revisit and improve
* Apply the shade
*
* 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();
if (shade == -1) return c;
if (shade == -1) return;
float fshade = shade / 100000.f;
float red = c.getRed() * fshade;
float green = c.getGreen() * fshade;
float blue = c.getGreen() * fshade;
double fshade = shade / 100000.d;
return new Color(Math.round(red), Math.round(green), Math.round(blue), c.getAlpha());
hsl[2] *= fshade;
}
/**
* This algorithm returns result different from PowerPoint.
* TODO: revisit and improve
* Apply the tint
*
* 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();
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;
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());
hsl[2] = hsl[2] * ftint + (100 - ftint*100.);
}

View File

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

View File

@ -17,18 +17,32 @@
package org.apache.poi.sl.draw;
import java.awt.Color;
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.text.*;
import java.text.AttributedCharacterIterator;
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.TextAlign;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.sl.usermodel.TextRun.TextCap;
import org.apache.poi.sl.usermodel.TextShape;
import org.apache.poi.util.Units;
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){
if (lines.isEmpty()) return;
Insets2D insets = paragraph.getParentShape().getInsets();
double leftInset = insets.left;
double rightInset = insets.right;
double penY = y;
boolean firstLine = true;
@ -79,12 +90,17 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
Double leftMargin = paragraph.getLeftMargin();
if (leftMargin == null) {
// 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();
if (indent == null) {
indent = Units.toPoints(347663*indentLevel);
}
if (paragraph.getClass().getName().contains("HSLF")) {
// special handling for HSLF
indent -= leftMargin;
}
Double rightMargin = paragraph.getRightMargin();
if (rightMargin == null) {
rightMargin = 0d;
@ -104,25 +120,30 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
}
if (bullet != null){
bullet.setPosition(x + indent, penY);
bullet.setPosition(x+leftMargin+indent, penY);
bullet.draw(graphics);
// don't let text overlay the bullet and advance by the bullet width
double bulletWidth = bullet.getLayout().getAdvance() + 1;
penX = x + Math.max(leftMargin, indent+bulletWidth);
penX = x + Math.max(leftMargin, leftMargin+indent+bulletWidth);
} else {
penX = x + indent;
penX = x + leftMargin;
}
} else {
penX = x + leftMargin;
}
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();
if (ta == null) ta = TextAlign.LEFT;
switch (ta) {
case CENTER:
penX += (anchor.getWidth() - leftMargin - line.getWidth() - leftInset - rightInset) / 2;
penX += (anchor.getWidth() - line.getWidth() - leftInset - rightInset - leftMargin) / 2;
break;
case RIGHT:
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();
assert(buFont != null);
Color buColor = bulletStyle.getBulletFontColor();
if (buColor == null) buColor = (Color)firstLineAttr.getAttribute(TextAttribute.FOREGROUND);
PlaceableShape ps = getParagraphShape();
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);
Double buSz = bulletStyle.getBulletFontSize();
@ -256,7 +283,7 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
AttributedString str = new AttributedString(buCharacter);
str.addAttribute(TextAttribute.FOREGROUND, buColor);
str.addAttribute(TextAttribute.FOREGROUND, fgPaint);
str.addAttribute(TextAttribute.FAMILY, buFont);
str.addAttribute(TextAttribute.SIZE, fontSize);
@ -382,11 +409,31 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
this.endIndex = endIndex;
}
}
/**
* 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){
List<AttributedStringData> attList = new ArrayList<AttributedStringData>();
if (text == null) text = new StringBuilder();
PlaceableShape ps = getParagraphShape();
DrawFontManager fontHandler = (DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER);
for (TextRun run : paragraph){
@ -398,9 +445,9 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
text.append(runText);
int endIndex = text.length();
Color fgColor = run.getFontColor();
if (fgColor == null) fgColor = Color.BLACK;
attList.add(new AttributedStringData(TextAttribute.FOREGROUND, fgColor, beginIndex, endIndex));
PaintStyle fgPaintStyle = run.getFontColor();
Paint fgPaint = new DrawPaint(ps).getPaint(graphics, fgPaintStyle);
attList.add(new AttributedStringData(TextAttribute.FOREGROUND, fgPaint, beginIndex, endIndex));
// user can pass an custom object to convert fonts
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) {
DrawFactory fact = DrawFactory.getInstance(graphics);
Insets2D shapePadding = shape.getInsets();
double y0 = y;
Iterator<? extends TextParagraph<? extends TextRun>> paragraphs = shape.iterator();

View File

@ -32,17 +32,55 @@ public interface ColorStyle {
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 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]
* @return luminance shift in percents in the range [0..100000] (usually ...)
* or -1 if the value is not set
*/
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
*/
int getLumMod();
@ -50,8 +88,9 @@ public interface ColorStyle {
/**
* specifies a darker version of its input color.
* 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
* or -1 if the value is not set
*/
@ -60,8 +99,9 @@ public interface ColorStyle {
/**
* specifies a lighter version of its input color.
* 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
* or -1 if the value is not set
*/

View File

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

View File

@ -18,20 +18,26 @@
package org.apache.poi.sl.usermodel;
public interface Slide<T extends Shape, SS extends SlideShow, N extends Notes<T,SS>> extends Sheet<T, SS> {
N getNotes();
void setNotes(N notes);
N getNotes();
void setNotes(N notes);
boolean getFollowMasterBackground();
void setFollowMasterBackground(boolean follow);
boolean getFollowMasterBackground();
void setFollowMasterBackground(boolean follow);
boolean getFollowMasterColourScheme();
void setFollowMasterColourScheme(boolean follow);
boolean getFollowMasterColourScheme();
void setFollowMasterColourScheme(boolean follow);
boolean getFollowMasterObjects();
void setFollowMasterObjects(boolean follow);
boolean getFollowMasterObjects();
void setFollowMasterObjects(boolean follow);
/**
* @return the 1-based slide no.
*/
int getSlideNumber();
/**
* @return title of this slide or null if title is not set
*/
String getTitle();
/**
* @return the 1-based slide no.
*/
int getSlideNumber();
}

View File

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

View File

@ -20,6 +20,7 @@ package org.apache.poi.sl.usermodel;
import java.awt.Color;
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
*/
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();
/**

View File

@ -19,6 +19,8 @@ package org.apache.poi.sl.usermodel;
import java.awt.Color;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
/**
* Some text.
*/
@ -34,8 +36,33 @@ public interface TextRun {
TextCap getTextCap();
Color getFontColor();
void setFontColor(Color color);
/**
* 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);
/**
* Sets the font color
*
* @param color the color
*
* @see org.apache.poi.sl.draw.DrawPaint#createSolidPaint(Color)
*/
void setFontColor(PaintStyle color);
/**

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
*/
public abstract class CharacterPropertyFetcher<T> extends ParagraphPropertyFetcher<T> {
public boolean isFetchingFromMaster = false;
public CharacterPropertyFetcher(int level) {
super(level);
}

View File

@ -78,6 +78,22 @@ public class XSLFColor {
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() {
return getRawValue("lumOff");
}

View File

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

View File

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

View File

@ -27,10 +27,10 @@ import java.util.Comparator;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.sl.draw.DrawPaint;
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.SolidPaint;
import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;
import org.apache.poi.sl.usermodel.PlaceableShape;
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.xslf.model.PropertyFetcher;
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.CTBackground;
import org.openxmlformats.schemas.presentationml.x2006.main.CTBackgroundProperties;
@ -139,7 +152,7 @@ public abstract class XSLFShape implements Shape {
try {
pr = shape.getSpPr();
if (((CTShapeProperties)pr).isSetNoFill()) {
setValue(PaintStyle.TRANSPARENT_PAINT);
setValue(null);
return true;
}
} catch (IllegalStateException e) {}
@ -156,21 +169,19 @@ public abstract class XSLFShape implements Shape {
}
}
if (pr == null) {
setValue(PaintStyle.TRANSPARENT_PAINT);
return true;
}
if (pr == null) return false;
PaintStyle paint = null;
PackagePart pp = getSheet().getPackagePart();
for (XmlObject obj : pr.selectPath("*")) {
paint = selectPaint(obj, null, getSheet().getPackagePart());
if (paint != null) break;
paint = selectPaint(obj, null, pp);
if (paint != null) {
setValue(paint);
return true;
};
}
if (paint == null) return false;
setValue(paint);
return true;
return false;
}
};
fetchShapeProperty(fetcher);
@ -190,7 +201,7 @@ public abstract class XSLFShape implements Shape {
}
paint = selectPaint(fillRef);
return paint == null ? PaintStyle.TRANSPARENT_PAINT : paint;
return paint;
}
protected CTBackgroundProperties getBgPr() {
@ -347,8 +358,8 @@ public abstract class XSLFShape implements Shape {
paint = selectPaint(obj, phClr, pp);
if(paint != null) break;
}
return paint == null ? PaintStyle.TRANSPARENT_PAINT : paint;
}
return paint;
}
/**
* Convert shape fill into java.awt.Paint. The result is either Color or
@ -371,13 +382,13 @@ public abstract class XSLFShape implements Shape {
*/
protected PaintStyle selectPaint(XmlObject obj, final CTSchemeColor phClr, final PackagePart parentPart) {
if (obj instanceof CTNoFillProperties) {
return PaintStyle.TRANSPARENT_PAINT;
return null;
} else if (obj instanceof CTSolidColorFillProperties) {
return selectPaint((CTSolidColorFillProperties)obj, phClr, parentPart);
return selectPaint((CTSolidColorFillProperties)obj, phClr);
} else if (obj instanceof CTBlipFillProperties) {
return selectPaint((CTBlipFillProperties)obj, phClr, parentPart);
return selectPaint((CTBlipFillProperties)obj, parentPart);
} else if (obj instanceof CTGradientFillProperties) {
return selectPaint((CTGradientFillProperties) obj, phClr, parentPart);
return selectPaint((CTGradientFillProperties) obj, phClr);
} else if (obj instanceof CTStyleMatrixReference) {
return selectPaint((CTStyleMatrixReference)obj);
} 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();
if (phClr == null && solidFill.isSetSchemeClr()) {
phClr = solidFill.getSchemeClr();
}
final XSLFColor c = new XSLFColor(solidFill, theme, phClr);
return new SolidPaint() {
public ColorStyle getSolidColor() {
return c.getColorStyle();
}
};
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();
return new TexturePaint() {
private PackagePart getPart() {
@ -424,12 +434,12 @@ public abstract class XSLFShape implements Shape {
public int getAlpha() {
return (blip.sizeOfAlphaModFixArray() > 0)
? 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")
final CTGradientStop[] gs = gradFill.getGsLst().getGsArray();
@ -448,7 +458,11 @@ public abstract class XSLFShape implements Shape {
int i=0;
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;
i++;
}

View File

@ -19,8 +19,6 @@
package org.apache.poi.xslf.usermodel;
import static org.apache.poi.sl.usermodel.PaintStyle.TRANSPARENT_PAINT;
import java.awt.Color;
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.Guide;
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.DecorationSize;
import org.apache.poi.sl.usermodel.PaintStyle;
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.LineCompound;
import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
@ -219,7 +222,6 @@ public abstract class XSLFSimpleShape extends XSLFShape implements SimpleShape {
*/
public Color getLineColor() {
PaintStyle ps = getLinePaint();
if (ps == null || ps == TRANSPARENT_PAINT) return null;
if (ps instanceof SolidPaint) {
return ((SolidPaint)ps).getSolidColor().getColor();
}
@ -232,7 +234,7 @@ public abstract class XSLFSimpleShape extends XSLFShape implements SimpleShape {
CTLineProperties spPr = shape.getSpPr().getLn();
if (spPr != null) {
if (spPr.isSetNoFill()) {
setValue(TRANSPARENT_PAINT); // use it as 'nofill' value
setValue(null); // use it as 'nofill' value
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
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.
CTStyleMatrixReference lnRef = style.getLnRef();
@ -279,7 +281,7 @@ public abstract class XSLFSimpleShape extends XSLFShape implements SimpleShape {
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() {
PaintStyle ps = getFillPaint();
if (ps == null || ps == TRANSPARENT_PAINT) return null;
if (ps instanceof SolidPaint) {
return ((SolidPaint)ps).getSolidColor().getColor();
}

View File

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

View File

@ -21,7 +21,10 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.sl.draw.DrawPaint;
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.util.Beta;
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.
* A <code>null</code> value means to use the text font color.
*/
public Color getBulletFontColor(){
public PaintStyle getBulletFontColor(){
final XSLFTheme theme = getParentShape().getSheet().getTheme();
ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getIndentLevel()){
public boolean fetch(CTTextParagraphProperties props){
@ -277,19 +280,33 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
};
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.
*
* @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();
CTColor c = pr.isSetBuClr() ? pr.getBuClr() : pr.addNewBuClr();
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();
for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {
masterSheet = m;
XmlObject xo = masterSheet.getXmlObject();
for (String xpath : xpaths) {
XmlObject[] o = xo.selectPath(xpath);
@ -767,32 +783,35 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){
boolean ok = false;
XSLFTextShape shape = getParentShape();
XSLFSheet sheet = shape.getSheet();
if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());
if (ok) return true;
if(!ok) {
XSLFTextShape shape = getParentShape();
ok = shape.fetchShapeProperty(visitor);
if(!ok){
CTPlaceholder ph = shape.getCTPlaceholder();
if(ph == null){
// if it is a plain text box then take defaults from presentation.xml
XMLSlideShow ppt = getParentShape().getSheet().getSlideShow();
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel());
if(themeProps != null) ok = visitor.fetch(themeProps);
}
if(!ok){
// defaults for placeholders are defined in the slide master
CTTextParagraphProperties defaultProps = getDefaultMasterStyle();
if(defaultProps != null) ok = visitor.fetch(defaultProps);
}
}
ok = shape.fetchShapeProperty(visitor);
if (ok) return true;
CTPlaceholder ph = shape.getCTPlaceholder();
if(ph == null){
// if it is a plain text box then take defaults from presentation.xml
XMLSlideShow ppt = sheet.getSlideShow();
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel());
if (themeProps != null) ok = visitor.fetch(themeProps);
}
if (ok) return true;
return ok;
// defaults for placeholders are defined in the slide master
CTTextParagraphProperties defaultProps = getDefaultMasterStyle();
// TODO: determine master shape
if(defaultProps != null) ok = visitor.fetch(defaultProps);
if (ok) return true;
return false;
}
@SuppressWarnings("deprecation")
void copy(XSLFTextParagraph other){
if (other == this) return;
@ -848,7 +867,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
if(buChar != null && !buChar.equals(getBulletCharacter())){
setBulletCharacter(buChar);
}
Color buColor = other.getBulletFontColor();
PaintStyle buColor = other.getBulletFontColor();
if(buColor != null && !buColor.equals(getBulletFontColor())){
setBulletFontColor(buColor);
}
@ -920,10 +939,20 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
}
@Override
public Color getBulletFontColor() {
public PaintStyle 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
public AutoNumberingScheme getAutoNumberingScheme() {
return XSLFTextParagraph.this.getAutoNumberingScheme();

View File

@ -18,6 +18,9 @@ package org.apache.poi.xslf.usermodel;
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.util.Beta;
import org.apache.poi.xslf.model.CharacterPropertyFetcher;
@ -84,10 +87,21 @@ public class XSLFTextRun implements TextRun {
@Override
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();
CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill();
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.isSetPrstClr()) fill.unsetPrstClr();
@ -98,22 +112,22 @@ public class XSLFTextRun implements TextRun {
}
@Override
public Color getFontColor(){
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
CTShapeStyle style = _p.getParentShape().getSpStyle();
final CTSchemeColor phClr = style == null ? null : style.getFontRef().getSchemeClr();
CharacterPropertyFetcher<Color> fetcher = new CharacterPropertyFetcher<Color>(_p.getIndentLevel()){
public PaintStyle getFontColor(){
CharacterPropertyFetcher<PaintStyle> fetcher = new CharacterPropertyFetcher<PaintStyle>(_p.getIndentLevel()){
public boolean fetch(CTTextCharacterProperties props){
CTSolidColorFillProperties solidFill = props.getSolidFill();
if(solidFill != null) {
boolean useCtxColor =
(solidFill.isSetSchemeClr() && solidFill.getSchemeClr().getVal() == STSchemeColorVal.PH_CLR)
|| isFetchingFromMaster;
Color c = new XSLFColor(solidFill, theme, useCtxColor ? phClr : null).getColor();
setValue(c);
XSLFShape shape = _p.getParentShape();
CTShapeStyle style = shape.getSpStyle();
CTSchemeColor phClr = null;
if (style != null && style.getFontRef() != null) {
phClr = style.getFontRef().getSchemeClr();
}
PaintStyle ps = shape.getPaint(props, phClr);
if (ps != null) {
setValue(ps);
return true;
}
return false;
}
};
@ -250,7 +264,7 @@ public class XSLFTextRun implements TextRun {
}
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()){
public boolean fetch(CTTextCharacterProperties props){
@ -474,35 +488,36 @@ public class XSLFTextRun implements TextRun {
}
private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){
XSLFTextShape shape = _p.getParentShape();
XSLFSheet sheet = shape.getSheet();
boolean ok = false;
if(_r.isSetRPr()) ok = fetcher.fetch(getRPr());
if(!ok) {
XSLFTextShape shape = _p.getParentShape();
ok = shape.fetchShapeProperty(fetcher);
if(!ok){
CTPlaceholder ph = shape.getCTPlaceholder();
if(ph == null){
// if it is a plain text box then take defaults from presentation.xml
XMLSlideShow ppt = shape.getSheet().getSlideShow();
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel());
if(themeProps != null) {
fetcher.isFetchingFromMaster = true;
ok = fetcher.fetch(themeProps);
}
}
if (!ok) {
CTTextParagraphProperties defaultProps = _p.getDefaultMasterStyle();
if(defaultProps != null) {
fetcher.isFetchingFromMaster = true;
ok = fetcher.fetch(defaultProps);
}
}
if (_r.isSetRPr()) ok = fetcher.fetch(getRPr());
if (ok) return true;
ok = shape.fetchShapeProperty(fetcher);
if (ok) return true;
CTPlaceholder ph = shape.getCTPlaceholder();
if (ph == null){
// if it is a plain text box then take defaults from presentation.xml
XMLSlideShow ppt = sheet.getSlideShow();
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel());
if (themeProps != null) {
// TODO: determine master shape
ok = fetcher.fetch(themeProps);
}
}
if (ok) return true;
return ok;
CTTextParagraphProperties defaultProps = _p.getDefaultMasterStyle();
if(defaultProps != null) {
// TODO: determine master shape
ok = fetcher.fetch(defaultProps);
}
if (ok) return true;
return false;
}
void copy(XSLFTextRun r){
@ -511,7 +526,7 @@ public class XSLFTextRun implements TextRun {
setFontFamily(srcFontFamily);
}
Color srcFontColor = r.getFontColor();
PaintStyle srcFontColor = r.getFontColor();
if(srcFontColor != null && !srcFontColor.equals(getFontColor())){
setFontColor(srcFontColor);
}

View File

@ -19,19 +19,22 @@
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.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.File;
import java.util.HashMap;
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
@ -40,22 +43,33 @@ import java.util.List;
*/
public class PPTX2PNG {
static void usage(){
System.out.println("Usage: PPTX2PNG [options] <pptx file>");
System.out.println("Options:");
System.out.println(" -scale <float> scale factor");
System.out.println(" -slide <integer> 1-based index of a slide to render");
static void usage(String error){
String msg =
"Usage: PPTX2PNG [options] <ppt or pptx file>\n" +
(error == null ? "" : ("Error: "+error+"\n")) +
"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 {
if (args.length == 0) {
usage();
usage(null);
return;
}
int slidenum = -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++) {
if (args[i].startsWith("-")) {
@ -63,55 +77,104 @@ public class PPTX2PNG {
scale = Float.parseFloat(args[++i]);
} else if ("-slide".equals(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 {
file = args[i];
file = new File(args[i]);
}
}
if(file == null){
usage();
if (file == null || !file.exists()) {
usage("File not specified or it doesn't exist");
return;
}
System.out.println("Processing " + file);
XMLSlideShow ppt = new XMLSlideShow(OPCPackage.open(file));
if (outdir == null) {
outdir = file.getParentFile();
}
if (outdir == null || !outdir.exists() || !outdir.isDirectory()) {
usage("Output directory doesn't exist");
return;
}
Dimension pgsize = ppt.getPageSize();
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 height = (int) (pgsize.height * scale);
List<XSLFSlide> slide = ppt.getSlides();
for (int i = 0; i < slide.size(); i++) {
if (slidenum != -1 && slidenum != (i + 1)) continue;
int slideNo=1;
for(Slide<?,?,?> slide : slides) {
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();
System.out.println("Rendering slide " + (i + 1) + (title == null ? "" : ": " + title));
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics();
fixFonts(graphics);
// default rendering options
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics();
graphics.scale(scale, scale);
// default rendering options
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
// draw stuff
slide.draw(graphics);
graphics.setColor(Color.white);
graphics.clearRect(0, 0, width, height);
graphics.scale(scale, scale);
// draw stuff
slide.get(i).draw(graphics);
// save the result
int sep = file.lastIndexOf(".");
String fname = file.substring(0, sep == -1 ? file.length() : sep) + "-" + (i + 1) +".png";
FileOutputStream out = new FileOutputStream(fname);
ImageIO.write(img, "png", out);
out.close();
// save the result
if (!"null".equals(format)) {
String outname = file.getName().replaceFirst(".pptx?", "");
outname = String.format("%1$s-%2$04d.%3$s", outname, slideNo, format);
File outfile = new File(outdir, outname);
ImageIO.write(img, format, outfile);
}
}
slideNo++;
}
System.out.println("Done");
if (!quite) {
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;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.util.JvmBugs;
import org.apache.poi.xslf.XSLFTestDataSamples;
import org.apache.poi.POIDataSamples;
import org.apache.poi.xslf.util.PPTX2PNG;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@ -44,7 +39,6 @@ public class TestPPTX2PNG {
@BeforeClass
public static void activateJaxpDebug() {
jaxpDebugEnable = setDebugFld(true);
// setXmlInputFactory();
}
@AfterClass
@ -66,48 +60,26 @@ public class TestPPTX2PNG {
return false;
}
}
// 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
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){
args[args.length-1] = samples.getFile(sampleFile).getCanonicalPath();
try {
XMLSlideShow pptx = XSLFTestDataSamples.openSampleDocument(sampleFile);
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++;
}
PPTX2PNG.main(args);
} catch (IllegalStateException 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;
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.io.IOException;

View File

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

View File

@ -16,19 +16,24 @@
==================================================================== */
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.image.BufferedImage;
import java.io.IOException;
import java.util.List;
import org.apache.poi.sl.draw.DrawTextFragment;
import org.apache.poi.sl.draw.DrawTextParagraph;
import org.apache.poi.sl.usermodel.AutoNumberingScheme;
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.junit.Assume;
import org.junit.Test;
@ -37,7 +42,7 @@ import org.junit.Test;
* @author Yegor Kozlov
*/
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> {
DrawTextParagraphProxy(XSLFTextParagraph p) {
@ -58,7 +63,7 @@ public class TestXSLFTextParagraph {
}
@Test
public void testWrappingWidth() throws Exception {
public void testWrappingWidth() throws IOException {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape();
@ -142,6 +147,8 @@ public class TestXSLFTextParagraph {
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin;
assertEquals(244.0, expectedWidth, 0); // 300 - 10 - 10 - 36
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
*/
@Test
public void testBreakLines(){
public void testBreakLines() throws IOException {
String os = System.getProperty("os.name");
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
assertTrue(lines.get(0).getHeight() > lines.get(1).getHeight()*2);
ppt.close();
}
@Test
public void testThemeInheritance(){
public void testThemeInheritance() throws IOException {
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("prProps.pptx");
List<XSLFShape> shapes = ppt.getSlides().get(0).getShapes();
XSLFTextShape sh1 = (XSLFTextShape)shapes.get(0);
@ -252,10 +260,11 @@ public class TestXSLFTextParagraph {
XSLFTextShape sh3 = (XSLFTextShape)shapes.get(2);
assertEquals("Foundation", sh3.getText());
assertEquals(TextAlign.CENTER, sh3.getTextParagraphs().get(0).getTextAlign());
ppt.close();
}
@Test
public void testParagraphProperties(){
public void testParagraphProperties() throws IOException {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape();
@ -275,7 +284,7 @@ public class TestXSLFTextParagraph {
assertEquals(null, p.getBulletFontColor());
p.setBulletFontColor(Color.red);
assertEquals(Color.red, p.getBulletFontColor());
assertTrue(sameColor(Color.red, p.getBulletFontColor()));
assertNull(p.getBulletFontSize());
p.setBulletFontSize(200.);
@ -342,34 +351,35 @@ public class TestXSLFTextParagraph {
assertEquals(72.0, p.getDefaultTabSize(), 0);
ppt.close();
}
@Test
public void testLineBreak(){
@Test(expected = IllegalStateException.class)
public void testLineBreak() throws IOException {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape();
XSLFTextParagraph p = sh.addNewTextParagraph();
XSLFTextRun r1 = p.addNewTextRun();
r1.setText("Hello,");
XSLFTextRun r2 = p.addLineBreak();
assertEquals("\n", r2.getRawText());
r2.setFontSize(10.0);
assertEquals(10.0, r2.getFontSize(), 0);
XSLFTextRun r3 = p.addNewTextRun();
r3.setText("World!");
r3.setFontSize(20.0);
XSLFTextRun r4 = p.addLineBreak();
assertEquals(20.0, r4.getFontSize(), 0);
assertEquals("Hello,\nWorld!\n",sh.getText());
try {
XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape();
XSLFTextParagraph p = sh.addNewTextParagraph();
XSLFTextRun r1 = p.addNewTextRun();
r1.setText("Hello,");
XSLFTextRun r2 = p.addLineBreak();
assertEquals("\n", r2.getRawText());
r2.setFontSize(10.0);
assertEquals(10.0, r2.getFontSize(), 0);
XSLFTextRun r3 = p.addNewTextRun();
r3.setText("World!");
r3.setFontSize(20.0);
XSLFTextRun r4 = p.addLineBreak();
assertEquals(20.0, r4.getFontSize(), 0);
assertEquals("Hello,\nWorld!\n",sh.getText());
// "You cannot change text of a line break, it is always '\\n'"
r2.setText("aaa");
fail("Expected IllegalStateException");
} catch (IllegalStateException e){
assertEquals("You cannot change text of a line break, it is always '\\n'", e.getMessage());
} finally {
ppt.close();
}
}
}

View File

@ -18,16 +18,23 @@
*/
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
*/
public class TestXSLFTextRun extends TestCase {
public class TestXSLFTextRun {
public void testRunProperties(){
@Test
public void testRunProperties() throws IOException {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape();
@ -35,26 +42,26 @@ public class TestXSLFTextRun extends TestCase {
XSLFTextRun r = sh.addNewTextParagraph().addNewTextRun();
assertEquals("en-US", r.getRPr().getLang());
assertEquals(0., r.getCharacterSpacing());
assertEquals(0., r.getCharacterSpacing(), 0);
r.setCharacterSpacing(3);
assertEquals(3., r.getCharacterSpacing());
assertEquals(3., r.getCharacterSpacing(), 0);
r.setCharacterSpacing(-3);
assertEquals(-3., r.getCharacterSpacing());
assertEquals(-3., r.getCharacterSpacing(), 0);
r.setCharacterSpacing(0);
assertEquals(0., r.getCharacterSpacing());
assertEquals(0., r.getCharacterSpacing(), 0);
assertFalse(r.getRPr().isSetSpc());
assertEquals(Color.black, r.getFontColor());
assertTrue(sameColor(Color.black, r.getFontColor()));
r.setFontColor(Color.red);
assertEquals(Color.red, r.getFontColor());
assertTrue(sameColor(Color.red, r.getFontColor()));
assertEquals("Calibri", r.getFontFamily());
r.setFontFamily("Arial");
assertEquals("Arial", r.getFontFamily());
assertEquals(18.0, r.getFontSize());
assertEquals(18.0, r.getFontSize(), 0);
r.setFontSize(13.0);
assertEquals(13.0, r.getFontSize());
assertEquals(13.0, r.getFontSize(), 0);
assertEquals(false, r.isSuperscript());
r.setSuperscript(true);
@ -67,5 +74,7 @@ public class TestXSLFTextRun extends TestCase {
assertEquals(true, r.isSubscript());
r.setSubscript(false);
assertEquals(false, r.isSubscript());
ppt.close();
}
}

View File

@ -16,16 +16,26 @@
==================================================================== */
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.io.IOException;
import java.util.List;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.xslf.XSLFTestDataSamples;
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.STPlaceholderType;
@ -82,7 +92,7 @@ public class TestXSLFTextShape {
XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor());
assertTrue(sameColor(Color.black, r1.getFontColor()));
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
CTPlaceholder ph2 = shape2.getCTPlaceholder();
@ -151,7 +161,7 @@ public class TestXSLFTextShape {
XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor());
assertTrue(sameColor(Color.black, r1.getFontColor()));
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
CTPlaceholder ph2 = shape2.getCTPlaceholder();
@ -262,7 +272,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.LEFT, r1.getParentParagraph().getTextAlign());
assertEquals("Calibri", r1.getFontFamily());
assertEquals(40.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor());
assertTrue(sameColor(Color.black, r1.getFontColor()));
assertTrue(r1.isBold());
assertFalse(r1.isItalic());
assertFalse(r1.isUnderlined());
@ -336,7 +346,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign());
assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor());
assertTrue(sameColor(Color.black, r1.getFontColor()));
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
CTPlaceholder ph2 = shape2.getCTPlaceholder();
@ -404,7 +414,7 @@ public class TestXSLFTextShape {
assertEquals(0, pr5.getParentParagraph().getIndentLevel());
assertEquals("Right", pr5.getRawText());
assertEquals("Calibri", pr5.getFontFamily());
assertEquals(Color.black, pr5.getFontColor());
assertTrue(sameColor(Color.black, pr5.getFontColor()));
}
@SuppressWarnings("unused")
@ -444,7 +454,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign());
assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor());
assertTrue(sameColor(Color.black, r1.getFontColor()));
assertFalse(r1.isBold());
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
@ -517,7 +527,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.LEFT, r1.getParentParagraph().getTextAlign());
assertEquals("Calibri", r1.getFontFamily());
assertEquals(20.0, r1.getFontSize(), 0);
assertEquals(Color.black, r1.getFontColor());
assertTrue(sameColor(Color.black, r1.getFontColor()));
assertTrue(r1.isBold());
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
@ -605,7 +615,7 @@ public class TestXSLFTextShape {
assertEquals("Calibri", r1.getFontFamily());
assertEquals(12.0, r1.getFontSize(), 0);
// 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);
assertEquals("Friday, October 21, 2011", dt.getText());
@ -615,7 +625,7 @@ public class TestXSLFTextShape {
}
@Test
public void testTitleStyles(){
public void testTitleStyles() throws IOException {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlideMaster master = ppt.getSlideMasters().get(0);
@ -693,10 +703,12 @@ public class TestXSLFTextShape {
assertEquals("Calibri", textRun.getFontFamily());
lv5PPr.setAlgn(STTextAlignType.CTR);
assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
ppt.close();
}
@Test
public void testBodyStyles(){
public void testBodyStyles() throws IOException {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlideMaster master = ppt.getSlideMasters().get(0);
@ -895,7 +907,7 @@ public class TestXSLFTextShape {
assertEquals("Calibri", r3.getFontFamily());
lv3PPr.setAlgn(STTextAlignType.CTR);
assertEquals(TextAlign.CENTER, p3.getTextAlign());
ppt.close();
}
}

View File

@ -16,6 +16,7 @@
==================================================================== */
package org.apache.poi.xslf.usermodel;
import static org.apache.poi.sl.TestCommonSL.sameColor;
import static org.junit.Assert.*;
import java.awt.Color;
@ -66,7 +67,7 @@ public class TestXSLFTheme {
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 3");
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());
assertTrue(sh1.getFillStyle().getPaint() instanceof SolidPaint) ; // solid fill
@ -89,13 +90,13 @@ public class TestXSLFTheme {
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 4");
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());
assertTrue(sh1.getFillStyle().getPaint() instanceof SolidPaint) ; // solid fill
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 3");
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
assertTrue(slide.getSlideLayout().getFollowMasterGraphics());
@ -107,7 +108,7 @@ public class TestXSLFTheme {
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 1");
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
// font size is 40pt and scale factor is 90%
assertEquals(36.0, run2.getFontSize(), 0);
@ -119,12 +120,12 @@ public class TestXSLFTheme {
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Subtitle 3");
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
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 2");
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
assertFalse(slide.getSlideLayout().getFollowMasterGraphics());
@ -154,12 +155,12 @@ public class TestXSLFTheme {
XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Title 3");
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
XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Subtitle 4");
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
}
}

View File

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

View File

@ -18,19 +18,49 @@
package org.apache.poi.hslf.model;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
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.text.AttributedCharacterIterator;
import java.util.Map;
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.VerticalAlignment;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -259,7 +289,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable {
rt.setFontSize((double)_font.getSize());
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.isItalic()) rt.setItalic(true);

View File

@ -22,10 +22,16 @@ import java.io.ByteArrayInputStream;
import java.io.InputStream;
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.sl.usermodel.*;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.draw.DrawPaint;
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.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -113,20 +119,8 @@ public final class HSLFFill {
return new FillStyle() {
public PaintStyle getPaint() {
switch (getFillType()) {
case FILL_SOLID: {
return new SolidPaint() {
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_SOLID:
return DrawPaint.createSolidPaint(getForegroundColor());
case FILL_PICTURE: {
final HSLFPictureData pd = getPictureData();
if (pd == null) break;
@ -149,7 +143,7 @@ public final class HSLFFill {
logger.log(POILogger.WARN, "unsuported fill type: " + getFillType());
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
/**
* Return title of this slide or <code>null</code> if the slide does not have title.
* <p>
* The title is a run of text of type <code>TextHeaderAtom.CENTER_TITLE_TYPE</code> or
* <code>TextHeaderAtom.TITLE_TYPE</code>
* </p>
*
* @see TextHeaderAtom
*
* @return title of this slide
*/
@Override
public String getTitle(){
for (List<HSLFTextParagraph> tp : getTextParagraphs()) {
if (tp.isEmpty()) continue;

View File

@ -132,6 +132,20 @@ public final class HSLFSlideShow implements SlideShow {
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"
* 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.TextPropCollection.TextPropType;
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.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.util.*;
@ -403,8 +406,24 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
}
@Override
public Color getBulletFontColor() {
return HSLFTextParagraph.this.getBulletColor();
public void setBulletFontColor(Color color) {
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
@ -497,7 +516,9 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFTextRun> {
TextProp tp = getPropVal(_paragraphStyle, "bullet.color", this);
if (tp == null) {
// 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);

View File

@ -21,8 +21,14 @@ import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.getPropVal;
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.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.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -315,13 +321,15 @@ public final class HSLFTextRun implements TextRun {
}
/**
* @return font color as RGB value
* @see java.awt.Color
* @return font color as PaintStyle
*/
public Color getFontColor() {
@Override
public SolidPaint getFontColor() {
TextProp tp = getPropVal(characterStyle, "font.color", parentParagraph);
return (tp == null) ? null
: HSLFTextParagraph.getColorFromColorIndexStruct(tp.getValue(), parentParagraph.getSheet());
if (tp == null) return null;
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);
}
/**
* Sets color of the text, as a java.awt.Color
*/
public void setFontColor(Color color) {
@Override
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
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);
}

View File

@ -17,6 +17,7 @@
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.assertFalse;
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.HSLFTextRun;
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.StrokeStyle.LineDash;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.junit.Before;
import org.junit.Test;
@ -189,16 +190,16 @@ public final class TestShapes {
List<HSLFTextParagraph> para = tb.getTextParagraphs();
HSLFTextRun tr = para.get(0).getTextRuns().get(0);
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);
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);
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);
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());
}
@ -235,7 +236,7 @@ public final class TestShapes {
assertTrue(rt.isItalic());
assertFalse(rt.isUnderlined());
assertEquals("Arial", rt.getFontFamily());
assertEquals(Color.red, rt.getFontColor());
assertTrue(sameColor(Color.red, rt.getFontColor()));
// Serialize and read again
ByteArrayOutputStream out = new ByteArrayOutputStream();
@ -255,7 +256,7 @@ public final class TestShapes {
assertTrue(rt.isItalic());
assertFalse(rt.isUnderlined());
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;
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.io.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import org.apache.poi.POIDataSamples;
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.Test;
@ -539,7 +550,7 @@ public final class TestTextRun {
List<HSLFTextParagraph> run = tx.getTextParagraphs();
HSLFTextRun rt = run.get(0).getTextRuns().get(0);
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.