resizeToFitText()导致带有非拉丁字符的文本溢出文本框

时间:2017-06-08 14:33:48

标签: java apache-poi

我们正在使用Apache POI 3.16(撰写本文时的最新版本)。

我们的代码如下:

XSLFTextBox textBox = slide.createTextBox();
XSLFTextParagraph paragraph = textBox.getTextParagraphs().get(0);
XSLFTextRun textRun = paragraph.addNewTextRun();
textRun.setText("non-Latin characters here");
textBox.setAnchor(new Rectangle(left, top, width, 10000));
textBox.resizeToFitText();

请注意,我们不会以任何方式更改字体样式。

此代码导致文本溢出文本框:

Text overflowing textbox with Apache POI

它似乎不是Apache POI错误。我只能找到关于resizeToFitText()Bug 45140Bug 47594)的两个问题,两者都与换行符(which is another problem we're encountering)有关。

关于我们如何规避问题的任何想法?

更新1:这是一个完整的独立复制案例:

import java.awt.Rectangle;
import java.io.FileOutputStream;

import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTextBox;
import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
import org.apache.poi.xslf.usermodel.XSLFTextRun;

public class TextBoxOverflow {
    public static void main(String[] args) throws Exception {

        XMLSlideShow slideShow = new XMLSlideShow();

        XSLFSlide slide = slideShow.createSlide();

        XSLFTextBox textBox = slide.createTextBox();
        XSLFTextParagraph paragraph = textBox.getTextParagraphs().get(0);
        XSLFTextRun textRun = paragraph.addNewTextRun();
        textRun.setText(
            "ちょっと早いけどTシャツが着たくなる季節♡お母さんの影響か、非常に恐竜が大好きです。もう飼いたいくらい大好きです。#ジュラシックワールド のラプトル4姉妹とか激的に可愛くて可愛くて可愛くて可愛いです。めろめろ、大好き♡お母さんも恐竜が好きで、小さい頃、古代生物の図鑑を一緒に見てたの思い出す〜とい");
        textBox.setAnchor(new Rectangle(50, 50, 200, 5000));
        textBox.resizeToFitText();

        FileOutputStream out = new FileOutputStream("TextBoxOverflow.pptx");
        slideShow.write(out);
        out.close();
        slideShow.close();
    }
}

结果:

Text overflowing textbox with Apache POI

更新2:在Apache POI的错误跟踪器中记录错误:
https://bz.apache.org/bugzilla/show_bug.cgi?id=61169

1 个答案:

答案 0 :(得分:1)

这似乎是Windows迄今为止对Unicode支持不佳的一个缺点。

如果我运行以下代码

import java.awt.Rectangle;
import java.io.FileOutputStream;

import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTextBox;
import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
import org.apache.poi.xslf.usermodel.XSLFTextRun;

import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;

public class TextBoxOverflow {
    public static void main(String[] args) throws Exception {

        XMLSlideShow slideShow = new XMLSlideShow();

        XSLFSlide slide = slideShow.createSlide();

        XSLFTextBox textBox = slide.createTextBox();
        XSLFTextParagraph paragraph = textBox.getTextParagraphs().get(0);
        XSLFTextRun textRun = paragraph.addNewTextRun();

        textRun.setText(
            "ちょっと早いけどTシャツが着たくなる季節♡お母さんの影響か、非常に恐竜が大好きです。もう飼いたいくらい大好きです。#ジュラシックワールド のラプトル4姉妹とか激的に可愛くて可愛くて可愛くて可愛いです。めろめろ、大好き♡お母さんも恐竜が好きで、小さい頃、古代生物の図鑑を一緒に見てたの思い出す〜とい");

        textBox.setAnchor(new Rectangle(50, 50, 200, 5000));

        double heigth = textBox.getTextHeight();
System.out.println(heigth);

        textBox.resizeToFitText();

        CTShape ctshape = (CTShape)textBox.getXmlObject();
System.out.println(ctshape.getSpPr());

        //set TextBox autofit the text 
        ctshape.getTxBody().getBodyPr().addNewSpAutoFit();

        FileOutputStream out = new FileOutputStream("TextBoxOverflow.pptx");
        slideShow.write(out);
        out.close();
        slideShow.close();
    }
}

Linux,然后我得到:

enter image description here

如您所见,textBox.getTextHeight()330.0且主播中的cycy="4203700"

这会生成一个适当调整大小的文本框。

如果我在Windows中也这样做,那么我得到:

enter image description here

如您所见,textBox.getTextHeight()183.78125且主播中的cycy="2346722"

这肯定会导致文本框只有一半高度。

如果您执行ctshape.getTxBody().getBodyPr().addNewSpAutoFit();,则设置“将文本框大小自动调整为文本”标志。然后,至少对PowerPoint中的文本进行任何更改都会导致自动调整该框。

2017年6月10日编辑:

至少找到一个近似的解决方案。如果我们将XSLFTextRun的字体系列设置为“Meiryo”,那么Windows中的文本框高度的确定也大致正确:

import java.awt.Rectangle;
import java.io.FileOutputStream;

import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTextBox;
import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
import org.apache.poi.xslf.usermodel.XSLFTextRun;

import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;

public class TextBoxOverflow {
    public static void main(String[] args) throws Exception {

        XMLSlideShow slideShow = new XMLSlideShow();

        XSLFSlide slide = slideShow.createSlide();

        XSLFTextBox textBox = slide.createTextBox();
        XSLFTextParagraph paragraph = textBox.getTextParagraphs().get(0);
        XSLFTextRun textRun = paragraph.addNewTextRun();

        String fontfamily = "Meiryo";
        textRun.setFontFamily(fontfamily);  

        textRun.setText(
            "ちょっと早いけどTシャツが着たくなる季節♡お母さんの影響か、非常に恐竜が大好きです。もう飼いたいくらい大好きです。#ジュラシックワールド のラプトル4姉妹とか激的に可愛くて可愛くて可愛くて可愛いです。めろめろ、大好き♡お母さんも恐竜が好きで、小さい頃、古代生物の図鑑を一緒に見てたの思い出す〜とい");

        textBox.setAnchor(new Rectangle(50, 50, 200, 5000));

        double heigth = textBox.getTextHeight();
System.out.println(heigth);

        textBox.resizeToFitText();

        CTShape ctshape = (CTShape)textBox.getXmlObject();
System.out.println(ctshape.getSpPr());

        //set TextBox autofit the text 
        ctshape.getTxBody().getBodyPr().addNewSpAutoFit();

        FileOutputStream out = new FileOutputStream("TextBoxOverflow.pptx");
        slideShow.write(out);
        out.close();
        slideShow.close();
    }
}

Linux导入与上述相同的值:textBox.getTextHeight()330.0,锚点中的cycy="4203700"

但现在Windows textBox.getTextHeight()353.8330078125,而cy中的cy="4506379"ctshape.getTxBody().getBodyPr().addNewSpAutoFit();。结合Microsoft,我认为这是可以接受的。

不清楚应由谁负责。 Java由于其支持较差的Unicode或public class MainActivity extends Activity { private static final String TAG = "ButtonActivity"; private static final String INC_BUTTON_PIN_NAME = "BCM4"; // GPIO port wired to the button private static final String DEC_BUTTON_PIN_NAME = "BCM17"; // GPIO port wired to the button private Gpio mIncButtonGpio; private Gpio mDecButtonGpio; Handler mHandler = new Handler(Looper.getMainLooper()); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PeripheralManagerService service = new PeripheralManagerService(); try { // Step 1. Create GPIO connection. mIncButtonGpio = service.openGpio(INC_BUTTON_PIN_NAME); mDecButtonGpio = service.openGpio(DEC_BUTTON_PIN_NAME); // Step 2. Configure as an input. mIncButtonGpio.setDirection(Gpio.DIRECTION_IN); mDecButtonGpio.setDirection(Gpio.DIRECTION_IN); // Step 3. Enable edge trigger events. mIncButtonGpio.setEdgeTriggerType(Gpio.EDGE_FALLING); mDecButtonGpio.setEdgeTriggerType(Gpio.EDGE_FALLING); // Step 4. Register an event callback. mIncButtonGpio.registerGpioCallback(mIncCallback); mDecButtonGpio.registerGpioCallback(mDecCallback); } catch (IOException e) { Log.e(TAG, "Error on PeripheralIO API", e); } } // Step 4. Register an event callback. private GpioCallback mIncCallback = new GpioCallback() { @Override public boolean onGpioEdge(Gpio gpio) { Log.i(TAG, "GPIO changed, INC button pressed"); // Step 5. Return true to keep callback active. return true; } }; private GpioCallback mDecCallback = new GpioCallback() { @Override public boolean onGpioEdge(Gpio gpio) { Log.i(TAG, "GPIO changed, DEC button pressed"); // Step 5. Return true to keep callback active. return true; } }; @Override protected void onDestroy() { super.onDestroy(); // Step 6. Close the resource if (mIncButtonGpio != null) { mIncButtonGpio.unregisterGpioCallback(mIncCallback); try { mIncButtonGpio.close(); } catch (IOException e) { Log.e(TAG, "Error on PeripheralIO API", e); } } if (mDecButtonGpio != null) { mDecButtonGpio.unregisterGpioCallback(mDecCallback); try { mDecButtonGpio.close(); } catch (IOException e) { Log.e(TAG, "Error on PeripheralIO API", e); } } } } ,因为它的字体管理效果不佳。