misc improvements in text rendering in xlsf
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1203143 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
959ab00472
commit
91d87aff7d
@ -431,6 +431,8 @@ class RenderableShape {
|
|||||||
|
|
||||||
float lineWidth = (float) _shape.getLineWidth();
|
float lineWidth = (float) _shape.getLineWidth();
|
||||||
if(lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt
|
if(lineWidth == 0.0f) lineWidth = 0.25f; // Both PowerPoint and OOo draw zero-length lines as 0.25pt
|
||||||
|
Number fontScale = (Number)graphics.getRenderingHint(XSLFRenderingHint.GROUP_SCALE);
|
||||||
|
if(fontScale != null) lineWidth *= fontScale.floatValue();
|
||||||
|
|
||||||
LineDash lineDash = _shape.getLineDash();
|
LineDash lineDash = _shape.getLineDash();
|
||||||
float[] dash = null;
|
float[] dash = null;
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* ====================================================================
|
||||||
|
* 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.xslf.usermodel;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.font.TextLayout;
|
||||||
|
import java.text.AttributedCharacterIterator;
|
||||||
|
import java.text.AttributedString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a renderable text fragment
|
||||||
|
*/
|
||||||
|
class TextFragment {
|
||||||
|
final TextLayout _layout;
|
||||||
|
final AttributedString _str;
|
||||||
|
|
||||||
|
TextFragment(TextLayout layout, AttributedString str){
|
||||||
|
_layout = layout;
|
||||||
|
_str = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(Graphics2D graphics, double x, double y){
|
||||||
|
if(_str == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double yBaseline = y + _layout.getAscent();
|
||||||
|
|
||||||
|
Integer textMode = (Integer)graphics.getRenderingHint(XSLFRenderingHint.TEXT_RENDERING_MODE);
|
||||||
|
if(textMode != null && textMode == XSLFRenderingHint.TEXT_AS_SHAPES){
|
||||||
|
_layout.draw(graphics, (float)x, (float)yBaseline);
|
||||||
|
} else {
|
||||||
|
graphics.drawString(_str.getIterator(), (float)x, (float)yBaseline );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return full height of this text run which is sum of ascent, descent and leading
|
||||||
|
*/
|
||||||
|
public float getHeight(){
|
||||||
|
return _layout.getAscent() + _layout.getDescent() + _layout.getLeading();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return width if this text run
|
||||||
|
*/
|
||||||
|
public float getWidth(){
|
||||||
|
return _layout.getAdvance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the string to be painted
|
||||||
|
*/
|
||||||
|
public String getString(){
|
||||||
|
if(_str == null) return "";
|
||||||
|
|
||||||
|
AttributedCharacterIterator it = _str.getIterator();
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
for (char c = it.first(); c != it.DONE; c = it.next()) {
|
||||||
|
buf.append(c);
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return "[" + getClass().getSimpleName() + "] " + getString();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* ====================================================================
|
||||||
|
* 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.xslf.usermodel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages fonts when rendering slides.
|
||||||
|
*
|
||||||
|
* Use this class to handle unknown / missing fonts or to substitute fonts
|
||||||
|
*/
|
||||||
|
public interface XSLFFontManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* select a font to be used to paint text
|
||||||
|
*
|
||||||
|
* @param family the font family as defined in the .pptx file.
|
||||||
|
* This can be unknown or missing in the graphic environment.
|
||||||
|
*
|
||||||
|
* @return the font to be used to paint text
|
||||||
|
*/
|
||||||
|
|
||||||
|
String getRendererableFont(String typeface, int pitchFamily);
|
||||||
|
}
|
@ -283,8 +283,8 @@ public class XSLFGroupShape extends XSLFShape {
|
|||||||
double scaleY = exterior.getHeight() / interior.getHeight();
|
double scaleY = exterior.getHeight() / interior.getHeight();
|
||||||
|
|
||||||
// group transform scales shapes but not fonts
|
// group transform scales shapes but not fonts
|
||||||
Number prevFontScale = (Number)graphics.getRenderingHint(XSLFRenderingHint.FONT_SCALE);
|
Number prevFontScale = (Number)graphics.getRenderingHint(XSLFRenderingHint.GROUP_SCALE);
|
||||||
graphics.setRenderingHint(XSLFRenderingHint.FONT_SCALE, Math.abs(1/scaleY));
|
graphics.setRenderingHint(XSLFRenderingHint.GROUP_SCALE, Math.abs(1/scaleY));
|
||||||
|
|
||||||
graphics.scale(scaleX, scaleY);
|
graphics.scale(scaleX, scaleY);
|
||||||
graphics.translate(-interior.getX(), -interior.getY());
|
graphics.translate(-interior.getX(), -interior.getY());
|
||||||
@ -302,7 +302,7 @@ public class XSLFGroupShape extends XSLFShape {
|
|||||||
graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true);
|
graphics.setRenderingHint(XSLFRenderingHint.GRESTORE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics.setRenderingHint(XSLFRenderingHint.FONT_SCALE, prevFontScale);
|
graphics.setRenderingHint(XSLFRenderingHint.GROUP_SCALE, prevFontScale);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,12 +51,12 @@ public class XSLFRenderingHint extends RenderingHints.Key {
|
|||||||
/**
|
/**
|
||||||
* how to render text:
|
* how to render text:
|
||||||
*
|
*
|
||||||
* {@link #TEXT_MODE_CHARACTERS} (default) means to draw via
|
* {@link #TEXT_AS_CHARACTERS} (default) means to draw via
|
||||||
* {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}.
|
* {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}.
|
||||||
* This mode draws text as characters. Use it if the target graphics writes the actual
|
* This mode draws text as characters. Use it if the target graphics writes the actual
|
||||||
* character codes instead of glyph outlines (PDFGraphics2D, SVGGraphics2D, etc.)
|
* character codes instead of glyph outlines (PDFGraphics2D, SVGGraphics2D, etc.)
|
||||||
*
|
*
|
||||||
* {@link #TEXT_MODE_GLYPHS} means to render via
|
* {@link #TEXT_AS_SHAPES} means to render via
|
||||||
* {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}.
|
* {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}.
|
||||||
* This mode draws glyphs as shapes and provides some advanced capabilities such as
|
* This mode draws glyphs as shapes and provides some advanced capabilities such as
|
||||||
* justification and font substitution. Use it if the target graphics is an image.
|
* justification and font substitution. Use it if the target graphics is an image.
|
||||||
@ -67,13 +67,19 @@ public class XSLFRenderingHint extends RenderingHints.Key {
|
|||||||
/**
|
/**
|
||||||
* draw text via {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}
|
* draw text via {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}
|
||||||
*/
|
*/
|
||||||
public static final int TEXT_MODE_CHARACTERS = 1;
|
public static final int TEXT_AS_CHARACTERS = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* draw text via {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}
|
* draw text via {@link java.awt.font.TextLayout#draw(java.awt.Graphics2D, float, float)}
|
||||||
*/
|
*/
|
||||||
public static final int TEXT_MODE_GLYPHS = 2;
|
public static final int TEXT_AS_SHAPES = 2;
|
||||||
|
|
||||||
@Internal
|
@Internal
|
||||||
public static final XSLFRenderingHint FONT_SCALE = new XSLFRenderingHint(5);
|
static final XSLFRenderingHint GROUP_SCALE = new XSLFRenderingHint(5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this object to resolve unknown / missing fonts when rendering slides
|
||||||
|
*/
|
||||||
|
public static final XSLFRenderingHint FONT_HANDLER = new XSLFRenderingHint(6);
|
||||||
|
|
||||||
}
|
}
|
@ -719,7 +719,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||||||
|
|
||||||
if(spacing > 0) {
|
if(spacing > 0) {
|
||||||
// If linespacing >= 0, then linespacing is a percentage of normal line height.
|
// If linespacing >= 0, then linespacing is a percentage of normal line height.
|
||||||
penY += spacing*0.01* _maxLineHeight;
|
penY += spacing*0.01* line.getHeight();
|
||||||
} else {
|
} else {
|
||||||
// positive value means absolute spacing in points
|
// positive value means absolute spacing in points
|
||||||
penY += -spacing;
|
penY += -spacing;
|
||||||
@ -731,41 +731,14 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||||||
return penY - y;
|
return penY - y;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TextFragment {
|
|
||||||
private TextLayout _layout;
|
|
||||||
private AttributedString _str;
|
|
||||||
|
|
||||||
TextFragment(TextLayout layout, AttributedString str){
|
|
||||||
_layout = layout;
|
|
||||||
_str = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(Graphics2D graphics, double x, double y){
|
|
||||||
double yBaseline = y + _layout.getAscent();
|
|
||||||
|
|
||||||
Integer textMode = (Integer)graphics.getRenderingHint(XSLFRenderingHint.TEXT_RENDERING_MODE);
|
|
||||||
if(textMode != null && textMode == XSLFRenderingHint.TEXT_MODE_GLYPHS){
|
|
||||||
_layout.draw(graphics, (float)x, (float)yBaseline);
|
|
||||||
} else {
|
|
||||||
graphics.drawString(_str.getIterator(), (float)x, (float)yBaseline );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getHeight(){
|
|
||||||
return _layout.getAscent() + _layout.getDescent() + _layout.getLeading();
|
|
||||||
}
|
|
||||||
public float getWidth(){
|
|
||||||
return _layout.getAdvance();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
AttributedString getAttributedString(Graphics2D graphics){
|
AttributedString getAttributedString(Graphics2D graphics){
|
||||||
|
|
||||||
String text = getRenderableText();
|
String text = getRenderableText();
|
||||||
|
|
||||||
AttributedString string = new AttributedString(text);
|
AttributedString string = new AttributedString(text);
|
||||||
|
|
||||||
|
XSLFFontManager fontHandler = (XSLFFontManager)graphics.getRenderingHint(XSLFRenderingHint.FONT_HANDLER);
|
||||||
|
|
||||||
int startIndex = 0;
|
int startIndex = 0;
|
||||||
for (XSLFTextRun run : _runs){
|
for (XSLFTextRun run : _runs){
|
||||||
int length = run.getRenderableText().length();
|
int length = run.getRenderableText().length();
|
||||||
@ -777,11 +750,15 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||||||
|
|
||||||
string.addAttribute(TextAttribute.FOREGROUND, run.getFontColor(), startIndex, endIndex);
|
string.addAttribute(TextAttribute.FOREGROUND, run.getFontColor(), startIndex, endIndex);
|
||||||
|
|
||||||
// user can pass an object to convert fonts via a rendering hint
|
// user can pass an custom object to convert fonts
|
||||||
string.addAttribute(TextAttribute.FAMILY, run.getFontFamily(), startIndex, endIndex);
|
String fontFamily = run.getFontFamily();
|
||||||
|
if(fontHandler != null) {
|
||||||
|
fontFamily = fontHandler.getRendererableFont(fontFamily, run.getPitchAndFamily());
|
||||||
|
}
|
||||||
|
string.addAttribute(TextAttribute.FAMILY, fontFamily, startIndex, endIndex);
|
||||||
|
|
||||||
float fontSz = (float)run.getFontSize();
|
float fontSz = (float)run.getFontSize();
|
||||||
Number fontScale = (Number)graphics.getRenderingHint(XSLFRenderingHint.FONT_SCALE);
|
Number fontScale = (Number)graphics.getRenderingHint(XSLFRenderingHint.GROUP_SCALE);
|
||||||
if(fontScale != null) fontSz *= fontScale.floatValue();
|
if(fontScale != null) fontSz *= fontScale.floatValue();
|
||||||
|
|
||||||
string.addAttribute(TextAttribute.SIZE, fontSz , startIndex, endIndex);
|
string.addAttribute(TextAttribute.SIZE, fontSz , startIndex, endIndex);
|
||||||
@ -813,7 +790,8 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ensure that the paragraph contains at least one character
|
* ensure that the paragraph contains at least one character.
|
||||||
|
* We need this trick to correctly measure text
|
||||||
*/
|
*/
|
||||||
private void ensureNotEmpty(){
|
private void ensureNotEmpty(){
|
||||||
XSLFTextRun r = addNewTextRun();
|
XSLFTextRun r = addNewTextRun();
|
||||||
@ -824,7 +802,14 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void breakText(Graphics2D graphics){
|
/**
|
||||||
|
* break text into lines
|
||||||
|
*
|
||||||
|
* @param graphics
|
||||||
|
* @return array of text fragments,
|
||||||
|
* each representing a line of text that fits in the wrapping width
|
||||||
|
*/
|
||||||
|
List<TextFragment> breakText(Graphics2D graphics){
|
||||||
_lines = new ArrayList<TextFragment>();
|
_lines = new ArrayList<TextFragment>();
|
||||||
|
|
||||||
// does this paragraph contain text?
|
// does this paragraph contain text?
|
||||||
@ -834,15 +819,16 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||||||
if(_runs.size() == 0) ensureNotEmpty();
|
if(_runs.size() == 0) ensureNotEmpty();
|
||||||
|
|
||||||
String text = getRenderableText();
|
String text = getRenderableText();
|
||||||
if(text.length() == 0) return;
|
if(text.length() == 0) return _lines;
|
||||||
|
|
||||||
AttributedString at = getAttributedString(graphics);
|
AttributedString at = getAttributedString(graphics);
|
||||||
AttributedCharacterIterator it = at.getIterator();
|
AttributedCharacterIterator it = at.getIterator();
|
||||||
LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());
|
LineBreakMeasurer measurer = new LineBreakMeasurer(it, graphics.getFontRenderContext());
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int startIndex = measurer.getPosition();
|
int startIndex = measurer.getPosition();
|
||||||
|
|
||||||
double wrappingWidth = getWrappingWidth(_lines.size() == 0) + 1; // add a pixel to compensate rounding errors
|
double wrappingWidth = getWrappingWidth(_lines.size() == 0) + 1; // add a pixel to compensate rounding errors
|
||||||
// shape width can be smaller that the sum of insets (proved by a test file)
|
// shape width can be smaller that the sum of insets (this was proved by a test file)
|
||||||
if(wrappingWidth < 0) wrappingWidth = 1;
|
if(wrappingWidth < 0) wrappingWidth = 1;
|
||||||
|
|
||||||
int nextBreak = text.indexOf('\n', startIndex + 1);
|
int nextBreak = text.indexOf('\n', startIndex + 1);
|
||||||
@ -862,13 +848,21 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||||||
layout = layout.getJustifiedLayout((float)wrappingWidth);
|
layout = layout.getJustifiedLayout((float)wrappingWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip over new line breaks (we paint 'clear' text runs not starting or ending with \n)
|
||||||
|
if(endIndex < it.getEndIndex() && text.charAt(endIndex) == '\n'){
|
||||||
|
measurer.setPosition(endIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
AttributedString str = new AttributedString(it, startIndex, endIndex);
|
AttributedString str = new AttributedString(it, startIndex, endIndex);
|
||||||
TextFragment line = new TextFragment(layout, str);
|
TextFragment line = new TextFragment(
|
||||||
|
layout, // we will not paint empty paragraphs
|
||||||
|
emptyParagraph ? null : str);
|
||||||
_lines.add(line);
|
_lines.add(line);
|
||||||
|
|
||||||
_maxLineHeight = Math.max(_maxLineHeight, line.getHeight());
|
_maxLineHeight = Math.max(_maxLineHeight, line.getHeight());
|
||||||
|
|
||||||
if(endIndex == it.getEndIndex()) break;
|
if(endIndex == it.getEndIndex()) break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isBullet() && !emptyParagraph) {
|
if(isBullet() && !emptyParagraph) {
|
||||||
@ -897,7 +891,7 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
|
|||||||
_bullet = new TextFragment(layout, str);
|
_bullet = new TextFragment(layout, str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return _lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
CTTextParagraphProperties getDefaultStyle(){
|
CTTextParagraphProperties getDefaultStyle(){
|
||||||
|
@ -63,15 +63,15 @@ public class XSLFTextRun {
|
|||||||
|
|
||||||
String getRenderableText(){
|
String getRenderableText(){
|
||||||
String txt = _r.getT();
|
String txt = _r.getT();
|
||||||
|
TextCap cap = getTextCap();
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
for(int i = 0; i < txt.length(); i++) {
|
for(int i = 0; i < txt.length(); i++) {
|
||||||
char c = txt.charAt(i);
|
char c = txt.charAt(i);
|
||||||
if(c == '\t') {
|
if(c == '\t') {
|
||||||
// replace tab with the effective number of white spaces
|
// TODO: finish support for tabs
|
||||||
buf.append(" ");
|
buf.append(" ");
|
||||||
} else {
|
} else {
|
||||||
switch (getTextCap()){
|
switch (cap){
|
||||||
case ALL:
|
case ALL:
|
||||||
buf.append(Character.toUpperCase(c));
|
buf.append(Character.toUpperCase(c));
|
||||||
break;
|
break;
|
||||||
@ -268,6 +268,24 @@ public class XSLFTextRun {
|
|||||||
return visitor.getValue();
|
return visitor.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte getPitchAndFamily(){
|
||||||
|
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
|
||||||
|
|
||||||
|
CharacterPropertyFetcher<Byte> visitor = new CharacterPropertyFetcher<Byte>(_p.getLevel()){
|
||||||
|
public boolean fetch(CTTextCharacterProperties props){
|
||||||
|
CTTextFont font = props.getLatin();
|
||||||
|
if(font != null){
|
||||||
|
setValue(font.getPitchFamily());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchCharacterProperty(visitor);
|
||||||
|
|
||||||
|
return visitor.getValue() == null ? 0 : visitor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether a run of text will be formatted as strikethrough text.
|
* Specifies whether a run of text will be formatted as strikethrough text.
|
||||||
*
|
*
|
||||||
|
@ -493,7 +493,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements Iterable<
|
|||||||
double y0 = y;
|
double y0 = y;
|
||||||
for(int i = 0; i < _paragraphs.size(); i++){
|
for(int i = 0; i < _paragraphs.size(); i++){
|
||||||
XSLFTextParagraph p = _paragraphs.get(i);
|
XSLFTextParagraph p = _paragraphs.get(i);
|
||||||
List<XSLFTextParagraph.TextFragment> lines = p.getTextLines();
|
List<TextFragment> lines = p.getTextLines();
|
||||||
|
|
||||||
if(i > 0 && lines.size() > 0) {
|
if(i > 0 && lines.size() > 0) {
|
||||||
// the amount of vertical white space before the paragraph
|
// the amount of vertical white space before the paragraph
|
||||||
|
@ -2,9 +2,10 @@ package org.apache.poi.xslf.usermodel;
|
|||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.*;
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by IntelliJ IDEA.
|
* Created by IntelliJ IDEA.
|
||||||
@ -98,4 +99,74 @@ public class TestXSLFTextParagraph extends TestCase {
|
|||||||
assertEquals(244.0, expectedWidth); // 300 - 10 - 10 - 36
|
assertEquals(244.0, expectedWidth); // 300 - 10 - 10 - 36
|
||||||
assertEquals(expectedWidth, p.getWrappingWidth(false));
|
assertEquals(expectedWidth, p.getWrappingWidth(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testBreakLines(){
|
||||||
|
XMLSlideShow ppt = new XMLSlideShow();
|
||||||
|
XSLFSlide slide = ppt.createSlide();
|
||||||
|
XSLFTextShape sh = slide.createAutoShape();
|
||||||
|
|
||||||
|
XSLFTextParagraph p = sh.addNewTextParagraph();
|
||||||
|
XSLFTextRun r = p.addNewTextRun();
|
||||||
|
r.setFontFamily("serif"); // this should always be available
|
||||||
|
r.setFontSize(12);
|
||||||
|
r.setText(
|
||||||
|
"Paragraph formatting allows for more granular control " +
|
||||||
|
"of text within a shape. Properties here apply to all text " +
|
||||||
|
"residing within the corresponding paragraph.");
|
||||||
|
|
||||||
|
sh.setAnchor(new Rectangle(50, 50, 300, 200));
|
||||||
|
|
||||||
|
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
|
||||||
|
Graphics2D graphics = img.createGraphics();
|
||||||
|
|
||||||
|
List<TextFragment> lines;
|
||||||
|
lines = p.breakText(graphics);
|
||||||
|
assertEquals(3, lines.size());
|
||||||
|
|
||||||
|
// descrease the shape width from 300 pt to 100 pt
|
||||||
|
sh.setAnchor(new Rectangle(50, 50, 100, 200));
|
||||||
|
lines = p.breakText(graphics);
|
||||||
|
assertEquals(10, lines.size());
|
||||||
|
|
||||||
|
// descrease the shape width from 300 pt to 100 pt
|
||||||
|
sh.setAnchor(new Rectangle(50, 50, 600, 200));
|
||||||
|
lines = p.breakText(graphics);
|
||||||
|
assertEquals(2, lines.size());
|
||||||
|
|
||||||
|
// set left and right margins to 200pt. This leaves 200pt for wrapping text
|
||||||
|
sh.setLeftInset(200);
|
||||||
|
sh.setRightInset(200);
|
||||||
|
lines = p.breakText(graphics);
|
||||||
|
assertEquals(4, lines.size());
|
||||||
|
|
||||||
|
r.setText("Apache POI");
|
||||||
|
lines = p.breakText(graphics);
|
||||||
|
assertEquals(1, lines.size());
|
||||||
|
assertEquals("Apache POI", lines.get(0).getString());
|
||||||
|
|
||||||
|
r.setText("Apache\nPOI");
|
||||||
|
lines = p.breakText(graphics);
|
||||||
|
assertEquals(2, lines.size());
|
||||||
|
assertEquals("Apache", lines.get(0).getString());
|
||||||
|
assertEquals("POI", lines.get(1).getString());
|
||||||
|
|
||||||
|
XSLFAutoShape sh2 = slide.createAutoShape();
|
||||||
|
sh2.setAnchor(new Rectangle(50, 50, 300, 200));
|
||||||
|
XSLFTextParagraph p2 = sh2.addNewTextParagraph();
|
||||||
|
XSLFTextRun r2 = p2.addNewTextRun();
|
||||||
|
r2.setFontFamily("serif"); // this should always be available
|
||||||
|
r2.setFontSize(30);
|
||||||
|
r2.setText("Apache\n");
|
||||||
|
XSLFTextRun r3 = p2.addNewTextRun();
|
||||||
|
r3.setFontFamily("serif"); // this should always be available
|
||||||
|
r3.setFontSize(10);
|
||||||
|
r3.setText("POI");
|
||||||
|
lines = p2.breakText(graphics);
|
||||||
|
assertEquals(2, lines.size());
|
||||||
|
assertEquals("Apache", lines.get(0).getString());
|
||||||
|
assertEquals("POI", lines.get(1).getString());
|
||||||
|
// the first line is at least two times higher than the second
|
||||||
|
assertTrue(lines.get(0).getHeight() > lines.get(1).getHeight()*2);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user