junit fixes

set font size via Double
color handling via HSL calculation

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/common_sl@1691117 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-07-15 00:30:21 +00:00
parent 72ce8545dd
commit f7b8e88bda
25 changed files with 583 additions and 364 deletions

View File

@ -74,7 +74,7 @@ public final class ApacheconEU08 {
slide.addShape(box2);
HSLFTextBox box3 = new HSLFTextBox();
box3.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(32);
box3.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(32d);
box3.setText(
"Yegor Kozlov\r" +
"yegor - apache - org");
@ -129,10 +129,10 @@ public final class ApacheconEU08 {
List<HSLFTextParagraph> tp = box2.getTextParagraphs();
for (int i : new byte[]{0,1,2,8}) {
tp.get(i).getTextRuns().get(0).setFontSize(28);
tp.get(i).getTextRuns().get(0).setFontSize(28d);
}
for (int i : new byte[]{3,4,5,6,7}) {
tp.get(i).getTextRuns().get(0).setFontSize(24);
tp.get(i).getTextRuns().get(0).setFontSize(24d);
tp.get(i).setIndentLevel(1);
}
box2.setAnchor(new Rectangle(36, 80, 648, 400));
@ -152,15 +152,15 @@ public final class ApacheconEU08 {
HSLFTableCell cell = table1.getCell(i, j);
cell.setText(txt1[i][j]);
HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
rt.setFontSize(10);
rt.setFontSize(10d);
rt.setFontFamily("Arial");
rt.setBold(true);
if(i == 0){
rt.setFontSize(32);
rt.setFontSize(32d);
rt.setFontColor(Color.white);
cell.getFill().setForegroundColor(new Color(0, 153, 204));
} else {
rt.setFontSize(28);
rt.setFontSize(28d);
cell.getFill().setForegroundColor(new Color(235, 239, 241));
}
cell.setVerticalAlignment(VerticalAlignment.MIDDLE);
@ -186,7 +186,7 @@ public final class ApacheconEU08 {
HSLFTextBox box1 = new HSLFTextBox();
box1.setHorizontalCentered(true);
box1.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(24);
box1.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(24d);
box1.setText("The source code is available at\r" +
"http://people.apache.org/~yegor/apachecon_eu08/");
box1.setAnchor(new Rectangle(80, 356, 553, 65));
@ -225,7 +225,7 @@ public final class ApacheconEU08 {
slide.addShape(box1);
HSLFTextBox box2 = new HSLFTextBox();
box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18);
box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d);
box2.setText("Creating a simple presentation from scratch");
box2.setAnchor(new Rectangle(170, 100, 364, 30));
slide.addShape(box2);
@ -233,7 +233,7 @@ public final class ApacheconEU08 {
HSLFTextBox box3 = new HSLFTextBox();
HSLFTextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0);
rt3.setFontFamily("Courier New");
rt3.setFontSize(8);
rt3.setFontSize(8d);
box3.setText(
"SlideShow ppt = new SlideShow();\u000b" +
"Slide slide = ppt.createSlide();\u000b" +
@ -334,7 +334,7 @@ public final class ApacheconEU08 {
slide.addShape(box1);
HSLFTextBox box2 = new HSLFTextBox();
box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18);
box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d);
box2.setText("PPGraphics2D: PowerPoint Graphics2D driver");
box2.setAnchor(new Rectangle(178, 70, 387, 30));
slide.addShape(box2);
@ -342,7 +342,7 @@ public final class ApacheconEU08 {
HSLFTextBox box3 = new HSLFTextBox();
HSLFTextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0);
rt3.setFontFamily("Courier New");
rt3.setFontSize(8);
rt3.setFontSize(8d);
box3.setText(
"//bar chart data. The first value is the bar color, the second is the width\u000b" +
"Object[] def = new Object[]{\u000b" +
@ -446,10 +446,10 @@ public final class ApacheconEU08 {
List<HSLFTextParagraph> tp = box2.getTextParagraphs();
for (int i : new byte[]{0,1,3}) {
tp.get(i).getTextRuns().get(0).setFontSize(28);
tp.get(i).getTextRuns().get(0).setFontSize(28d);
}
for (int i : new byte[]{2,4,5}) {
tp.get(i).getTextRuns().get(0).setFontSize(24);
tp.get(i).getTextRuns().get(0).setFontSize(24d);
tp.get(i).setIndentLevel(1);
}

View File

@ -37,7 +37,7 @@ public final class BulletsDemo {
HSLFTextBox shape = new HSLFTextBox();
HSLFTextParagraph rt = shape.getTextParagraphs().get(0);
rt.getTextRuns().get(0).setFontSize(42);
rt.getTextRuns().get(0).setFontSize(42d);
rt.setBullet(true);
rt.setIndent(0d); //bullet offset
rt.setLeftMargin(50d); //text offset (should be greater than bullet offset)

View File

@ -55,7 +55,7 @@ public final class TableDemo {
HSLFTableCell cell = table1.getCell(i, j);
HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
rt.setFontFamily("Arial");
rt.setFontSize(10);
rt.setFontSize(10d);
if(i == 0){
cell.getFill().setForegroundColor(new Color(227, 227, 227));
} else {
@ -93,17 +93,17 @@ public final class TableDemo {
for (int j = 0; j < txt2[i].length; j++) {
HSLFTableCell cell = table2.getCell(i, j);
HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0);
rt.setFontSize(10);
rt.setFontSize(10d);
rt.setFontFamily("Arial");
if(i == 0){
cell.getFill().setForegroundColor(new Color(0, 51, 102));
rt.setFontColor(Color.white);
rt.setBold(true);
rt.setFontSize(14);
rt.setFontSize(14d);
cell.setHorizontalCentered(true);
} else {
rt.getTextParagraph().setBullet(true);
rt.setFontSize(12);
rt.setFontSize(12d);
rt.getTextParagraph().setAlignment(TextAlign.LEFT);
cell.setHorizontalCentered(false);
}

View File

@ -42,7 +42,7 @@ public class Tutorial2 {
XSLFTextParagraph p1 = shape1.addNewTextParagraph();
XSLFTextRun r1 = p1.addNewTextRun();
r1.setText("Paragraph Formatting");
r1.setFontSize(24);
r1.setFontSize(24d);
r1.setFontColor(new Color(85, 142, 213));
XSLFTextParagraph p2 = shape1.addNewTextParagraph();
@ -52,20 +52,20 @@ public class Tutorial2 {
p2.setSpaceAfter(300d); // 3 lines after the paragraph
XSLFTextRun r2 = p2.addNewTextRun();
r2.setText("Paragraph properties apply to all text residing within the corresponding paragraph.");
r2.setFontSize(16);
r2.setFontSize(16d);
XSLFTextParagraph p3 = shape1.addNewTextParagraph();
XSLFTextRun r3 = p3.addNewTextRun();
r3.setText("Run Formatting");
r3.setFontSize(24);
r3.setFontSize(24d);
r3.setFontColor(new Color(85, 142, 213));
XSLFTextParagraph p4 = shape1.addNewTextParagraph();
p4.setSpaceBefore(-20d); // 20 pt from the previous paragraph
p4.setSpaceAfter(300d); // 3 lines after the paragraph
XSLFTextRun r4 = p4.addNewTextRun();
r4.setFontSize(16);
r4.setFontSize(16d);
r4.setText(
"Run level formatting is the most granular property level and allows " +
"for the specifying of all low level text properties. The text run is " +

View File

@ -142,6 +142,12 @@ public abstract class XSLFShape implements Shape {
if (pr == null) {
pr = shape.getGrpSpPr();
}
if (pr == null) {
if (shape.getXmlObject() instanceof CTBackground) {
pr = shape.getXmlObject();
}
}
if (pr == null) {
setValue(PaintStyle.TRANSPARENT_PAINT);
return true;
@ -174,29 +180,7 @@ public abstract class XSLFShape implements Shape {
if (fillRef == null) {
fillRef = getBgRef();
}
if (fillRef == null) {
return PaintStyle.TRANSPARENT_PAINT;
}
// The idx attribute refers to the index of a fill style or
// background fill style within the presentation's style matrix, defined by the fmtScheme element.
// value of 0 or 1000 indicates no background,
// values 1-999 refer to the index of a fill style within the fillStyleLst element
// values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element.
int idx = (int)fillRef.getIdx();
CTSchemeColor phClr = fillRef.getSchemeClr();
XSLFSheet sheet = getSheet();
XSLFTheme theme = sheet.getTheme();
XmlObject fillProps = null;
CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme();
if(idx >= 1 && idx <= 999){
fillProps = matrix.getFillStyleLst().selectPath("*")[idx - 1];
} else if (idx >= 1001 ){
fillProps = matrix.getBgFillStyleLst().selectPath("*")[idx - 1001];
}
if(fillProps != null) {
paint = selectPaint(fillProps, phClr, sheet.getPackagePart());
}
paint = selectPaint(fillRef);
return paint == null ? PaintStyle.TRANSPARENT_PAINT : paint;
}
@ -250,6 +234,28 @@ public abstract class XSLFShape implements Shape {
}
return _ph;
}
/**
* Specifies that the corresponding shape should be represented by the generating application
* as a placeholder. When a shape is considered a placeholder by the generating application
* it can have special properties to alert the user that they may enter content into the shape.
* Different types of placeholders are allowed and can be specified by using the placeholder
* type attribute for this element
*
* @param placeholder
*/
protected void setPlaceholder(Placeholder placeholder) {
String xquery = "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:nvPr";
CTApplicationNonVisualDrawingProps nv = selectProperty(CTApplicationNonVisualDrawingProps.class, xquery);
if (nv == null) return;
if(placeholder == null) {
if (nv.isSetPh()) nv.unsetPh();
_ph = null;
} else {
nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ordinal() + 1));
}
}
/**
* As there's no xmlbeans hierarchy, but XSLF works with subclassing, not all
@ -365,6 +371,8 @@ public abstract class XSLFShape implements Shape {
return selectPaint((CTBlipFillProperties)obj, phClr, parentPart);
} else if (obj instanceof CTGradientFillProperties) {
return selectPaint((CTGradientFillProperties) obj, phClr, parentPart);
} else if (obj instanceof CTStyleMatrixReference) {
return selectPaint((CTStyleMatrixReference)obj);
} else {
return null;
}
@ -479,5 +487,25 @@ public abstract class XSLFShape implements Shape {
};
}
protected PaintStyle selectPaint(CTStyleMatrixReference fillRef) {
if (fillRef == null) return null;
// The idx attribute refers to the index of a fill style or
// background fill style within the presentation's style matrix, defined by the fmtScheme element.
// value of 0 or 1000 indicates no background,
// values 1-999 refer to the index of a fill style within the fillStyleLst element
// values 1001 and above refer to the index of a background fill style within the bgFillStyleLst element.
int idx = (int)fillRef.getIdx();
CTSchemeColor phClr = fillRef.getSchemeClr();
XSLFSheet sheet = getSheet();
XSLFTheme theme = sheet.getTheme();
XmlObject fillProps = null;
CTStyleMatrix matrix = theme.getXmlObject().getThemeElements().getFmtScheme();
if (idx >= 1 && idx <= 999) {
fillProps = matrix.getFillStyleLst().selectPath("*")[idx - 1];
} else if (idx >= 1001 ){
fillProps = matrix.getBgFillStyleLst().selectPath("*")[idx - 1001];
}
return (fillProps == null) ? null : selectPaint(fillProps, phClr, theme.getPackagePart());
}
}

View File

@ -118,7 +118,7 @@ public class XSLFTableCell extends XSLFTextShape {
private double getBorderWidth(char bltr) {
CTLineProperties ln = getCTLine(bltr, false);
return (ln == null) ? defaultBorderWidth : Units.toPoints(ln.getW());
return (ln == null || !ln.isSetW()) ? defaultBorderWidth : Units.toPoints(ln.getW());
}
private void setBorderColor(char bltr, Color color) {

View File

@ -23,6 +23,7 @@ import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.util.*;
import org.apache.poi.xslf.model.ParagraphPropertyFetcher;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.*;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
@ -379,9 +380,9 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
@Override
public void setIndent(Double indent){
if ((indent == null || indent == -1d) && !_p.isSetPPr()) return;
if ((indent == null) && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
if(indent == -1) {
if(indent == null) {
if(pr.isSetIndent()) pr.unsetIndent();
} else {
pr.setIndent(Units.toEMU(indent));
@ -441,7 +442,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
public void setRightMargin(Double rightMargin){
if (rightMargin == null && !_p.isSetPPr()) return;
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
if(rightMargin == -1) {
if(rightMargin == null) {
if(pr.isSetMarR()) pr.unsetMarR();
} else {
pr.setMarR(Units.toEMU(rightMargin));
@ -788,69 +789,102 @@ public class XSLFTextParagraph implements TextParagraph<XSLFTextRun> {
return ok;
}
void copy(XSLFTextParagraph p){
TextAlign srcAlign = p.getTextAlign();
void copy(XSLFTextParagraph other){
if (other == this) return;
CTTextParagraph thisP = getXmlObject();
CTTextParagraph otherP = other.getXmlObject();
if (thisP.isSetPPr()) thisP.unsetPPr();
if (thisP.isSetEndParaRPr()) thisP.unsetEndParaRPr();
_runs.clear();
for (int i=thisP.sizeOfBrArray(); i>0; i--) {
thisP.removeBr(i-1);
}
for (int i=thisP.sizeOfRArray(); i>0; i--) {
thisP.removeR(i-1);
}
for (int i=thisP.sizeOfFldArray(); i>0; i--) {
thisP.removeFld(i-1);
}
XmlCursor thisC = thisP.newCursor();
thisC.toEndToken();
XmlCursor otherC = otherP.newCursor();
otherC.copyXmlContents(thisC);
otherC.dispose();
thisC.dispose();
List<XSLFTextRun> otherRs = other.getTextRuns();
int i=0;
for(CTRegularTextRun rtr : thisP.getRArray()) {
XSLFTextRun run = new XSLFTextRun(rtr, this);
run.copy(otherRs.get(i++));
_runs.add(run);
}
// set properties again, in case we are based on a different
// template
TextAlign srcAlign = other.getTextAlign();
if(srcAlign != getTextAlign()){
setTextAlign(srcAlign);
}
boolean isBullet = p.isBullet();
boolean isBullet = other.isBullet();
if(isBullet != isBullet()){
setBullet(isBullet);
if(isBullet) {
String buFont = p.getBulletFont();
String buFont = other.getBulletFont();
if(buFont != null && !buFont.equals(getBulletFont())){
setBulletFont(buFont);
}
String buChar = p.getBulletCharacter();
String buChar = other.getBulletCharacter();
if(buChar != null && !buChar.equals(getBulletCharacter())){
setBulletCharacter(buChar);
}
Color buColor = p.getBulletFontColor();
Color buColor = other.getBulletFontColor();
if(buColor != null && !buColor.equals(getBulletFontColor())){
setBulletFontColor(buColor);
}
double buSize = p.getBulletFontSize();
if(buSize != getBulletFontSize()){
Double buSize = other.getBulletFontSize();
if(!doubleEquals(buSize, getBulletFontSize())){
setBulletFontSize(buSize);
}
}
}
Double leftMargin = p.getLeftMargin();
if(leftMargin != getLeftMargin()){
Double leftMargin = other.getLeftMargin();
if (!doubleEquals(leftMargin, getLeftMargin())){
setLeftMargin(leftMargin);
}
Double indent = p.getIndent();
if(indent != getIndent()){
Double indent = other.getIndent();
if (!doubleEquals(indent, getIndent())) {
setIndent(indent);
}
Double spaceAfter = p.getSpaceAfter();
if(spaceAfter != getSpaceAfter()){
Double spaceAfter = other.getSpaceAfter();
if (!doubleEquals(spaceAfter, getSpaceAfter())) {
setSpaceAfter(spaceAfter);
}
Double spaceBefore = p.getSpaceBefore();
if(spaceBefore != getSpaceBefore()){
Double spaceBefore = other.getSpaceBefore();
if (!doubleEquals(spaceBefore, getSpaceBefore())) {
setSpaceBefore(spaceBefore);
}
Double lineSpacing = p.getLineSpacing();
if(lineSpacing != getLineSpacing()){
Double lineSpacing = other.getLineSpacing();
if (!doubleEquals(lineSpacing, getLineSpacing())) {
setLineSpacing(lineSpacing);
}
List<XSLFTextRun> srcR = p.getTextRuns();
List<XSLFTextRun> tgtR = getTextRuns();
for(int i = 0; i < srcR.size(); i++){
XSLFTextRun r1 = srcR.get(i);
XSLFTextRun r2 = tgtR.get(i);
r2.copy(r1);
}
}
private static boolean doubleEquals(Double d1, Double d2) {
return (d1 == d2 || (d1 != null && d1.equals(d2)));
}
@Override
public Double getDefaultFontSize() {
CTTextCharacterProperties endPr = _p.getEndParaRPr();

View File

@ -82,7 +82,8 @@ public class XSLFTextRun implements TextRun {
return _r;
}
public void setFontColor(Color color){
@Override
public void setFontColor(Color color) {
CTTextCharacterProperties rPr = getRPr();
CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill();
CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();
@ -96,6 +97,7 @@ public class XSLFTextRun implements TextRun {
}
@Override
public Color getFontColor(){
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
CTShapeStyle style = _p.getParentShape().getSpStyle();
@ -119,17 +121,13 @@ public class XSLFTextRun implements TextRun {
return fetcher.getValue();
}
/**
*
* @param fontSize font size in points.
* The value of <code>-1</code> unsets the Sz attribyte from the underlying xml bean
*/
public void setFontSize(double fontSize){
@Override
public void setFontSize(Double fontSize){
CTTextCharacterProperties rPr = getRPr();
if(fontSize == -1.0) {
if(rPr.isSetSz()) rPr.unsetSz();
if(fontSize == null) {
if (rPr.isSetSz()) rPr.unsetSz();
} else {
if(fontSize < 1.0) {
if (fontSize < 1.0) {
throw new IllegalArgumentException("Minimum font size is 1pt but was " + fontSize);
}
@ -137,9 +135,6 @@ public class XSLFTextRun implements TextRun {
}
}
/**
* @return font size in points or null if font size is not set.
*/
@Override
public Double getFontSize(){
double scale = 1;

View File

@ -433,6 +433,10 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements TextShape
protected abstract CTTextBody getTextBody(boolean create);
@Override
public void setPlaceholder(Placeholder placeholder) {
super.setPlaceholder(placeholder);
}
public Placeholder getTextType(){
CTPlaceholder ph = getCTPlaceholder();
@ -442,27 +446,6 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements TextShape
return Placeholder.values()[val - 1];
}
/**
* Specifies that the corresponding shape should be represented by the generating application
* as a placeholder. When a shape is considered a placeholder by the generating application
* it can have special properties to alert the user that they may enter content into the shape.
* Different types of placeholders are allowed and can be specified by using the placeholder
* type attribute for this element
*
* @param placeholder
*/
public void setPlaceholder(Placeholder placeholder){
String xquery = "declare namespace p='http://schemas.openxmlformats.org/presentationml/2006/main' .//*/p:nvPr";
CTApplicationNonVisualDrawingProps nv = selectProperty(CTApplicationNonVisualDrawingProps.class, xquery);
if (nv == null) return;
if(placeholder == null) {
if (nv.isSetPh()) nv.unsetPh();
} else {
nv.addNewPh().setType(STPlaceholderType.Enum.forInt(placeholder.ordinal() + 1));
}
}
@Override
public double getTextHeight(){
DrawFactory drawFact = DrawFactory.getInstance(null);
@ -490,45 +473,55 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements TextShape
@Override
void copy(XSLFShape sh){
super.copy(sh);
void copy(XSLFShape other){
super.copy(other);
XSLFTextShape tsh = (XSLFTextShape)sh;
XSLFTextShape otherTS = (XSLFTextShape)other;
CTTextBody otherTB = otherTS.getTextBody(false);
CTTextBody thisTB = getTextBody(true);
if (otherTB == null) {
return;
}
thisTB.setBodyPr((CTTextBodyProperties)otherTB.getBodyPr().copy());
boolean srcWordWrap = tsh.getWordWrap();
if (thisTB.isSetLstStyle()) thisTB.unsetLstStyle();
if (otherTB.isSetLstStyle()) {
thisTB.setLstStyle((CTTextListStyle)otherTB.getLstStyle().copy());
}
boolean srcWordWrap = otherTS.getWordWrap();
if(srcWordWrap != getWordWrap()){
setWordWrap(srcWordWrap);
}
double leftInset = tsh.getLeftInset();
double leftInset = otherTS.getLeftInset();
if(leftInset != getLeftInset()) {
setLeftInset(leftInset);
}
double rightInset = tsh.getRightInset();
double rightInset = otherTS.getRightInset();
if(rightInset != getRightInset()) {
setRightInset(rightInset);
}
double topInset = tsh.getTopInset();
double topInset = otherTS.getTopInset();
if(topInset != getTopInset()) {
setTopInset(topInset);
}
double bottomInset = tsh.getBottomInset();
double bottomInset = otherTS.getBottomInset();
if(bottomInset != getBottomInset()) {
setBottomInset(bottomInset);
}
VerticalAlignment vAlign = tsh.getVerticalAlignment();
VerticalAlignment vAlign = otherTS.getVerticalAlignment();
if(vAlign != getVerticalAlignment()) {
setVerticalAlignment(vAlign);
}
List<XSLFTextParagraph> srcP = tsh.getTextParagraphs();
List<XSLFTextParagraph> tgtP = getTextParagraphs();
for(int i = 0; i < srcP.size(); i++){
XSLFTextParagraph p1 = srcP.get(i);
XSLFTextParagraph p2 = tgtP.get(i);
p2.copy(p1);
clearText();
for (XSLFTextParagraph srcP : otherTS.getTextParagraphs()) {
XSLFTextParagraph tgtP = addNewTextParagraph();
tgtP.copy(srcP);
}
}
}

View File

@ -125,7 +125,7 @@ public class TestXSLFAutoShape {
p.setIndent(2.0);
assertEquals(2.0, p.getIndent(), 0);
assertTrue(p.getXmlObject().getPPr().isSetIndent());
p.setIndent(-1d);
p.setIndent(null);
assertNull(p.getIndent());
assertFalse(p.getXmlObject().getPPr().isSetIndent());
p.setIndent(10.0);
@ -225,7 +225,7 @@ public class TestXSLFAutoShape {
assertEquals(1000, r.getXmlObject().getRPr().getSz());
r.setFontSize(12.5);
assertEquals(1250, r.getXmlObject().getRPr().getSz());
r.setFontSize(-1);
r.setFontSize(null);
assertFalse(r.getXmlObject().getRPr().isSetSz());
assertFalse(r.getXmlObject().getRPr().isSetLatin());

View File

@ -143,7 +143,7 @@ public class TestXSLFSlide {
assertFalse(r2.isItalic());
assertEquals(Color.white, r2.getFontColor());
assertEquals(new Color(148, 198, 0), sh2.getFillColor());
assertEquals(new Color(74, 99, 0), sh2.getLineColor()); // slightly different from PowerPoint!
assertEquals(new Color(148, 198, 0), sh2.getLineColor()); // slightly different from PowerPoint!
// the 5th slide has a picture and a texture fill
XSLFSlide slide2 = ppt.createSlide().importContent(src.getSlides().get(4));

View File

@ -78,7 +78,6 @@ public class TestXSLFTextBox {
assertEquals(20.0, r.getFontSize(), 0);
pPr.unsetSz(); // Should never be
assertEquals(-1.0, r.getFontSize(), 0);
assertNull(r.getFontSize());
}
}

View File

@ -30,6 +30,7 @@ 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;
/**
@ -74,16 +75,16 @@ public class TestXSLFTextParagraph {
DrawTextParagraphProxy dtp = new DrawTextParagraphProxy(p);
double leftInset = sh.getLeftInset();
double rightInset = sh.getRightInset();
Double leftInset = sh.getLeftInset();
Double rightInset = sh.getRightInset();
assertEquals(7.2, leftInset, 0);
assertEquals(7.2, rightInset, 0);
double leftMargin = p.getLeftMargin();
Double leftMargin = p.getLeftMargin();
assertEquals(0.0, leftMargin, 0);
double indent = p.getIndent();
assertEquals(0.0, indent, 0); // default
Double indent = p.getIndent();
assertNull(indent); // default
double expectedWidth;
@ -150,10 +151,7 @@ public class TestXSLFTextParagraph {
@Test
public void testBreakLines(){
String os = System.getProperty("os.name");
if(os == null || !os.contains("Windows")) {
_logger.log(POILogger.WARN, "Skipping testBreakLines(), it is executed only on Windows machines");
return;
}
Assume.assumeTrue("Skipping testBreakLines(), it is executed only on Windows machines", (os != null && os.contains("Windows")));
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide();
@ -162,7 +160,7 @@ public class TestXSLFTextParagraph {
XSLFTextParagraph p = sh.addNewTextParagraph();
XSLFTextRun r = p.addNewTextRun();
r.setFontFamily("Arial"); // this should always be available
r.setFontSize(12);
r.setFontSize(12d);
r.setText(
"Paragraph formatting allows for more granular control " +
"of text within a shape. Properties here apply to all text " +
@ -179,13 +177,13 @@ public class TestXSLFTextParagraph {
lines = dtp.getLines();
assertEquals(4, lines.size());
// descrease the shape width from 300 pt to 100 pt
// decrease the shape width from 300 pt to 100 pt
sh.setAnchor(new Rectangle(50, 50, 100, 200));
dtp.breakText(graphics);
lines = dtp.getLines();
assertEquals(12, lines.size());
// descrease the shape width from 300 pt to 100 pt
// decrease the shape width from 300 pt to 100 pt
sh.setAnchor(new Rectangle(50, 50, 600, 200));
dtp.breakText(graphics);
lines = dtp.getLines();
@ -224,12 +222,13 @@ public class TestXSLFTextParagraph {
XSLFTextParagraph p2 = sh2.addNewTextParagraph();
XSLFTextRun r2 = p2.addNewTextRun();
r2.setFontFamily("serif"); // this should always be available
r2.setFontSize(30);
r2.setFontSize(30d);
r2.setText("Apache\n");
XSLFTextRun r3 = p2.addNewTextRun();
r3.setFontFamily("serif"); // this should always be available
r3.setFontSize(10);
r3.setFontSize(10d);
r3.setText("POI");
dtp = new DrawTextParagraphProxy(p2);
dtp.breakText(graphics);
lines = dtp.getLines();
assertEquals(2, lines.size());
@ -278,7 +277,7 @@ public class TestXSLFTextParagraph {
p.setBulletFontColor(Color.red);
assertEquals(Color.red, p.getBulletFontColor());
assertEquals(100.0, p.getBulletFontSize(), 0);
assertNull(p.getBulletFontSize());
p.setBulletFontSize(200.);
assertEquals(200., p.getBulletFontSize(), 0);
p.setBulletFontSize(-20.);
@ -286,17 +285,21 @@ public class TestXSLFTextParagraph {
assertEquals(72.0, p.getDefaultTabSize(), 0);
assertEquals(0.0, p.getIndent(), 0);
assertNull(p.getIndent());
p.setIndent(72.0);
assertEquals(72.0, p.getIndent(), 0);
p.setIndent(-1.0); // the value of -1.0 resets to the defaults
assertEquals(0.0, p.getIndent(), 0);
p.setIndent(-1d); // the value of -1.0 resets to the defaults (not any more ...)
assertEquals(-1d, p.getIndent(), 0);
p.setIndent(null);
assertNull(p.getIndent());
assertEquals(0.0, p.getLeftMargin(), 0);
p.setLeftMargin(72.0);
assertEquals(72.0, p.getLeftMargin(), 0);
p.setLeftMargin(-1.0); // the value of -1.0 resets to the defaults
assertEquals(0.0, p.getLeftMargin(), 0);
assertEquals(-1.0, p.getLeftMargin(), 0);
p.setLeftMargin(null);
assertEquals(0d, p.getLeftMargin(), 0); // default will be taken from master
assertEquals(0, p.getIndentLevel());
p.setIndentLevel(1);
@ -304,19 +307,19 @@ public class TestXSLFTextParagraph {
p.setIndentLevel(2);
assertEquals(2, p.getIndentLevel());
assertEquals(100., p.getLineSpacing(), 0);
assertNull(p.getLineSpacing());
p.setLineSpacing(200.);
assertEquals(200.0, p.getLineSpacing(), 0);
p.setLineSpacing(-15.);
assertEquals(-15.0, p.getLineSpacing(), 0);
assertEquals(0., p.getSpaceAfter(), 0);
assertNull(p.getSpaceAfter());
p.setSpaceAfter(200.);
assertEquals(200.0, p.getSpaceAfter(), 0);
p.setSpaceAfter(-15.);
assertEquals(-15.0, p.getSpaceAfter(), 0);
assertEquals(0., p.getSpaceBefore(), 0);
assertNull(p.getSpaceBefore());
p.setSpaceBefore(200.);
assertEquals(200.0, p.getSpaceBefore(), 0);
p.setSpaceBefore(-15.);

View File

@ -24,6 +24,7 @@ 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.presentationml.x2006.main.CTPlaceholder;
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
@ -33,6 +34,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
*/
public class TestXSLFTextShape {
@Test
public void testLayouts(){
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("layouts.pptx");
@ -612,7 +614,7 @@ public class TestXSLFTextShape {
assertEquals("10", sldNum.getText());
}
@Test
public void testTitleStyles(){
XMLSlideShow ppt = new XMLSlideShow();
@ -693,6 +695,7 @@ public class TestXSLFTextShape {
assertEquals(TextAlign.CENTER, paragraph.getTextAlign());
}
@Test
public void testBodyStyles(){
XMLSlideShow ppt = new XMLSlideShow();

View File

@ -59,7 +59,7 @@ public class TestXSLFTheme {
}
void slide1(XSLFSlide slide){
assertEquals(Color.white, slide.getBackground().getFillColor());
assertEquals(Color.WHITE, slide.getBackground().getFillColor());
XSLFTheme theme = slide.getTheme();
assertEquals("Office Theme", theme.getName());
@ -75,7 +75,7 @@ public class TestXSLFTheme {
void slide2(XSLFSlide slide){
// Background 2, darker 10%
// YK: PPT shows slightly different color: new Color(221, 217, 195)
assertEquals(new Color(214, 212, 203), slide.getBackground().getFillColor());
assertEquals(new Color(221, 217, 195), slide.getBackground().getFillColor());
}
void slide3(XSLFSlide slide){
@ -133,7 +133,7 @@ public class TestXSLFTheme {
void slide7(XSLFSlide slide){
//YK: PPT reports a slightly different color: r=189,g=239,b=87
assertEquals(new Color(182, 218, 108), slide.getBackground().getFillColor());
assertEquals(new Color(189, 239, 87), slide.getBackground().getFillColor());
assertFalse(slide.getFollowMasterGraphics());
}

View File

@ -256,7 +256,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable {
txt.setText(s);
HSLFTextRun rt = txt.getTextParagraphs().get(0).getTextRuns().get(0);
rt.setFontSize(_font.getSize());
rt.setFontSize((double)_font.getSize());
rt.setFontFamily(_font.getFamily());
if (getColor() != null) rt.setFontColor(getColor());

View File

@ -141,7 +141,7 @@ public final class HSLFTextRun implements TextRun {
* @param propName The name of the Paragraph TextProp
* @param val The value to set for the TextProp
*/
public void setCharTextPropVal(String propName, int val) {
public void setCharTextPropVal(String propName, Integer val) {
setPropVal(characterStyle, propName, val);
}
@ -251,20 +251,17 @@ public final class HSLFTextRun implements TextRun {
setPropVal(characterStyle, "superscript", val);
}
/**
* Gets the font size
*/
@Override
public Double getFontSize() {
TextProp tp = getPropVal(characterStyle, "font.size", parentParagraph);
return tp == null ? null : (double)tp.getValue();
}
/**
* Sets the font size
*/
public void setFontSize(int fontSize) {
setCharTextPropVal("font.size", fontSize);
@Override
public void setFontSize(Double fontSize) {
Integer iFontSize = (fontSize == null) ? null : fontSize.intValue();
setCharTextPropVal("font.size", iFontSize);
}
/**

View File

@ -18,12 +18,11 @@
package org.apache.poi.sl.draw;
import static org.apache.poi.sl.usermodel.PaintStyle.TRANSPARENT_PAINT;
import java.awt.*;
import java.awt.MultipleGradientPaint.ColorSpaceType;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.Shape;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.IOException;
import java.io.InputStream;
@ -35,7 +34,13 @@ import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
/**
* This class handles color transformations
*
* @see HSL code taken from <a href="https://tips4java.wordpress.com/2009/07/05/hsl-color/">Java Tips Weblog</a>
*/
public class DrawPaint {
// HSL code is public domain - see https://tips4java.wordpress.com/contact-us/
private final static POILogger LOG = POILogFactory.getLogger(DrawPaint.class);
@ -126,7 +131,7 @@ public class DrawPaint {
}
result = applyAlpha(result, color);
result = applyLuminanace(result, color);
result = applyLuminance(result, color);
result = applyShade(result, color);
result = applyTint(result, color);
@ -135,7 +140,7 @@ public class DrawPaint {
protected static Color applyAlpha(Color c, ColorStyle fc) {
int alpha = c.getAlpha();
return (alpha == 0 || alpha == -1) ? c : new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha);
return (alpha == 255) ? c : new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha);
}
/**
@ -145,8 +150,10 @@ public class DrawPaint {
* @param lumMod luminance modulation in the range [0..100000]
* @param lumOff luminance offset in the range [0..100000]
* @return modified color
*
* @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 applyLuminanace(Color c, ColorStyle fc) {
protected static Color applyLuminance(Color c, ColorStyle fc) {
int lumMod = fc.getLumMod();
if (lumMod == -1) lumMod = 100000;
@ -155,24 +162,33 @@ public class DrawPaint {
if (lumMod == 100000 && lumOff == 0) return c;
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
// 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.)
float red,green,blue;
double fLumOff = lumOff / 100000d;
double fLumMod = lumMod / 100000d;
if (lumOff > 0) {
float flumOff = lumOff / 100000.f;
red = (255.f - r) * (1.f - flumOff) + r;
green = (255.f - g) * flumOff + g;
blue = (255.f - b) * flumOff + b;
} else {
float flumMod = lumMod / 100000.f;
red = r * flumMod;
green = g * flumMod;
blue = b * flumMod;
}
return new Color(Math.round(red), Math.round(green), Math.round(blue), c.getAlpha());
double hsl[] = RGB2HSL(c);
hsl[2] = hsl[2]*fLumMod+fLumOff;
Color c2 = HSL2RGB(hsl[0], hsl[1], hsl[2], c.getAlpha()/255d);
return c2;
}
/**
@ -302,165 +318,127 @@ public class DrawPaint {
}
}
public static class PathGradientPaint implements Paint {
// http://asserttrue.blogspot.de/2010/01/how-to-iimplement-custom-paint-in-50.html
protected final Color colors[];
protected final float fractions[];
protected final int capStyle;
protected final int joinStyle;
protected final int transparency;
public PathGradientPaint(Color colors[], float fractions[]) {
this(colors,fractions,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
}
public PathGradientPaint(Color colors[], float fractions[], int capStyle, int joinStyle) {
this.colors = colors;
this.fractions = fractions;
this.capStyle = capStyle;
this.joinStyle = joinStyle;
// determine transparency
boolean opaque = true;
for (int i = 0; i < colors.length; i++){
opaque = opaque && (colors[i].getAlpha() == 0xff);
}
this.transparency = opaque ? OPAQUE : TRANSLUCENT;
}
public PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform transform,
RenderingHints hints) {
return new PathGradientContext(cm, deviceBounds, userBounds, transform, hints);
}
public int getTransparency() {
return transparency;
/**
* Convert HSL values to a RGB Color.
*
* @param h Hue is specified as degrees in the range 0 - 360.
* @param s Saturation is specified as a percentage in the range 1 - 100.
* @param l Luminance is specified as a percentage in the range 1 - 100.
* @param alpha the alpha value between 0 - 1
*
* @returns the RGB Color object
*/
private static Color HSL2RGB(double h, double s, double l, double alpha) {
if (s <0.0f || s > 100.0f) {
String message = "Color parameter outside of expected range - Saturation";
throw new IllegalArgumentException( message );
}
class PathGradientContext implements PaintContext {
protected final Rectangle deviceBounds;
protected final Rectangle2D userBounds;
protected final AffineTransform xform;
protected final RenderingHints hints;
/**
* for POI: the shape will be only known when the subclasses determines the concrete implementation
* in the draw/-content method, so we need to postpone the setting/creation as long as possible
**/
protected final Shape shape;
protected final PaintContext pCtx;
protected final int gradientSteps;
WritableRaster raster;
public PathGradientContext(
ColorModel cm
, Rectangle deviceBounds
, Rectangle2D userBounds
, AffineTransform xform
, RenderingHints hints
) {
shape = (Shape)hints.get(Drawable.GRADIENT_SHAPE);
if (shape == null) {
throw new IllegalPathStateException("PathGradientPaint needs a shape to be set via the rendering hint PathGradientPaint.GRADIANT_SHAPE.");
}
this.deviceBounds = deviceBounds;
this.userBounds = userBounds;
this.xform = xform;
this.hints = hints;
gradientSteps = getGradientSteps(shape);
Point2D start = new Point2D.Double(0, 0);
Point2D end = new Point2D.Double(gradientSteps, 0);
LinearGradientPaint gradientPaint = new LinearGradientPaint(start, end, fractions, colors, CycleMethod.NO_CYCLE, ColorSpaceType.SRGB, new AffineTransform());
Rectangle bounds = new Rectangle(0, 0, gradientSteps, 1);
pCtx = gradientPaint.createContext(cm, bounds, bounds, new AffineTransform(), hints);
}
public void dispose() {}
public ColorModel getColorModel() {
return pCtx.getColorModel();
}
public Raster getRaster(int xOffset, int yOffset, int w, int h) {
ColorModel cm = getColorModel();
if (raster == null) createRaster();
// TODO: eventually use caching here
WritableRaster childRaster = cm.createCompatibleWritableRaster(w, h);
Rectangle2D childRect = new Rectangle2D.Double(xOffset, yOffset, w, h);
if (!childRect.intersects(deviceBounds)) {
// usually doesn't happen ...
return childRaster;
}
Rectangle2D destRect = new Rectangle2D.Double();
Rectangle2D.intersect(childRect, deviceBounds, destRect);
int dx = (int)(destRect.getX()-deviceBounds.getX());
int dy = (int)(destRect.getY()-deviceBounds.getY());
int dw = (int)destRect.getWidth();
int dh = (int)destRect.getHeight();
Object data = raster.getDataElements(dx, dy, dw, dh, null);
dx = (int)(destRect.getX()-childRect.getX());
dy = (int)(destRect.getY()-childRect.getY());
childRaster.setDataElements(dx, dy, dw, dh, data);
return childRaster;
}
protected int getGradientSteps(Shape shape) {
Rectangle rect = shape.getBounds();
int lower = 1;
int upper = (int)(Math.max(rect.getWidth(),rect.getHeight())/2.0);
while (lower < upper-1) {
int mid = lower + (upper - lower) / 2;
BasicStroke bs = new BasicStroke(mid, capStyle, joinStyle);
Area area = new Area(bs.createStrokedShape(shape));
if (area.isSingular()) {
upper = mid;
} else {
lower = mid;
}
}
return upper;
}
protected void createRaster() {
ColorModel cm = getColorModel();
raster = cm.createCompatibleWritableRaster((int)deviceBounds.getWidth(), (int)deviceBounds.getHeight());
BufferedImage img = new BufferedImage(cm, raster, false, null);
Graphics2D graphics = img.createGraphics();
graphics.setRenderingHints(hints);
graphics.translate(-deviceBounds.getX(), -deviceBounds.getY());
graphics.transform(xform);
Raster img2 = pCtx.getRaster(0, 0, gradientSteps, 1);
int rgb[] = new int[cm.getNumComponents()];
for (int i = gradientSteps-1; i>=0; i--) {
img2.getPixel(i, 0, rgb);
Color c = new Color(rgb[0],rgb[1],rgb[2]);
if (rgb.length == 4) {
// it doesn't work to use just a color with transparency ...
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, rgb[3]/255.0f));
}
graphics.setStroke(new BasicStroke(i+1, capStyle, joinStyle));
graphics.setColor(c);
graphics.draw(shape);
}
graphics.dispose();
}
if (l <0.0f || l > 100.0f) {
String message = "Color parameter outside of expected range - Luminance";
throw new IllegalArgumentException( message );
}
if (alpha <0.0f || alpha > 1.0f) {
String message = "Color parameter outside of expected range - Alpha";
throw new IllegalArgumentException( message );
}
// Formula needs all values between 0 - 1.
h = h % 360.0f;
h /= 360f;
s /= 100f;
l /= 100f;
double q = (l < 0.5d)
? l * (1d + s)
: (l + s) - (s * l);
double p = 2d * l - q;
double r = Math.max(0, HUE2RGB(p, q, h + (1.0d / 3.0d)));
double g = Math.max(0, HUE2RGB(p, q, h));
double b = Math.max(0, HUE2RGB(p, q, h - (1.0d / 3.0d)));
r = Math.min(r, 1.0d);
g = Math.min(g, 1.0d);
b = Math.min(b, 1.0d);
return new Color((float)r, (float)g, (float)b, (float)alpha);
}
}
private static double HUE2RGB(double p, double q, double h) {
if (h < 0d) h += 1d;
if (h > 1d) h -= 1d;
if (6d * h < 1d) {
return p + ((q - p) * 6d * h);
}
if (2d * h < 1d) {
return q;
}
if (3d * h < 2d) {
return p + ( (q - p) * 6d * ((2.0d / 3.0d) - h) );
}
return p;
}
/**
* Convert a RGB Color to it corresponding HSL values.
*
* @return an array containing the 3 HSL values.
*/
private static double[] RGB2HSL(Color color)
{
// Get RGB values in the range 0 - 1
float[] rgb = color.getRGBColorComponents( null );
double r = rgb[0];
double g = rgb[1];
double b = rgb[2];
// Minimum and Maximum RGB values are used in the HSL calculations
double min = Math.min(r, Math.min(g, b));
double max = Math.max(r, Math.max(g, b));
// Calculate the Hue
double h = 0;
if (max == min) {
h = 0;
} else if (max == r) {
h = ((60d * (g - b) / (max - min)) + 360d) % 360d;
} else if (max == g) {
h = (60d * (b - r) / (max - min)) + 120d;
} else if (max == b) {
h = (60d * (r - g) / (max - min)) + 240d;
}
// Calculate the Luminance
double l = (max + min) / 2d;
// Calculate the Saturation
double s = 0;
if (max == min) {
s = 0;
} else if (l <= .5d) {
s = (max - min) / (max + min);
} else {
s = (max - min) / (2d - max - min);
}
return new double[] {h, s * 100, l * 100};
}
}

View File

@ -34,7 +34,6 @@ import org.apache.poi.util.Units;
public class DrawTextParagraph<T extends TextRun> implements Drawable {
protected TextParagraph<T> paragraph;
double x, y;
protected Insets2D insets = new Insets2D(0,0,0,0);
protected List<DrawTextFragment> lines = new ArrayList<DrawTextFragment>();
protected String rawText;
protected DrawTextFragment bullet;
@ -49,14 +48,6 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
this.paragraph = paragraph;
}
public Insets2D getInsets() {
return insets;
}
public void setInsets(Insets2D insets) {
this.insets.set(insets.top, insets.left, insets.bottom, insets.right);
}
public void setPosition(double x, double y) {
// TODO: replace it, by applyTransform????
this.x = x;
@ -78,6 +69,7 @@ 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;
@ -336,6 +328,7 @@ public class DrawTextParagraph<T extends TextRun> implements Drawable {
protected double getWrappingWidth(boolean firstLine, Graphics2D graphics){
// internal margins for the text box
Insets2D insets = paragraph.getParentShape().getInsets();
double leftInset = insets.left;
double rightInset = insets.right;

View File

@ -119,7 +119,6 @@ public class DrawTextShape<T extends TextShape<? extends TextParagraph<? extends
if (startAt > autoNbrIdx) autoNbrIdx = startAt;
}
dp.setAutoNumberingIdx(autoNbrIdx);
dp.setInsets(shapePadding);
dp.breakText(graphics);
if (!isFirstLine) {

View File

@ -0,0 +1,186 @@
/* ====================================================================
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.draw;
import java.awt.*;
import java.awt.MultipleGradientPaint.ColorSpaceType;
import java.awt.MultipleGradientPaint.CycleMethod;
import java.awt.geom.*;
import java.awt.image.*;
class PathGradientPaint implements Paint {
// http://asserttrue.blogspot.de/2010/01/how-to-iimplement-custom-paint-in-50.html
protected final Color colors[];
protected final float fractions[];
protected final int capStyle;
protected final int joinStyle;
protected final int transparency;
public PathGradientPaint(Color colors[], float fractions[]) {
this(colors,fractions,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
}
public PathGradientPaint(Color colors[], float fractions[], int capStyle, int joinStyle) {
this.colors = colors;
this.fractions = fractions;
this.capStyle = capStyle;
this.joinStyle = joinStyle;
// determine transparency
boolean opaque = true;
for (int i = 0; i < colors.length; i++){
opaque = opaque && (colors[i].getAlpha() == 0xff);
}
this.transparency = opaque ? OPAQUE : TRANSLUCENT;
}
public PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform transform,
RenderingHints hints) {
return new PathGradientContext(cm, deviceBounds, userBounds, transform, hints);
}
public int getTransparency() {
return transparency;
}
class PathGradientContext implements PaintContext {
protected final Rectangle deviceBounds;
protected final Rectangle2D userBounds;
protected final AffineTransform xform;
protected final RenderingHints hints;
/**
* for POI: the shape will be only known when the subclasses determines the concrete implementation
* in the draw/-content method, so we need to postpone the setting/creation as long as possible
**/
protected final Shape shape;
protected final PaintContext pCtx;
protected final int gradientSteps;
WritableRaster raster;
public PathGradientContext(
ColorModel cm
, Rectangle deviceBounds
, Rectangle2D userBounds
, AffineTransform xform
, RenderingHints hints
) {
shape = (Shape)hints.get(Drawable.GRADIENT_SHAPE);
if (shape == null) {
throw new IllegalPathStateException("PathGradientPaint needs a shape to be set via the rendering hint PathGradientPaint.GRADIANT_SHAPE.");
}
this.deviceBounds = deviceBounds;
this.userBounds = userBounds;
this.xform = xform;
this.hints = hints;
gradientSteps = getGradientSteps(shape);
Point2D start = new Point2D.Double(0, 0);
Point2D end = new Point2D.Double(gradientSteps, 0);
LinearGradientPaint gradientPaint = new LinearGradientPaint(start, end, fractions, colors, CycleMethod.NO_CYCLE, ColorSpaceType.SRGB, new AffineTransform());
Rectangle bounds = new Rectangle(0, 0, gradientSteps, 1);
pCtx = gradientPaint.createContext(cm, bounds, bounds, new AffineTransform(), hints);
}
public void dispose() {}
public ColorModel getColorModel() {
return pCtx.getColorModel();
}
public Raster getRaster(int xOffset, int yOffset, int w, int h) {
ColorModel cm = getColorModel();
if (raster == null) createRaster();
// TODO: eventually use caching here
WritableRaster childRaster = cm.createCompatibleWritableRaster(w, h);
Rectangle2D childRect = new Rectangle2D.Double(xOffset, yOffset, w, h);
if (!childRect.intersects(deviceBounds)) {
// usually doesn't happen ...
return childRaster;
}
Rectangle2D destRect = new Rectangle2D.Double();
Rectangle2D.intersect(childRect, deviceBounds, destRect);
int dx = (int)(destRect.getX()-deviceBounds.getX());
int dy = (int)(destRect.getY()-deviceBounds.getY());
int dw = (int)destRect.getWidth();
int dh = (int)destRect.getHeight();
Object data = raster.getDataElements(dx, dy, dw, dh, null);
dx = (int)(destRect.getX()-childRect.getX());
dy = (int)(destRect.getY()-childRect.getY());
childRaster.setDataElements(dx, dy, dw, dh, data);
return childRaster;
}
protected int getGradientSteps(Shape shape) {
Rectangle rect = shape.getBounds();
int lower = 1;
int upper = (int)(Math.max(rect.getWidth(),rect.getHeight())/2.0);
while (lower < upper-1) {
int mid = lower + (upper - lower) / 2;
BasicStroke bs = new BasicStroke(mid, capStyle, joinStyle);
Area area = new Area(bs.createStrokedShape(shape));
if (area.isSingular()) {
upper = mid;
} else {
lower = mid;
}
}
return upper;
}
protected void createRaster() {
ColorModel cm = getColorModel();
raster = cm.createCompatibleWritableRaster((int)deviceBounds.getWidth(), (int)deviceBounds.getHeight());
BufferedImage img = new BufferedImage(cm, raster, false, null);
Graphics2D graphics = img.createGraphics();
graphics.setRenderingHints(hints);
graphics.translate(-deviceBounds.getX(), -deviceBounds.getY());
graphics.transform(xform);
Raster img2 = pCtx.getRaster(0, 0, gradientSteps, 1);
int rgb[] = new int[cm.getNumComponents()];
for (int i = gradientSteps-1; i>=0; i--) {
img2.getPixel(i, 0, rgb);
Color c = new Color(rgb[0],rgb[1],rgb[2]);
if (rgb.length == 4) {
// it doesn't work to use just a color with transparency ...
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, rgb[3]/255.0f));
}
graphics.setStroke(new BasicStroke(i+1, capStyle, joinStyle));
graphics.setColor(c);
graphics.draw(shape);
}
graphics.dispose();
}
}
}

View File

@ -35,7 +35,18 @@ public interface TextRun {
TextCap getTextCap();
Color getFontColor();
void setFontColor(Color color);
/**
* @return font size in points or null if font size is not set.
*/
Double getFontSize();
/**
* @param fontSize font size in points, if null the underlying fontsize will be unset
*/
void setFontSize(Double fontSize);
String getFontFamily();
boolean isBold();

View File

@ -47,7 +47,7 @@ public final class TestSetBoldItalic {
HSLFTextBox txtbox = new HSLFTextBox();
rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0);
txtbox.setText(val);
rt.setFontSize(42);
rt.setFontSize(42d);
rt.setBold(true);
rt.setItalic(true);
rt.setUnderlined(false);

View File

@ -194,7 +194,7 @@ public final class TestShapes {
rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0);
txtbox.setText(val);
rt.setFontFamily("Arial");
rt.setFontSize(42);
rt.setFontSize(42d);
rt.setBold(true);
rt.setItalic(true);
rt.setUnderlined(false);

View File

@ -168,7 +168,7 @@ public final class TestRichTextRun {
// Change 2nd to different size and font
assertEquals(2, ssRichB.getFontCollection().getChildRecords().length); // Default + TNR
rtrRb.setFontSize(18);
rtrRb.setFontSize(18d);
rtrRb.setFontFamily("Courier");
assertEquals(3, ssRichB.getFontCollection().getChildRecords().length); // Default + TNR + Courier
assertEquals(18, rtrRb.getFontSize(), 0);
@ -183,7 +183,7 @@ public final class TestRichTextRun {
assertNotNull(rtr.getTextParagraph().getParagraphStyle());
// Change Font size
rtr.setFontSize(99);
rtr.setFontSize(99d);
assertEquals(99, rtr.getFontSize(), 0);
assertEquals(defaultFont, rtr.getFontFamily());
assertNotNull(rtr.getCharacterStyle());
@ -191,7 +191,7 @@ public final class TestRichTextRun {
assertEquals(1, ss.getFontCollection().getChildRecords().length); // Default
// Change Font size and name
rtr.setFontSize(25);
rtr.setFontSize(25d);
rtr.setFontFamily("Times New Roman");
assertEquals(25, rtr.getFontSize(), 0);
assertEquals("Times New Roman", rtr.getFontFamily());
@ -209,7 +209,7 @@ public final class TestRichTextRun {
HSLFTextRun rtr = textParass.get(0).get(0).getTextRuns().get(0);
rtr.setBold(true);
rtr.setFontSize(18);
rtr.setFontSize(18d);
rtr.setFontFamily("Courier");
HSLFTextParagraph.storeText(textParass.get(0));
@ -228,7 +228,7 @@ public final class TestRichTextRun {
// Tweak existing one again, to ensure really worked
rtr.setBold(false);
rtr.setFontSize(17);
rtr.setFontSize(17d);
rtr.setFontFamily("CourierZZ");
// Check it took those changes
@ -511,7 +511,7 @@ public final class TestRichTextRun {
"Multiline text");
HSLFTextParagraph rt = shape.getTextParagraphs().get(0);
HSLFTextRun tr = rt.getTextRuns().get(0);
tr.setFontSize(42);
tr.setFontSize(42d);
rt.setBullet(true);
rt.setLeftMargin(50d);
rt.setIndent(0d);