#61169 - Text with Japanese characters overflows textbox

- add resize methods with Graphics argument

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1801329 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2017-07-08 22:20:55 +00:00
parent cfc7aa4315
commit 377615e9cd
10 changed files with 346 additions and 77 deletions

View File

@ -207,7 +207,7 @@ public class DrawTextShape extends DrawSimpleShape {
* @param oldGraphics the graphics context, which properties are to be copied, may be null * @param oldGraphics the graphics context, which properties are to be copied, may be null
* @return the height in points * @return the height in points
*/ */
protected double getTextHeight(Graphics2D oldGraphics) { public double getTextHeight(Graphics2D oldGraphics) {
// dry-run in a 1x1 image and return the vertical advance // dry-run in a 1x1 image and return the vertical advance
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics = img.createGraphics(); Graphics2D graphics = img.createGraphics();

View File

@ -17,6 +17,8 @@
package org.apache.poi.sl.usermodel; package org.apache.poi.sl.usermodel;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.List; import java.util.List;
public interface TextShape< public interface TextShape<
@ -173,8 +175,21 @@ public interface TextShape<
/** /**
* Compute the cumulative height occupied by the text * Compute the cumulative height occupied by the text
*
* @return the cumulative height occupied by the text
*/ */
double getTextHeight(); double getTextHeight();
/**
* Compute the cumulative height occupied by the text
*
* @param graphics a customized graphics context, e.g. which contains font mappings
*
* @return the cumulative height occupied by the text
*
* @since POI 3.17-beta2
*/
double getTextHeight(Graphics2D graphics);
/** /**
* Returns the type of vertical alignment for the text. * Returns the type of vertical alignment for the text.
@ -255,4 +270,25 @@ public interface TextShape<
* @return the text placeholder * @return the text placeholder
*/ */
TextPlaceholder getTextPlaceholder(); TextPlaceholder getTextPlaceholder();
/**
* Adjust the size of the shape so it encompasses the text inside it.
*
* @return a {@code Rectangle2D} that is the bounds of this shape.
*
* @since POI 3.17-beta2
*/
Rectangle2D resizeToFitText();
/**
* Adjust the size of the shape so it encompasses the text inside it.
*
* @param graphics a customized graphics context, e.g. which contains font mappings
*
* @return a {@code Rectangle2D} that is the bounds of this shape.
*
* @since POI 3.17-beta2
*/
Rectangle2D resizeToFitText(Graphics2D graphics);
} }

View File

@ -64,6 +64,7 @@ public class XSLFTextRun implements TextRun {
return _p; return _p;
} }
@Override
public String getRawText(){ public String getRawText(){
if (_r instanceof CTTextField) { if (_r instanceof CTTextField) {
return ((CTTextField)_r).getT(); return ((CTTextField)_r).getT();
@ -111,6 +112,7 @@ public class XSLFTextRun implements TextRun {
return buf.toString(); return buf.toString();
} }
@Override
public void setText(String text){ public void setText(String text){
if (_r instanceof CTTextField) { if (_r instanceof CTTextField) {
((CTTextField)_r).setT(text); ((CTTextField)_r).setT(text);
@ -157,6 +159,7 @@ public class XSLFTextRun implements TextRun {
public PaintStyle getFontColor(){ public PaintStyle getFontColor(){
final boolean hasPlaceholder = getParentParagraph().getParentShape().getPlaceholder() != null; final boolean hasPlaceholder = getParentParagraph().getParentShape().getPlaceholder() != null;
CharacterPropertyFetcher<PaintStyle> fetcher = new CharacterPropertyFetcher<PaintStyle>(_p.getIndentLevel()){ CharacterPropertyFetcher<PaintStyle> fetcher = new CharacterPropertyFetcher<PaintStyle>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props == null) { if (props == null) {
return false; return false;
@ -191,7 +194,9 @@ public class XSLFTextRun implements TextRun {
public void setFontSize(Double fontSize){ public void setFontSize(Double fontSize){
CTTextCharacterProperties rPr = getRPr(true); CTTextCharacterProperties rPr = getRPr(true);
if(fontSize == null) { if(fontSize == null) {
if (rPr.isSetSz()) rPr.unsetSz(); if (rPr.isSetSz()) {
rPr.unsetSz();
}
} else { } else {
if (fontSize < 1.0) { if (fontSize < 1.0) {
throw new IllegalArgumentException("Minimum font size is 1pt but was " + fontSize); throw new IllegalArgumentException("Minimum font size is 1pt but was " + fontSize);
@ -205,9 +210,12 @@ public class XSLFTextRun implements TextRun {
public Double getFontSize(){ public Double getFontSize(){
double scale = 1; double scale = 1;
CTTextNormalAutofit afit = getParentParagraph().getParentShape().getTextBodyPr().getNormAutofit(); CTTextNormalAutofit afit = getParentParagraph().getParentShape().getTextBodyPr().getNormAutofit();
if(afit != null) scale = (double)afit.getFontScale() / 100000; if(afit != null) {
scale = (double)afit.getFontScale() / 100000;
}
CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getIndentLevel()){ CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null && props.isSetSz()) { if (props != null && props.isSetSz()) {
setValue(props.getSz()*0.01); setValue(props.getSz()*0.01);
@ -228,6 +236,7 @@ public class XSLFTextRun implements TextRun {
public double getCharacterSpacing(){ public double getCharacterSpacing(){
CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getIndentLevel()){ CharacterPropertyFetcher<Double> fetcher = new CharacterPropertyFetcher<Double>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null && props.isSetSpc()) { if (props != null && props.isSetSpc()) {
setValue(props.getSpc()*0.01); setValue(props.getSpc()*0.01);
@ -252,7 +261,9 @@ public class XSLFTextRun implements TextRun {
public void setCharacterSpacing(double spc){ public void setCharacterSpacing(double spc){
CTTextCharacterProperties rPr = getRPr(true); CTTextCharacterProperties rPr = getRPr(true);
if(spc == 0.0) { if(spc == 0.0) {
if(rPr.isSetSpc()) rPr.unsetSpc(); if(rPr.isSetSpc()) {
rPr.unsetSpc();
}
} else { } else {
rPr.setSpc((int)(100*spc)); rPr.setSpc((int)(100*spc));
} }
@ -267,9 +278,15 @@ public class XSLFTextRun implements TextRun {
CTTextCharacterProperties rPr = getRPr(true); CTTextCharacterProperties rPr = getRPr(true);
if(typeface == null){ if(typeface == null){
if(rPr.isSetLatin()) rPr.unsetLatin(); if(rPr.isSetLatin()) {
if(rPr.isSetCs()) rPr.unsetCs(); rPr.unsetLatin();
if(rPr.isSetSym()) rPr.unsetSym(); }
if(rPr.isSetCs()) {
rPr.unsetCs();
}
if(rPr.isSetSym()) {
rPr.unsetSym();
}
} else { } else {
if(isSymbol){ if(isSymbol){
CTTextFont font = rPr.isSetSym() ? rPr.getSym() : rPr.addNewSym(); CTTextFont font = rPr.isSetSym() ? rPr.getSym() : rPr.addNewSym();
@ -277,8 +294,12 @@ public class XSLFTextRun implements TextRun {
} else { } else {
CTTextFont latin = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin(); CTTextFont latin = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin();
latin.setTypeface(typeface); latin.setTypeface(typeface);
if(charset != -1) latin.setCharset(charset); if(charset != -1) {
if(pictAndFamily != -1) latin.setPitchFamily(pictAndFamily); latin.setCharset(charset);
}
if(pictAndFamily != -1) {
latin.setPitchFamily(pictAndFamily);
}
} }
} }
} }
@ -288,6 +309,7 @@ public class XSLFTextRun implements TextRun {
final XSLFTheme theme = _p.getParentShape().getSheet().getTheme(); final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
CharacterPropertyFetcher<String> visitor = new CharacterPropertyFetcher<String>(_p.getIndentLevel()){ CharacterPropertyFetcher<String> visitor = new CharacterPropertyFetcher<String>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null) { if (props != null) {
CTTextFont font = props.getLatin(); CTTextFont font = props.getLatin();
@ -310,10 +332,12 @@ public class XSLFTextRun implements TextRun {
return visitor.getValue(); return visitor.getValue();
} }
@Override
public byte getPitchAndFamily(){ public byte getPitchAndFamily(){
// final XSLFTheme theme = _p.getParentShape().getSheet().getTheme(); // final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();
CharacterPropertyFetcher<Byte> visitor = new CharacterPropertyFetcher<Byte>(_p.getIndentLevel()){ CharacterPropertyFetcher<Byte> visitor = new CharacterPropertyFetcher<Byte>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null) { if (props != null) {
CTTextFont font = props.getLatin(); CTTextFont font = props.getLatin();
@ -338,6 +362,7 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public boolean isStrikethrough() { public boolean isStrikethrough() {
CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if(props != null && props.isSetStrike()) { if(props != null && props.isSetStrike()) {
setValue(props.getStrike() != STTextStrikeType.NO_STRIKE); setValue(props.getStrike() != STTextStrikeType.NO_STRIKE);
@ -353,6 +378,7 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public boolean isSuperscript() { public boolean isSuperscript() {
CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null && props.isSetBaseline()) { if (props != null && props.isSetBaseline()) {
setValue(props.getBaseline() > 0); setValue(props.getBaseline() > 0);
@ -401,6 +427,7 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public boolean isSubscript() { public boolean isSubscript() {
CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null && props.isSetBaseline()) { if (props != null && props.isSetBaseline()) {
setValue(props.getBaseline() < 0); setValue(props.getBaseline() < 0);
@ -416,8 +443,10 @@ public class XSLFTextRun implements TextRun {
/** /**
* @return whether a run of text will be formatted as a superscript text. Default is false. * @return whether a run of text will be formatted as a superscript text. Default is false.
*/ */
@Override
public TextCap getTextCap() { public TextCap getTextCap() {
CharacterPropertyFetcher<TextCap> fetcher = new CharacterPropertyFetcher<TextCap>(_p.getIndentLevel()){ CharacterPropertyFetcher<TextCap> fetcher = new CharacterPropertyFetcher<TextCap>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null && props.isSetCap()) { if (props != null && props.isSetCap()) {
int idx = props.getCap().intValue() - 1; int idx = props.getCap().intValue() - 1;
@ -439,6 +468,7 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public boolean isBold(){ public boolean isBold(){
CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null && props.isSetB()) { if (props != null && props.isSetB()) {
setValue(props.getB()); setValue(props.getB());
@ -459,6 +489,7 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public boolean isItalic(){ public boolean isItalic(){
CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null && props.isSetI()) { if (props != null && props.isSetI()) {
setValue(props.getI()); setValue(props.getI());
@ -479,6 +510,7 @@ public class XSLFTextRun implements TextRun {
@Override @Override
public boolean isUnderlined(){ public boolean isUnderlined(){
CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){ CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){
@Override
public boolean fetch(CTTextCharacterProperties props){ public boolean fetch(CTTextCharacterProperties props){
if (props != null && props.isSetU()) { if (props != null && props.isSetU()) {
setValue(props.getU() != STTextUnderlineType.NONE); setValue(props.getU() != STTextUnderlineType.NONE);
@ -603,16 +635,24 @@ public class XSLFTextRun implements TextRun {
} }
boolean bold = r.isBold(); boolean bold = r.isBold();
if(bold != isBold()) setBold(bold); if(bold != isBold()) {
setBold(bold);
}
boolean italic = r.isItalic(); boolean italic = r.isItalic();
if(italic != isItalic()) setItalic(italic); if(italic != isItalic()) {
setItalic(italic);
}
boolean underline = r.isUnderlined(); boolean underline = r.isUnderlined();
if(underline != isUnderlined()) setUnderlined(underline); if(underline != isUnderlined()) {
setUnderlined(underline);
}
boolean strike = r.isStrikethrough(); boolean strike = r.isStrikethrough();
if(strike != isStrikethrough()) setStrikethrough(strike); if(strike != isStrikethrough()) {
setStrikethrough(strike);
}
} }

View File

@ -19,6 +19,7 @@
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
@ -601,23 +602,29 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
@Override @Override
public double getTextHeight(){ public double getTextHeight(){
DrawFactory drawFact = DrawFactory.getInstance(null); return getTextHeight(null);
}
@Override
public double getTextHeight(Graphics2D graphics){
DrawFactory drawFact = DrawFactory.getInstance(graphics);
DrawTextShape dts = drawFact.getDrawable(this); DrawTextShape dts = drawFact.getDrawable(this);
return dts.getTextHeight(); return dts.getTextHeight(graphics);
} }
/** @Override
* Adjust the size of the shape so it encompasses the text inside it.
*
* @return a <code>Rectangle2D</code> that is the bounds of this shape.
*/
public Rectangle2D resizeToFitText(){ public Rectangle2D resizeToFitText(){
return resizeToFitText(null);
}
@Override
public Rectangle2D resizeToFitText(Graphics2D graphics) {
Rectangle2D anchor = getAnchor(); Rectangle2D anchor = getAnchor();
if(anchor.getWidth() == 0.) { if(anchor.getWidth() == 0.) {
throw new POIXMLException("Anchor of the shape was not set."); throw new POIXMLException("Anchor of the shape was not set.");
} }
double height = getTextHeight(); double height = getTextHeight(graphics);
height += 1; // add a pixel to compensate rounding errors height += 1; // add a pixel to compensate rounding errors
Insets2D insets = getInsets(); Insets2D insets = getInsets();

View File

@ -0,0 +1,59 @@
/*
* ====================================================================
* 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.IOException;
import java.io.InputStream;
import org.apache.poi.POIDataSamples;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory;
public class SLCommonUtils {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
/** a generic way to open a sample slideshow document **/
public static SlideShow<?,?> openSampleSlideshow(String sampleName) throws IOException {
InputStream is = _slTests.openResourceAsStream(sampleName);
try {
return SlideShowFactory.create(is);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
is.close();
}
}
/**
* Tests, if the scratchpad classes are on the classpath
*
* @return true, if only xslf is on the classpath, and false, if both classpaths
* (XSLF and HSLF) can be used/referenced
*/
public static boolean xslfOnly() {
try {
Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
return false;
} catch (Exception e) {
return true;
}
}
}

View File

@ -0,0 +1,158 @@
/* ====================================================================
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 static org.apache.poi.sl.SLCommonUtils.xslfOnly;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeFalse;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.sl.draw.DrawFactory;
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.sl.usermodel.StrokeStyle.LineDash;
import org.apache.poi.sl.usermodel.TextBox;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFTextRun;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
/**
* Test rendering - specific to font handling
*/
public class TestFonts {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
private static final String JPTEXT =
"\u3061\u3087\u3063\u3068\u65E9\u3044\u3051\u3069T\u30B7\u30E3\u30C4\u304C\u7740\u305F\u304F\u306A" +
"\u308B\u5B63\u7BC0\u2661\u304A\u6BCD\u3055\u3093\u306E\u5F71\u97FF\u304B\u3001\u975E\u5E38\u306B" +
"\u6050\u7ADC\u304C\u5927\u597D\u304D\u3067\u3059\u3002\u3082\u3046\u98FC\u3044\u305F\u3044\u304F" +
"\u3089\u3044\u5927\u597D\u304D\u3067\u3059\u3002#\u30B8\u30E5\u30E9\u30B7\u30C3\u30AF\u30EF\u30FC" +
"\u30EB\u30C9 \u306E\u30E9\u30D7\u30C8\u30EB4\u59C9\u59B9\u3068\u304B\u6FC0\u7684\u306B\u53EF\u611B" +
"\u304F\u3066\u53EF\u611B\u304F\u3066\u53EF\u611B\u304F\u3066\u53EF\u611B\u3044\u3067\u3059\u3002" +
"\u3081\u308D\u3081\u308D\u3001\u5927\u597D\u304D\u2661\u304A\u6BCD\u3055\u3093\u3082\u6050\u7ADC" +
"\u304C\u597D\u304D\u3067\u3001\u5C0F\u3055\u3044\u9803\u3001\u53E4\u4EE3\u751F\u7269\u306E\u56F3" +
"\u9451\u3092\u4E00\u7DD2\u306B\u898B\u3066\u305F\u306E\u601D\u3044\u51FA\u3059\u301C\u3068\u3044";
private static final String INIT_FONTS[] = { "mona.ttf" };
@BeforeClass
public static void initGE() throws FontFormatException, IOException {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
for (String s : INIT_FONTS) {
Font font = Font.createFont(Font.TRUETYPE_FONT, _slTests.getFile(s));
ge.registerFont(font);
}
}
@Test
public void resizeToFitTextHSLF() throws IOException {
assumeFalse(xslfOnly());
SlideShow<?,?> ppt = new HSLFSlideShow();
TextBox<?,?> tb = resizeToFitText(ppt);
Rectangle2D anc = tb.getAnchor();
// ignore font metrics differences on windows / linux (... hopefully ...)
assertEquals(anc.getHeight(), 312d, 5);
// setFont(tb, "Mona");
// FileOutputStream fos = new FileOutputStream("bla-hslf.ppt");
// ppt.write(fos);
// fos.close();
ppt.close();
}
@Test
public void resizeToFitTextXSLF() throws IOException {
SlideShow<?,?> ppt = new XMLSlideShow();
TextBox<?,?> tb = resizeToFitText(ppt);
Rectangle2D anc = tb.getAnchor();
// ignore font metrics differences on windows / linux (... hopefully ...)
assertEquals(anc.getHeight(), 312d, 5);
// setFont(tb, "Mona");
// FileOutputStream fos = new FileOutputStream("bla-xslf.ppt");
// ppt.write(fos);
// fos.close();
ppt.close();
}
private TextBox<?,?> resizeToFitText(SlideShow<?,?> slideshow) throws IOException {
Slide<?,?> sld = slideshow.createSlide();
TextBox<?,?> tb = sld.createTextBox();
tb.setAnchor(new Rectangle(50, 50, 200, 50));
tb.setStrokeStyle(Color.black, LineDash.SOLID, 3);
tb.setText(JPTEXT);
setFont(tb, "NoSuchFont");
Dimension pgsize = slideshow.getPageSize();
int width = (int)pgsize.getWidth();
int height = (int)pgsize.getHeight();
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = img.createGraphics();
Map<String,String> fallbackMap = new HashMap<String,String>();
fallbackMap.put("NoSuchFont", "Mona");
graphics.setRenderingHint(Drawable.FONT_FALLBACK, fallbackMap);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
DrawFactory.getInstance(graphics).fixFonts(graphics);
tb.resizeToFitText(graphics);
graphics.dispose();
return tb;
}
private void setFont(TextBox<?,?> tb, String fontFamily) {
// TODO: set east asian font family - MS Office uses "MS Mincho" or "MS Gothic" as a fallback
// see https://stackoverflow.com/questions/26063828 for good explanation about the font metrics
// differences on different environments
for (TextParagraph<?,?,? extends TextRun> p : tb.getTextParagraphs()) {
for (TextRun r : p.getTextRuns()) {
r.setFontFamily(fontFamily);
if (r instanceof XSLFTextRun) {
// TODO: provide API for HSLF
XSLFTextRun xr = (XSLFTextRun)r;
CTRegularTextRun tr = (CTRegularTextRun)xr.getXmlObject();
tr.getRPr().addNewEa().setTypeface(fontFamily);
}
}
}
}
}

View File

@ -19,7 +19,8 @@
package org.apache.poi.sl; package org.apache.poi.sl;
import static org.apache.poi.sl.TestTable.openSampleSlideshow; import static org.apache.poi.sl.SLCommonUtils.openSampleSlideshow;
import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
@ -37,25 +38,12 @@ import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow; import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.TextParagraph; import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.sl.usermodel.TextShape; import org.apache.poi.sl.usermodel.TextShape;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
public class TestHeadersFooters { public class TestHeadersFooters {
private static boolean xslfOnly = false;
@BeforeClass
public static void checkHslf() {
try {
Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
} catch (Exception e) {
xslfOnly = true;
}
}
@Test @Test
public void bug58144a() throws IOException { public void bug58144a() throws IOException {
assumeFalse(xslfOnly); assumeFalse(xslfOnly());
SlideShow<?,?> ppt = openSampleSlideshow("bug58144-headers-footers-2003.ppt"); SlideShow<?,?> ppt = openSampleSlideshow("bug58144-headers-footers-2003.ppt");
HSLFSlide sl = (HSLFSlide)ppt.getSlides().get(0); HSLFSlide sl = (HSLFSlide)ppt.getSlides().get(0);
HeadersFooters hfs = sl.getHeadersFooters(); HeadersFooters hfs = sl.getHeadersFooters();
@ -69,7 +57,7 @@ public class TestHeadersFooters {
@Test @Test
public void bug58144b() throws IOException { public void bug58144b() throws IOException {
assumeFalse(xslfOnly); assumeFalse(xslfOnly());
SlideShow<?,?> ppt = openSampleSlideshow("bug58144-headers-footers-2007.ppt"); SlideShow<?,?> ppt = openSampleSlideshow("bug58144-headers-footers-2007.ppt");
Slide<?,?> sl = ppt.getSlides().get(0); Slide<?,?> sl = ppt.getSlides().get(0);
HeadersFooters hfs2 = ((HSLFSlide)sl).getHeadersFooters(); HeadersFooters hfs2 = ((HSLFSlide)sl).getHeadersFooters();

View File

@ -19,6 +19,8 @@
package org.apache.poi.sl; package org.apache.poi.sl;
import static org.apache.poi.sl.SLCommonUtils.openSampleSlideshow;
import static org.apache.poi.sl.SLCommonUtils.xslfOnly;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@ -32,7 +34,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.sl.usermodel.Slide; import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow; import org.apache.poi.sl.usermodel.SlideShow;
@ -41,38 +42,13 @@ import org.apache.poi.sl.usermodel.TableCell;
import org.apache.poi.sl.usermodel.TableShape; import org.apache.poi.sl.usermodel.TableShape;
import org.apache.poi.sl.usermodel.TextShape.TextDirection; import org.apache.poi.sl.usermodel.TextShape.TextDirection;
import org.apache.poi.xslf.usermodel.XMLSlideShow; import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
public class TestTable { public class TestTable {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
private static boolean xslfOnly = false;
@BeforeClass
public static void checkHslf() {
try {
Class.forName("org.apache.poi.hslf.usermodel.HSLFSlideShow");
} catch (Exception e) {
xslfOnly = true;
}
}
/** a generic way to open a sample slideshow document **/
public static SlideShow<?,?> openSampleSlideshow(String sampleName) throws IOException {
InputStream is = _slTests.openResourceAsStream(sampleName);
try {
return SlideShowFactory.create(is);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
is.close();
}
}
@Test @Test
public void colWidthRowHeight() throws IOException { public void colWidthRowHeight() throws IOException {
assumeFalse(xslfOnly); assumeFalse(xslfOnly());
// Test of table dimensions of same slideshow saved as ppt/x // Test of table dimensions of same slideshow saved as ppt/x
// to check if both return similar (points) value // to check if both return similar (points) value
@ -121,7 +97,7 @@ public class TestTable {
@Test @Test
public void directionHSLF() throws IOException { public void directionHSLF() throws IOException {
assumeFalse(xslfOnly); assumeFalse(xslfOnly());
SlideShow<?,?> ppt1 = new HSLFSlideShow(); SlideShow<?,?> ppt1 = new HSLFSlideShow();
testTextDirection(ppt1); testTextDirection(ppt1);
ppt1.close(); ppt1.close();
@ -173,7 +149,7 @@ public class TestTable {
@Test @Test
public void tableSpan() throws IOException { public void tableSpan() throws IOException {
String files[] = (xslfOnly) ? new String[]{ "bug60993.pptx" } : new String[]{ "bug60993.pptx", "bug60993.ppt" }; String files[] = (xslfOnly()) ? new String[]{ "bug60993.pptx" } : new String[]{ "bug60993.pptx", "bug60993.ppt" };
for (String f : files) { for (String f : files) {
SlideShow<?,?> ppt = openSampleSlideshow(f); SlideShow<?,?> ppt = openSampleSlideshow(f);
Slide<?,?> slide = ppt.getSlides().get(0); Slide<?,?> slide = ppt.getSlides().get(0);

View File

@ -20,6 +20,7 @@ package org.apache.poi.hslf.usermodel;
import static org.apache.poi.hslf.record.RecordTypes.OEPlaceholderAtom; import static org.apache.poi.hslf.record.RecordTypes.OEPlaceholderAtom;
import static org.apache.poi.hslf.record.RecordTypes.RoundTripHFPlaceholder12; import static org.apache.poi.hslf.record.RecordTypes.RoundTripHFPlaceholder12;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -312,21 +313,20 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
} }
} }
@Override
public Rectangle2D resizeToFitText() {
return resizeToFitText(null);
}
/** @Override
* Adjust the size of the shape so it encompasses the text inside it. public Rectangle2D resizeToFitText(Graphics2D graphics) {
*
* @return a <code>Rectangle2D</code> that is the bounds of this shape.
*/
public Rectangle2D resizeToFitText(){
Rectangle2D anchor = getAnchor(); Rectangle2D anchor = getAnchor();
if(anchor.getWidth() == 0.) { if(anchor.getWidth() == 0.) {
LOG.log(POILogger.WARN, "Width of shape wasn't set. Defaulting to 200px"); LOG.log(POILogger.WARN, "Width of shape wasn't set. Defaulting to 200px");
anchor.setRect(anchor.getX(), anchor.getY(), 200., anchor.getHeight()); anchor.setRect(anchor.getX(), anchor.getY(), 200., anchor.getHeight());
setAnchor(anchor); setAnchor(anchor);
} }
double height = getTextHeight(); double height = getTextHeight(graphics);
height += 1; // add a pixel to compensate rounding errors height += 1; // add a pixel to compensate rounding errors
Insets2D insets = getInsets(); Insets2D insets = getInsets();
@ -736,10 +736,15 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
} }
@Override @Override
public double getTextHeight(){ public double getTextHeight() {
DrawFactory drawFact = DrawFactory.getInstance(null); return getTextHeight(null);
}
@Override
public double getTextHeight(Graphics2D graphics) {
DrawFactory drawFact = DrawFactory.getInstance(graphics);
DrawTextShape dts = drawFact.getDrawable(this); DrawTextShape dts = drawFact.getDrawable(this);
return dts.getTextHeight(); return dts.getTextHeight(graphics);
} }
@Override @Override

Binary file not shown.