ekoz / kbase-doc

文档在线预览编辑,文档水印 / Office files preview or edit online, doc/docx convert to html, watermark
Apache License 2.0
470 stars 120 forks source link

加水印失败 #7

Closed jyf1997 closed 3 years ago

jyf1997 commented 4 years ago

当我使用这种方式加水印时: InputStream in = new FileInputStream(inputUrl); //获取word文档解析对象 XWPFDocument doucument = new XWPFDocument(in); addWaterMark(doucument,"水印","#d8d8d8"); 报错: Exception in thread "main" java.lang.IndexOutOfBoundsException at org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRImpl.getPictArray(Unknown Source) at com.zhibei.utils.PoiUtil.addWaterMark(PoiUtil.java:339) at com.zhibei.utils.PoiUtil.changeWord(PoiUtil.java:290) at com.zhibei.utils.PoiUtil.main(PoiUtil.java:486)

ekoz commented 4 years ago

@jyf1997 是否方便贴一下源码?我的源码里word添加水印的思路是采用docx4j,不是poi的方法,你可以尝试用我的代码实现下,详见单元测试类 WordProcessorTests

jyf1997 commented 4 years ago

以下是我解析Word的代码,我尝试过,如果是通过 IO流或者模板去创建 document对象, paragraph.getCTP().getRArray(0).getPictArray(0).这句就会报数组下标越界错误。如果直接调用无参的构造方法,则可以正常的运行并加上水印。随便问一下:POI可以为EXCEL或者PPT 加上文字水印吗? public static void changeWord(String inputUrl, String outputUrl,int status){ try { InputStream in = new FileInputStream(inputUrl); //获取word文档解析对象 XWPFDocument doucument = new XWPFDocument(in); addWaterMark(doucument,"水印","#d8d8d8"); //获取段落文本对象 List paragraphs = doucument.getParagraphs(); for (int i=0;i<paragraphs.size();i++) {//遍历模板中的段落对象找到标记位置 XWPFParagraph xwpfParagraph = paragraphs.get(i); List runs = xwpfParagraph.getRuns(); for (int l=0;l<runs.size();l++) { XWPFRun run = runs.get(l); String s = run.getText(run.getTextPosition()); if (status==1) s = WordAPi.Encrypt(s); else s=WordAPi.Decrypt(s); run.setText(s,0); } } //获取首行run对象 // XWPFRun run = paragraph.createRun(); //设置文本内容 // run.setText(readWord(inputUrl)); File file = new File(outputUrl); FileOutputStream stream = new FileOutputStream(file); doucument.write(stream); stream.close();

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private static void addWaterMark(Object obj, String watermark, String color) {
    if (obj instanceof XWPFDocument) {
        XWPFDocument doc = (XWPFDocument) obj;
        // create header-footer
        XWPFHeaderFooterPolicy headerFooterPolicy =doc.createHeaderFooterPolicy();

        // create default Watermark - fill color black and not rotated
        headerFooterPolicy.createWatermark(watermark);

        // get the default header
        // Note: createWatermark also sets FIRST and EVEN headers
        // but this code does not updating those other headers
        XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);
        XWPFParagraph paragraph = header.getParagraphArray(0);

        // get com.microsoft.schemas.vml.CTShape where fill color and rotation is set
        paragraph.getCTP().newCursor();
        XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren(new QName("urn:schemas-microsoft-com:vml", "shape"));
        if (xmlobjects.length > 0) {
            com.microsoft.schemas.vml.CTShape ctshape = (com.microsoft.schemas.vml.CTShape)xmlobjects[0];
            // set fill color
            ctshape.setFillcolor(color);
            // set rotation
            ctshape.setStyle(ctshape.getStyle() + ";rotation:315");
        }
    } else if (obj instanceof HWPFDocument) {

    }
}
YANZHAO1 commented 4 years ago

你好你的demo下载下来 用WatermarkServiceImpl中addWaterMark 方法加水印会报 数组越界,你在使用的过程中会出现吗? java.lang.IndexOutOfBoundsException at org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRImpl.getPictArray(Unknown Source)

YANZHAO1 commented 4 years ago

以下是我解析Word的代码,我尝试过,如果是通过 IO流或者模板去创建 document对象, paragraph.getCTP().getRArray(0).getPictArray(0).这句就会报数组下标越界错误。如果直接调用无参的构造方法,则可以正常的运行并加上水印。随便问一下:POI可以为EXCEL或者PPT 加上文字水印吗? public static void changeWord(String inputUrl, String outputUrl,int status){ try { InputStream in = new FileInputStream(inputUrl); //获取word文档解析对象 XWPFDocument doucument = new XWPFDocument(in); addWaterMark(doucument,"水印","#d8d8d8"); //获取段落文本对象 List paragraphs = doucument.getParagraphs(); for (int i=0;i<paragraphs.size();i++) {//遍历模板中的段落对象找到标记位置 XWPFParagraph xwpfParagraph = paragraphs.get(i); List runs = xwpfParagraph.getRuns(); for (int l=0;l<runs.size();l++) { XWPFRun run = runs.get(l); String s = run.getText(run.getTextPosition()); if (status==1) s = WordAPi.Encrypt(s); else s=WordAPi.Decrypt(s); run.setText(s,0); } } //获取首行run对象 // XWPFRun run = paragraph.createRun(); //设置文本内容 // run.setText(readWord(inputUrl)); File file = new File(outputUrl); FileOutputStream stream = new FileOutputStream(file); doucument.write(stream); stream.close();

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private static void addWaterMark(Object obj, String watermark, String color) {
    if (obj instanceof XWPFDocument) {
        XWPFDocument doc = (XWPFDocument) obj;
        // create header-footer
        XWPFHeaderFooterPolicy headerFooterPolicy =doc.createHeaderFooterPolicy();

        // create default Watermark - fill color black and not rotated
        headerFooterPolicy.createWatermark(watermark);

        // get the default header
        // Note: createWatermark also sets FIRST and EVEN headers
        // but this code does not updating those other headers
        XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT);
        XWPFParagraph paragraph = header.getParagraphArray(0);

        // get com.microsoft.schemas.vml.CTShape where fill color and rotation is set
        paragraph.getCTP().newCursor();
        XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren(new QName("urn:schemas-microsoft-com:vml", "shape"));
        if (xmlobjects.length > 0) {
            com.microsoft.schemas.vml.CTShape ctshape = (com.microsoft.schemas.vml.CTShape)xmlobjects[0];
            // set fill color
            ctshape.setFillcolor(color);
            // set rotation
            ctshape.setStyle(ctshape.getStyle() + ";rotation:315");
        }
    } else if (obj instanceof HWPFDocument) {

    }
}

你好 这个问题你解决了吗

ekoz commented 4 years ago

@YanZhao1 把你的代码和测试文档可以发我邮箱,我们调试下

jyf1997 commented 4 years ago

@YanZhao1
并非每个paragraph 对象都需要通过XML去修改,直接即可 XWPFHeaderFooterPolicy xFooter = new XWPFHeaderFooterPolicy(doucument); xFooter.createWatermark("水印");