freemaker生成word模板的各種坑,包含word打不開、批量添加圖片、圖片變形等問題總結

最近在使用freemaker做一個word模板,裏面包含大量表格、截圖、超鏈接等數據、歷時一週多,遇到很多坑,現在想想都後怕,現在簡單總結一下,希望給以後的小夥伴提供幫助,少走彎路!

坑一:word打不開

可能原因:

1、往xml文件中添加數據佔位時,不細心導致文件中出現多餘的{、}、;、#等字符,導致xml校驗錯誤,會導致生成的word打不開。

2、word中有超鏈接,鏈接中包含多個參數時,會用&進行連接,然而在xml中&屬於特殊字符,如若不處理,導致xml校驗錯誤,會導致生成的word打不開;處理方式有兩種如下

第一種:使用CDATA包含此鏈接,使得xml不解析,比如<![CDATA[www.test.com?param=1&num=2]]>

第二種:將特殊字符轉義,&對應的轉義爲&amp;    其他特殊字符轉義可自行去網上查詢,轉義後的鏈接就變成www.test.com?param=1&amp;num=2,這種xml是可以解析的。

3、xml校驗沒有問題(xml校驗器https://www.runoob.com/xml/xml-validator.html),此時生成的docx文檔,使用wps是可以打開的,但是使用office確打不開,解決方案是直接生成doc格式的文檔,這樣wps跟office都能打開了,具體原因不詳,可能跟freemarker對docx跟doc支持不一樣。

坑二:批量添加圖片

由於第一次往word文檔中加圖片,而且是動態批量添加,沒有頭緒,網上查詢了資料也都沒有太好的方法,後面想着直接動態循環生成rId,沒成想直接成功了,非常開心,但也產生一個新問題,就是圖片變形了(下面在詳細說),實現方式如下:

往word中加圖片,首先在模板中需要插入一個圖片進行佔位,轉換成xml後,關於圖片的地方有三點,我自己理解的,描述的可能不太對,見諒!

1、圖片的源定義

<Relationship Id="rId99" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image99.jpeg"/>

2、圖片的base64碼,用變量替換

<pkg:part pkg:name="/word/media/image99.jpeg" pkg:contentType="image/jpeg" pkg:compression="store">                                                                           
    <pkg:binaryData>${img_gqctt!"--"}</pkg:binaryData>
</pkg:part>

3、圖片展示

<w:p w:rsidR="005A1D92" w:rsidRDefault="00785A68" w:rsidP="005A1D92">
    <w:pPr>
        <w:adjustRightInd w:val="0"/>
        <w:spacing w:line="360" w:lineRule="auto"/>
        <w:contextualSpacing/>
        <w:rPr>
            <w:rFonts w:ascii="等線" w:eastAsia="等線" w:hAnsi="等線"/>
            <w:sz w:val="24"/>
        </w:rPr>
    </w:pPr>
    <w:r>
        <w:rPr>
            <w:rFonts w:ascii="等線" w:eastAsia="等線" w:hAnsi="等線" w:cs="等線" w:hint="eastAsia"/>
            <w:bCs/>
            <w:noProof/>
            <w:sz w:val="24"/>
        </w:rPr>
        <w:drawing>
            <wp:inline distT="0" distB="0" distL="114300" distR="114300" wp14:anchorId="46AD878E" wp14:editId="0A36392B">
                <wp:extent cx="5274945" cy="4326255"/>
                <wp:effectExtent l="0" t="0" r="5080" b="14605"/>
                <wp:docPr id="2" name="圖片 2" descr="1589945007(1)"/>
                <wp:cNvGraphicFramePr>
                    <a:graphicFrameLocks
                        xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
                    </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="2" name="圖片 2" descr="1589945007(1)"/>
                                    <pic:cNvPicPr>
                                        <a:picLocks noChangeAspect="1"/>
                                    </pic:cNvPicPr>
                                </pic:nvPicPr>
                                <pic:blipFill>
                                    <a:blip r:embed="rId99"/>
                                    <a:stretch>
                                        <a:fillRect/>
                                    </a:stretch>
                                </pic:blipFill>
                                <pic:spPr>
                                    <a:xfrm>
                                        <a:off x="0" y="0"/>
                                        <a:ext cx="5274945" cy="4326255"/>
                                    </a:xfrm>
                                    <a:prstGeom prst="rect">
                                        <a:avLst/>
                                    </a:prstGeom>
                                </pic:spPr>
                            </pic:pic>
                        </a:graphicData>
                    </a:graphic>
                </wp:inline>
            </w:drawing>
        </w:r>
        <w:r w:rsidR="005A1D92">
            <w:rPr>
                <w:rFonts w:ascii="等線" w:eastAsia="等線" w:hAnsi="等線" w:hint="eastAsia"/>
                <w:sz w:val="24"/>
            </w:rPr>
            <w:t xml:space="preserve"></w:t>
        </w:r>
    </w:p>

1跟2是通過image99.jpeg關聯,1跟3是通過rId99關聯

具體實現方式:

<#list img_glrcyry as glrcyry>
    <Relationship Id="rId${glrcyry_index+200}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image${glrcyry_index+200}.jpeg"/>
</#list>

爲什麼要+200,是爲了防止id重複,我這文檔中包含大量的圖片

<#list img_glrcyry as glrcyry>
	<pkg:part pkg:name="/word/media/image${glrcyry_index+200}.jpeg" pkg:contentType="image/jpeg" pkg:compression="store">
		<pkg:binaryData>${glrcyry.img_glrcyry}</pkg:binaryData>
	</pkg:part>
</#list>
<#list img_glrcyry as glrcyry>
<w:p w:rsidR="005A1D92" w:rsidRDefault="005A1D92" w:rsidP="005A1D92">
    <w:pPr>
        <w:adjustRightInd w:val="0"/>
        <w:spacing w:line="360" w:lineRule="auto"/>
        <w:contextualSpacing/>
        <w:rPr>
            <w:rFonts w:ascii="等線" w:eastAsia="等線" w:hAnsi="等線"/>
            <w:sz w:val="24"/>
        </w:rPr>
    </w:pPr>
    <w:r>
        <w:rPr>
            <w:noProof/>
        </w:rPr>
        <w:lastRenderedPageBreak/>
        <w:drawing>
            <wp:inline distT="0" distB="0" distL="0" distR="0">
                <wp:extent cx="5274945" cy="4326255"/>
                <wp:effectExtent l="0" t="0" r="1905" b="0"/>
                <wp:docPr id="${glrcyry_index+200}" name="圖片 ${glrcyry_index+200}" descr="C:\Users\hewh\AppData\Local\Temp\ksohtml14508\wps40.jpg"/>
                <wp:cNvGraphicFramePr>
                    <a:graphicFrameLocks
                        xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1"/>
                    </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="0" name="Picture 906" descr="C:\Users\hewh\AppData\Local\Temp\ksohtml14508\wps40.jpg"/>
                                    <pic:cNvPicPr>
                                        <a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
                                    </pic:cNvPicPr>
                                </pic:nvPicPr>
                                <pic:blipFill>
                                    <a:blip r:embed="rId${glrcyry_index+200}">
                                        <a:extLst>
                                            <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
                                                <a14:useLocalDpi
                                                    xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
                                                </a:ext>
                                            </a:extLst>
                                        </a:blip>
                                        <a:srcRect/>
                                        <a:stretch>
                                            <a:fillRect/>
                                        </a:stretch>
                                    </pic:blipFill>
                                    <pic:spPr bwMode="auto">
                                        <a:xfrm>
                                            <a:off x="0" y="0"/>
                                            <a:ext cx="5274945" cy="4326255"/>
                                        </a:xfrm>
                                        <a:prstGeom prst="rect">
                                            <a:avLst/>
                                        </a:prstGeom>
                                        <a:noFill/>
                                        <a:ln>
                                            <a:noFill/>
                                        </a:ln>
                                    </pic:spPr>
                                </pic:pic>
                            </a:graphicData>
                        </a:graphic>
                    </wp:inline>
                </w:drawing>
            </w:r>
            <w:r>
                <w:rPr>
                    <w:rFonts w:ascii="等線" w:eastAsia="等線" w:hAnsi="等線" w:hint="eastAsia"/>
                    <w:sz w:val="24"/>
                </w:rPr>
                <w:t xml:space="preserve"></w:t>
            </w:r>
        </w:p>
</#list>

這樣就能將圖片批量動態的添加到word模板中了。

坑三:圖片變形問題

因爲事先用了一個圖片進行佔位,所有在模板中,圖片的大小固定,如果新插入的圖片跟佔位大小不一樣,就會導致圖片變形,壓縮或者拉伸。下面看一下圖片位置裏面代碼有兩個核心的地方:

<wp:extent cx="5274945" cy="4326255"/>

<a:ext cx="5274945" cy="4326255"/>

第一個是圖片在word中的區域,長跟寬的大小,第二個是圖片本身的通過像素值轉換的長跟寬(我自己理解的,可能描述的不太對),網上有說圖片像素值轉換成這個大小的計算邏輯,是 像素值*914400/100,然後去替換長跟寬,後面我經過反覆試驗驗證,發現不是很準確,這樣會導致圖片變形。

我的思路:圖片變形無非就是長寬比例不一致導致,所以我們根據要插入的圖片的寬跟高,計算寬高比,來改變模板裏這個寬高值,保證圖片在模板裏跟原圖是同樣的寬高比,這樣圖片就不會變形。

因爲一個圖片在word中只能佔一頁,而實際上有的圖片過長,有的圖片過寬,所以我的思路是,如果圖片過長,就固定長度,壓縮寬度,如果圖片過寬,就固定寬度,壓縮長度。我自己在word中用一個圖片拉滿,佔滿一頁,寬度大概是5275000,長度大概是8780000,我就以這個爲基準,以圖片時間寬高計算要在模板中展示的實際寬高,部分代碼如下:

BufferedImage bufferedImage = ImgBase64Util.base64String2BufferedImage(imgData);
            double wordProportion = (double) 5275000/8780000;
            double realProportion = (double) bufferedImage.getWidth()/bufferedImage.getHeight();
            // 過寬,以寬度爲基準
            if(realProportion >= wordProportion){
                root.put("img_gqctt_width", "5275000");
                long realHeight = 5275000L * bufferedImage.getHeight() / bufferedImage.getWidth();
                root.put("img_gqctt_height", String.valueOf(realHeight));
            }else{
                root.put("img_gqctt_height", "8780000");
                long realWidth = 8780000L * bufferedImage.getWidth() / bufferedImage.getHeight();
                root.put("img_gqctt_width", String.valueOf(realWidth));
            }

這樣到時候直接替換模板中的寬高,如果是批量添加圖片,需要計算出每個圖片的在模板中的實際寬高

<wp:extent cx="${img_gqctt_width}" cy="${img_gqctt_height}"/>

<a:ext cx="${img_gqctt_width}" cy="${img_gqctt_height}"/>

至此就能保證圖片在word中不變形了!

一週多的時間,中間遇到各種問題,曾一度要奔潰,好在後來慢慢問題全部解決,收穫頗豐!繼續加油!共勉!

 

寫在最後:freemarker對高版本的docx支持不是很好,建議模板生成xml時,選擇word 2003 XML文檔,不建議選擇word XML文檔,最後生成word文檔時,直接生成doc格式的,能避免很多坑!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章