Apache POI对Word的处理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013066292/article/details/80325390

写在前面

当我们对docx进行内容上的修改时,可以在修改后对docx文件用压缩包软件进行解压,然后在解压出来的文件夹里的word文件夹下的document.xml文件进行查看对比(毕竟docx是采用ooxml标准,所以内容及其属性都是以xml的形式来写)。

解压后的文件结构大致如下:

├── [Content_Types].xml
├── _rels
├── _xmlsignatures (该文件夹会在有数字签名的情况下生成)
│   ├── _rels
│   │   └── origin.sigs.rels
│   ├── origin.sigs
│   └── sig1.xml
├── docProps
│   ├── app.xml
│   └── core.xml
└── word
    ├── _rels
    │   └── document.xml.rels
    ├── document.xml
    ├── fontTable.xml
    ├── settings.xml
    ├── styles.xml
    ├── theme
    │   └── theme1.xml
    └── webSettings.xml

代码部分是groovy,与Java差别不大,很容易进行改写。

操作

1.添加图片

1.1 常规

Apache POI官方提供了一些简单的samples,包含了图片和图表的添加等。

def addImage(String doc, String img, int width, int height) {

        //判断图片格式
        int format = adjustImageFormat(img)
        if (format != -1) {
        //针对已存在的文件,应使用            
        //XWPFDocument document = new XWPFDocument(new FileInputStream(doc))
            XWPFDocument document = new XWPFDocument()
            XWPFParagraph paragraph = document.createParagraph()
            XWPFRun run = paragraph.createRun()
            //获取图片文件,路径,格式和大小
            run.addPicture(new FileInputStream(img), format, img, Units.toEMU(width), Units.toEMU(height))
            FileOutputStream outputStream = new FileOutputStream(doc)
            document.write(outputStream)
        }
    }

    /**
     * 判断图片格式
     * @param imgFile
     * @return
     */
    private int adjustImageFormat(String imgFile) {
        int format

        if (imgFile.endsWith(".emf")) format = XWPFDocument.PICTURE_TYPE_EMF
        else if (imgFile.endsWith(".wmf")) format = XWPFDocument.PICTURE_TYPE_WMF
        else if (imgFile.endsWith(".pict")) format = XWPFDocument.PICTURE_TYPE_PICT
        else if (imgFile.endsWith(".jpeg") || imgFile.endsWith(".jpg")) format = XWPFDocument.PICTURE_TYPE_JPEG
        else if (imgFile.endsWith(".png")) format = XWPFDocument.PICTURE_TYPE_PNG
        else if (imgFile.endsWith(".dib")) format = XWPFDocument.PICTURE_TYPE_DIB
        else if (imgFile.endsWith(".gif")) format = XWPFDocument.PICTURE_TYPE_GIF
        else if (imgFile.endsWith(".tiff")) format = XWPFDocument.PICTURE_TYPE_TIFF
        else if (imgFile.endsWith(".eps")) format = XWPFDocument.PICTURE_TYPE_EPS
        else if (imgFile.endsWith(".bmp")) format = XWPFDocument.PICTURE_TYPE_BMP
        else if (imgFile.endsWith(".wpg")) format = XWPFDocument.PICTURE_TYPE_WPG
        else {
            System.err.println("Unsupported picture: " + imgFile +
                    ". Expected emf|wmf|pict|jpeg|png|dib|gif|tiff|eps|bmp|wpg")
            return -1
        }
        return format
    }

从目前来看,图片的添加似乎只能进行常规性的操作,就是在文字的后面追加。而对于我们想让图片对文字进行环绕的相关操作(比方说 衬于文字下方 )是没有的。

1.2 图片属性添加

在一开始的时候我们说过,当我们对word的内容进行修改的时候,它是在对document.xml里的相关内容进行修改,那么我们要如何看懂里面的内容呢?可以通过officeopenxml 网站进行了解和学习。

以我们这一节为例,我们需要了解在docx下插入图片后,对其进行相关的调整,那么就应该参考这里 DrawingML Overview

我们新建一个docx文档,然后插入图片,保存后我们可以看到其document.xml里的内容是这样(只截取主要部分):

<w:drawing>
                    <wp:inline distB="0" distL="0" distR="0" distT="0">
                        <wp:extent cx="5270500" cy="7058025"/>
                        <wp:effectExtent b="3175" l="0" r="0" t="0"/>
                        <wp:docPr id="1" name="图片 1"/>
                        <wp:cNvGraphicFramePr>
                            <a:graphicFrameLocks noChangeAspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/>
                        </wp:cNvGraphicFramePr>
                        <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                            <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                    <pic:nvPicPr>
                                        <pic:cNvPr id="1" name="D59B2F44-A382-4B8D-94E7-8457E3581342.jpg"/>
                                        <pic:cNvPicPr/>
                                    </pic:nvPicPr>
                                    <pic:blipFill>
                                        <a:blip cstate="print" r:embed="rId4">
                                            <a:extLst>
                                                <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
                                                    <a14:useLocalDpi val="0" xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main"/>
                                                </a:ext>
                                            </a:extLst>
                                        </a:blip>
                                        <a:stretch>
                                            <a:fillRect/>
                                        </a:stretch>
                                    </pic:blipFill>
                                    <pic:spPr>
                                        <a:xfrm>
                                            <a:off x="0" y="0"/>
                                            <a:ext cx="5270500" cy="7058025"/>
                                        </a:xfrm>
                                        <a:prstGeom prst="rect">
                                            <a:avLst/>
                                        </a:prstGeom>
                                    </pic:spPr>
                                </pic:pic>
                            </a:graphicData>
                        </a:graphic>
                    </wp:inline>
                </w:drawing>

然后我们把图片的 环绕文字 设置为 浮于文字之上 ,变化后的document.xml为:

<w:drawing>
                    <wp:anchor allowOverlap="1" behindDoc="0" distB="0" distL="114300" distR="114300" distT="0" layoutInCell="1" locked="0" relativeHeight="251658240" simplePos="0">
                        <wp:simplePos x="0" y="0"/>
                        <wp:positionH relativeFrom="column">
                            <wp:posOffset>1905</wp:posOffset>
                        </wp:positionH>
                        <wp:positionV relativeFrom="paragraph">
                            <wp:posOffset>40005</wp:posOffset>
                        </wp:positionV>
                        <wp:extent cx="5270500" cy="7058025"/>
                        <wp:effectExtent b="3175" l="0" r="0" t="0"/>
                        <wp:wrapNone/>
                        <wp:docPr id="1" name="图片 1"/>
                        <wp:cNvGraphicFramePr>
                            <a:graphicFrameLocks noChangeAspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/>
                        </wp:cNvGraphicFramePr>
                        <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
                            <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                    <pic:nvPicPr>
                                        <pic:cNvPr id="1" name="D59B2F44-A382-4B8D-94E7-8457E3581342.jpg"/>
                                        <pic:cNvPicPr/>
                                    </pic:nvPicPr>
                                    <pic:blipFill>
                                        <a:blip cstate="print" r:embed="rId4">
                                            <a:extLst>
                                                <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
                                                    <a14:useLocalDpi val="0" xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main"/>
                                                </a:ext>
                                            </a:extLst>
                                        </a:blip>
                                        <a:stretch>
                                            <a:fillRect/>
                                        </a:stretch>
                                    </pic:blipFill>
                                    <pic:spPr>
                                        <a:xfrm>
                                            <a:off x="0" y="0"/>
                                            <a:ext cx="5270500" cy="7058025"/>
                                        </a:xfrm>
                                        <a:prstGeom prst="rect">
                                            <a:avLst/>
                                        </a:prstGeom>
                                    </pic:spPr>
                                </pic:pic>
                            </a:graphicData>
                        </a:graphic>
                        <wp14:sizeRelH relativeFrom="page">
                            <wp14:pctWidth>0</wp14:pctWidth>
                        </wp14:sizeRelH>
                        <wp14:sizeRelV relativeFrom="page">
                            <wp14:pctHeight>0</wp14:pctHeight>
                        </wp14:sizeRelV>
                    </wp:anchor>
                </w:drawing>

通过对比,我们主要看到的一个变化是从< wp:inline >标签替换为< wp:anchor >标签开始,这是图片从内联到浮动的一个标志。然后是对anchor的属性以及它的下级标签等进行一些相关的设置,具体的内容参考 Positioning within a Word Processing Document 。当我们从内联切换到浮动后,对图片进行 浮在文字上 的设置主要是anchor标签下的behindDoc属性设为false,同时出现一个< wp:wrapNone/>的空标签。

以上主要是对从ooxml的角度来看当图片改变时在docx文档上的变化。那么目前我们要怎么通过Apache POI来处理?由于Apache POI应该只是进行了常规性的操作,所以我们需要自己尝试来编写一些规则,可以参考Stack Overflow上的这个问题Wrap Text in Apache POI(docx)? 进行处理。

扫描二维码关注公众号,回复: 3050815 查看本文章

1.3 参考

关于图片对文字的环绕请参考 :Positioning within a Word Processing Document - Floating Pictures - Text Wrapping

关于图片位置的确定请参考 :Positioning within a Word Processing Document - Floating Pictures - Positioning

1.4 其它

  1. 关于CTAnchor missing dependency CTPosH的问题
    使用Groovy编译的过程中报出以下的错误:
Error:Groovyc: While compiling signer-office_main: 
java.lang.RuntimeException: java.lang.NoClassDefFoundError: 
Unable to load class org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor 
due to missing dependency 
org/openxmlformats/schemas/drawingml/x2006/wordprocessingDrawing/CTPosH

原因在于poi-schema库下缺乏了CTPosH这个类,因为这是一个精简版的jar,只包含一些典型的类,所以体积比较小。因此为了解决这个问题,我们需要使用完整的schema的jar包: I’m using the poi-ooxml-schemas jar, but my code is failing with “java.lang.NoClassDefFoundError: org/openxmlformats/schemas/something


2. 安全

2.1 签名

 def addSignature(String doc) {
        //pfx证书密码
        def password = pfxPassoword.toCharArray()
        File file = new File(pfxPath)
        KeyStore keystore = KeyStore.getInstance("PKCS12")
        FileInputStream fis = new FileInputStream(file)
        keystore.load(fis, password)
        fis.close()

        //获取别名
        Enumeration enumas = keystore.aliases()
        String alias = null
        while (enumas.hasMoreElements()) {
            alias = (String) enumas.nextElement()
        }

        //准备密钥对
        Key key = keystore.getKey(alias, password)
        KeyPair keyPair = null
        if (key instanceof PrivateKey) {
            Certificate cert = keystore.getCertificate(alias)
            PublicKey publicKey = cert.getPublicKey()
            keyPair = new KeyPair(publicKey, (PrivateKey) key)
        }

        //签名配置
        SignatureConfig signatureConfig = new SignatureConfig()
        signatureConfig.setKey(keyPair.getPrivate())
        X509Certificate x509 = (X509Certificate) keystore.getCertificate(alias)
        signatureConfig.setSigningCertificateChain(Collections.singletonList(x509))

        //打开文件
        OPCPackage opcPackage = OPCPackage.open(new File(doc), PackageAccess.READ_WRITE)
        signatureConfig.setOpcPackage(opcPackage)

        //装载签名配置
        SignatureInfo si = new SignatureInfo()
        si.setSignatureConfig(signatureConfig)
        //调用签名方法
        si.confirmSignature()

        //关闭文件
        opcPackage.close()
    }

2.2 验签

  boolean verify(String file) {
        boolean result = false
        InputStream inputStream = FileMagic.prepareToCheckMagic(new FileInputStream(file))
        if (FileMagic.valueOf(inputStream) == FileMagic.OLE2) {

            System.out.println("Unsupport doc format")

        } else if (FileMagic.valueOf(inputStream) == FileMagic.OOXML) {
            try {
                OPCPackage opcPackage = OPCPackage.open(file, PackageAccess.READ)
                SignatureConfig signatureConfig = new SignatureConfig()
                signatureConfig.setOpcPackage(opcPackage)
                SignatureInfo signatureInfo = new SignatureInfo()
                signatureInfo.setSignatureConfig(signatureConfig)
                result = signatureInfo.verifySignature()

            } catch (InvalidFormatException e) {
                e.printStackTrace()
            }

        }
        return result
    }

2.3 参考

Apache POI - Encryption support

猜你喜欢

转载自blog.csdn.net/u013066292/article/details/80325390