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 就不详细在这里说了

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