python word 公式轉png圖片處理方式

      因項目中需要導入word文檔,但其中存在的公式,系統不支持,但又需要導入進系統,之前都是手動截圖後再重新插進去,關鍵時候上千章試卷要進行截圖也很耗時間,所以研究了一下轉換方式

 

      首先通過將docx後綴改成zip解壓後可以發現,公式分成兩部分,一部分是.wmf的矢量圖文件,一個是objectbin文件,但實際通過畫圖打開矢量圖後發現公式已經可以完整顯示出來了,那需要解決的關鍵部分就是.wmf轉.png文件就行了。最開始採用了java來做,但發現通過wmf轉svg再轉png,一些符號會顯示錯誤,例如微積分符號,可能和格式或者轉換方式有關,故放棄。偶然間通過畫圖將矢量圖wmf另存爲png時發現所有符號都是顯示正確的,那麼C#中肯定存在可以完成轉換的方式,果然,翻閱一些資料後發現wmf可以通過圖元文件寫入位圖,最後再將圖像信息存入文件中就可以很方便的完成轉換了,代碼如下:

             

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Xml;

namespace Project1
{
    class Class2
    {
        static void Main(string[] args)
         {
             String FileName = args[0];
             using (System.Drawing.Imaging.Metafile img = new System.Drawing.Imaging.Metafile(FileName))
             {
                 System.Drawing.Imaging.MetafileHeader header = img.GetMetafileHeader();
                 float scale = header.DpiX / 96f;
                 using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap((int)(scale * img.Width / header.DpiX * 100), (int)(scale * img.Height / header.DpiY * 100)))
                 {
                     using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
                     {
                         g.Clear(System.Drawing.Color.White);
                         g.ScaleTransform(scale, scale);
                         g.DrawImage(img, 0, 0);
                     }
                     bitmap.Save(@args[1], System.Drawing.Imaging.ImageFormat.Png);
                 }
             }
             Console.WriteLine("轉換完成");
         }
    }
}

     再完成轉換後,打算通過python-docx提取所有圖片轉換後再存入新的docx文件中來實現轉換,但踩了一個很大的坑,因爲python-docx中取出的圖片數量和實際有的公式數量並不匹配,主要是一些C2和C1之類的小字符。之後再用pydocx轉成html後發現,所有圖片信息都以base64的形式儲存在img標籤的src中,並且數量與實際公式的數量是一致的,那麼解決方式就確定了

 

先說一下個人的解決思路,java應該可以採用poi完成同樣的操作:

1.先將docx文件轉爲html,其中公式或者圖片按照base64編碼直接寫入html中(因如果不使用此種方式,直接通過 python-docx提取圖片數量可能會小於實際含有的圖片數量 導致轉換失敗)

2.提取html中的所有img標籤的內容,將src重新寫入文件中,cmd調用c#程序直接轉爲png後轉成base64編碼,替換回html中

3.將html轉化爲docx文件,就是最後的結果了,pydocx轉換的html有如下規律

1)所有內容都在body中

2)paragraph對應爲p標籤,遇到直接再新建的文檔中添加paragraph即可

3)所有文字以run類型直接添加到paragraph

4)遇到圖片直接再run中添加圖片即可,注意大小,大小的計算方式(獲取html中的width和height,併除以80轉爲Inches就是較合適的大小)

5)table處理較爲特別,table是不會存在於p標籤中,而是與p標籤並列,遇到table標籤後,獲取tr和td的數量並創建table,通過循環遍歷方式獲取cell, 再cell中通過添加paragraph來插入內容或圖片(處理與上述標籤一致)

tag的處理如下代碼所示:

 

def handle_tag(tag,parent,photo_base_path):
    if type(tag) == bs4.element.NavigableString:
        content=tag.replace("\n", "")
        if content=="":
            pass
        else:
            parent.add_run(content)
    elif type(tag)==bs4.element.Tag:
        if tag.name == "p":
            p = parent.add_paragraph()
            # 遍歷
            for child in tag.contents:
                handle_tag(child,p,photo_base_path)
        elif tag.name == "img":
            #按parent類型是否是進行區分
            run = parent.add_run()
            if tag["width"].endswith("pt"):
                width = float(tag["width"].replace("pt", ""))
            elif tag["width"].endswith("px"):
                width = float(tag["width"].replace("px", ""))
            if tag["height"].endswith("pt"):
                height = float(tag["height"].replace("pt", ""))
            elif tag["height"].endswith("px"):
                height = float(tag["height"].replace("px", ""))
            resultdata,path=savephoto(tag["src"], photo_base_path)
            run.add_picture(path, width=Inches(width / 80), height=Inches(height / 80))
        elif tag.name=="table":
            #獲取table下所有tr標籤和每一行的td標籤
            tr=tag.find_all("tr")
            if len(tr)!=0:
                td = tr[0].find_all("td")
                table = parent.add_table(rows=len(tr), cols=len(td))
                startrowindex=0
                for row in tr:
                    td = row.find_all("td")
                    startcolumnindex=0
                    for column in td:
                        cell=table.cell(startrowindex,startcolumnindex)
                        p=cell.add_paragraph()
                        for child in column.contents:
                            handle_tag(child, p,photo_base_path)
                        startcolumnindex=startcolumnindex+1
                    startrowindex=startrowindex+1
        else:
            pass

具體代碼見github:https://github.com/peoplhappy/wordformulatopng 就不詳細在這裏說了

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