Python透過PySide2、fitz完成word/pdf檔案互轉

Python透過PySide2、fitz完成word/pdf檔案互轉

  • 透過pyside2庫完成window設定
    • 一、在QT設計師中完成.ui檔案
    • 二、具體操作步驟
      • 1、專案需要匯入的庫
      • 2、載入ui檔案
      • 3、設定qt視窗中widget功能和訊號
      • 4、主功能函式1(word檔案轉化pdf檔案主功能函式)
      • 4、主功能函式2(pdf檔案轉化word檔案主功能函式)
      • 5、取得檔案path函式1(取得單個檔案路徑)
      • 5、取得檔案path函式2(取得多個檔案路徑)
      • 6、處理轉化函式1(執行單個word檔案和pdf檔案互轉)
      • 6、處理轉化函式2(執行多個word檔案和pdf檔案互轉)
      • 7、實現開啟從pdf中取得的圖像
    • 完整程式碼
    • 總結

透過pyside2庫完成window設定

第一次寫部落格!非專業程式設計師,只是對程式設計感興趣,自學的python的,主要為了方便日常工作。以及紀錄所學知識點。歡迎各位大佬指導!!!

一、在QT設計師中完成.ui檔案

二、具體操作步驟

1、專案需要匯入的庫

1
2
3
4
pip insatll pymupdf  (使用fitz需要安裝)
pip insatll pyside2  (使用pyside2需要安裝)
pip install  python-docx  (使用docx需要安裝)
pip install  pywin32  (使用win32com需要安裝)
1
2
3
4
5
6
7
8
from PySide2.QtWidgets import QApplication, QFileDialog, QMessageBox
from PySide2.QtUiTools import QUiLoader
from PySide2.QtCore import QFile
from win32com.client import constants, gencache
import fitz
from docx import Document
from docx.shared import Pt
import os

2、載入ui檔案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class WordTransform:

    def __init__(self):
        """
        載入ui檔案,初始化按鈕等觸發事件回應對接執行函式
        """
        file = QFile('./word_ppt.ui')
        file.open(QFile.ReadOnly)
        file.close()
        self.window = QUiLoader().load(file)
       
if __name__ == '__main__':
    app = QApplication([])
    new_word = WordTransform()
    new_word.window.show()
    app.exec_()

3、設定qt視窗中widget功能和訊號

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        # 設定單行文字框唯讀
        self.window.lineEdit.setReadOnly(True)
        # 設定多行文字框唯讀
        self.window.plainTextEdit.setReadOnly(True)
        # 當按鈕「開啟檔案」被點選觸發事件,執行對應函式
        self.window.pushButton1.clicked.connect(self.get_filepath)
        # 當按鈕「單個轉化」被點選觸發事件,執行對應函式
        self.window.pushButton2.clicked.connect(self.create_pdf_word)
        # 當按鈕「開啟檔案」被點選觸發事件,執行對應函式
        self.window.pushButton3.clicked.connect(self.get_filepaths)
        # 當按鈕「批量轉化」被點選觸發事件,執行對應函式
        self.window.pushButton4.clicked.connect(self.create_pdfs_words)
        # 當按鈕「開啟pdf中圖像」被點選觸發事件,執行對應函式
        self.window.pushButton5.clicked.connect(self.open_pdf_image)

4、主功能函式1(word檔案轉化pdf檔案主功能函式)

1
2
3
4
5
6
7
8
9
10
    def word_to_pdf(self, path):
        """
        word檔案轉化pdf檔案主功能函式
        """
        pdf_path = path.split('.')[0] + '.pdf'
        word = gencache.EnsureDispatch('Word.Application')
        doc = word.Documents.Open(path, ReadOnly=1)
        # 轉化方法
        doc.ExportAsFixedFormat(pdf_path, constants.wdExportFormatPDF)
        word.Quit()

4、主功能函式2(pdf檔案轉化word檔案主功能函式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    def pdf_to_word(self, path):
        """
        pdf檔案轉化word檔案主功能函式
        註:該函式木器中能識別pdf中的純文字和圖像訊息,表格等其他識別不出
        """
        pic_path = './pdf_word_images'  # 取得pdf檔案中圖像儲存路徑
        if not os.path.exists(pic_path):
            os.mkdir(pic_path)
        else:
            pass
        document = Document()
        word_path = path.split('.')[0] + '.docx'
        doc = fitz.open(path)
        for n in range(doc.page_count):
            page = doc.load_page(n)
            # 取得pdf中的文字訊息,並寫入word
            document.add_paragraph(page.getText('text'))
        self.window.progressBar.setValue(1)
        for i in range(doc.page_count):
            for image in doc.get_page_images(i):
                xref = image[0]
                pix = fitz.Pixmap(doc, xref)
                if pix.n < 5:
                    pix.writePNG(os.path.join(pic_path, 'page%s-%s.png' % (i, xref)))  # 儲存圖像
                    document.add_picture(os.path.join(pic_path, 'page%s-%s.png' % (i, xref)), Pt(400), Pt(200))  # 取得pdf中的圖像訊息,並寫入word檔案
                # 否則先轉換CMYK
                else:
                    pix0 = fitz.Pixmap(fitz.csRGB, pix)
                    pix0.writePNG(os.path.join(pic_path, 'page%s-%s.png' % (i, xref)))
                    document.add_picture(os.path.join(pic_path, 'page%s-%s.png' % (i, xref)), Pt(400), Pt(200))
                    pix0 = None
                    # 釋放資源
                    pix = None
        document.save(word_path)  # 儲存word檔案

5、取得檔案path函式1(取得單個檔案路徑)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 def get_filepath(self):
        """
        跳出檔案路徑核選框,取得所選擇的單個檔案路徑並寫入到單行文字框中
        """
        try:
            mode = self.window.buttonGroup.checkedButton().text()
            if mode == 'word 轉 pdf':
                filepath, _ = QFileDialog.getOpenFileName(
                    self.window,  # 父視窗物件
                    "選擇上傳檔案",  # 視窗的標題
                    r"C:",  # 起始目錄
                    "word檔案型別 (*.docx *.doc )"  # 選擇型別過濾項,過濾內容在括弧中
                )
                self.window.lineEdit.setReadOnly(False)
                self.window.lineEdit.setText(filepath)
                self.window.lineEdit.setReadOnly(True)
            elif mode == 'pdf 轉 word':
                filepath, _ = QFileDialog.getOpenFileName(
                    self.window,  # 父視窗物件
                    "選擇上傳檔案",  # 視窗的標題
                    r"C:",  # 起始目錄
                    "word檔案型別 (*.pdf)"  # 選擇型別過濾項,過濾內容在括弧中
                )
                self.window.lineEdit.setReadOnly(False)
                self.window.lineEdit.setText(filepath)
                self.window.lineEdit.setReadOnly(True)
        except:
            QMessageBox.critical(self.window, '錯誤提示', '請選擇轉換模式!!!')

5、取得檔案path函式2(取得多個檔案路徑)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    def get_filepaths(self):
        """
        跳出檔案路徑核選框,取得所選擇的多個檔案路徑並寫入到多行文字框中
        """
        try:
            self.list_path = []
            mode = self.window.buttonGroup.checkedButton().text()
            if mode == 'word 轉 pdf':
                filepaths, _ = QFileDialog.getOpenFileNames(
                    self.window,
                    "選擇你要上傳的多個圖像",
                    r"C:",
                    "word檔案型別 (*.docx *.doc )"
                )
                self.window.plainTextEdit.setReadOnly(False)
                self.window.plainTextEdit.clear()
                for word_path in filepaths:
                    self.window.plainTextEdit.appendPlainText(word_path)
                    self.list_path.append(word_path)
                self.window.plainTextEdit.setReadOnly(True)
            elif mode == 'pdf 轉 word':
                filepaths, _ = QFileDialog.getOpenFileNames(
                        self.window,  # 父視窗物件
                        "選擇你要上傳的多個圖像",  # 視窗的標題
                        r"C:",  # 起始目錄
                        "word檔案型別 (*.pdf)"  # 選擇型別過濾項,過濾內容在括弧中
                )
                self.window.plainTextEdit.setReadOnly(False)
                self.window.plainTextEdit.clear()
                for word_path in filepaths:
                    self.window.plainTextEdit.appendPlainText(word_path)
                    self.list_path.append(word_path)
                self.window.plainTextEdit.setReadOnly(True)
        except:
            QMessageBox.critical(self.window, '錯誤提示', '請選擇轉換模式!!!')

6、處理轉化函式1(執行單個word檔案和pdf檔案互轉)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    def create_pdf_word(self):
        """
        執行單個word檔案和pdf檔案互轉
        """
        path = self.window.lineEdit.text()
        if path:
            try:
                mode = self.window.buttonGroup.checkedButton().text()
                if path and (mode == 'word 轉 pdf'):
                    self.window.progressBar.setRange(0, 2)
                    # 設定進度條顯示進度訊息(0-2)對應不同的進度訊息
                    self.window.progressBar.setValue(1)
                    self.word_to_pdf(path)
                    # 設定進度條顯示進度訊息(0-2)對應不同的進度訊息
                    self.window.progressBar.setValue(2)
                    # 將進度條倒退到開頭
                    self.window.progressBar.reset()
                    self.window.lineEdit.clear()
                elif path and (mode == 'pdf 轉 word'):
                    self.window.progressBar.setRange(0, 2)
                    # 設定進度條顯示進度訊息(0-2)對應不同的進度訊息
                    self.window.progressBar.setValue(1)
                    self.pdf_to_word(path)
                    # 設定進度條顯示進度訊息(0-2)對應不同的進度訊息
                    self.window.progressBar.setValue(2)
                    # 將進度條倒退到開頭
                    self.window.progressBar.reset()
                    self.window.lineEdit.clear()
            except:
                QMessageBox.critical(self.window, '錯誤提示', '請選擇轉換模式!!!')
        else:
            QMessageBox.critical(self.window, '錯誤提示', '檔案路徑不能為空!!!')

6、處理轉化函式2(執行多個word檔案和pdf檔案互轉)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    def create_pdfs_wrods(self):
        """
        執行多個word檔案和pdf檔案互轉
        """
        text = self.window.plainTextEdit.toPlainText()
        if text:
            try:
                self.window.progressBar.setRange(0, len(self.list_path))
                mode = self.window.buttonGroup.checkedButton().text()
                if mode == 'word 轉 pdf':
                    i = 1
                    for path in self.list_path:
                        self.word_to_pdf(path)
                        # 設定進度條顯示進度訊息(0-3)對應不同的進度訊息
                        self.window.progressBar.setValue(i)
                        i += 1
                    # 將進度條倒退到開頭
                    self.window.progressBar.reset()
                    self.window.plainTextEdit.clear()
                elif mode == 'pdf 轉 word':
                    i = 1
                    for path in self.list_path:
                        self.pdf_to_word(path)
                        # 設定進度條顯示進度訊息(0-3)對應不同的進度訊息
                        self.window.progressBar.setValue(i)
                        i += 1
                    # 將進度條倒退到開頭
                    self.window.progressBar.reset()
                    self.window.plainTextEdit.clear()
            except:
                QMessageBox.critical(self.window, '錯誤提示', '請選擇轉換模式!!!')
        else:
            QMessageBox.critical(self.window, '錯誤提示', '檔案路徑不能為空!!!')

7、實現開啟從pdf中取得的圖像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    def open_pdf_image(self):
        """
        開啟已取得的pdf中的圖像
        """
        filepath, _ = QFileDialog.getOpenFileName(
            self.window,  # 父視窗物件
            "選擇上傳檔案",  # 視窗的標題
            r"./pdf_word_images",  # 起始目錄
            "word檔案型別 (*.png *.jpg)"  # 選擇型別過濾項,過濾內容在括弧中
        )
        if filepath:
            os.system(f'start {filepath}')
        else:
            pass

完整程式碼

ui檔案下載地址:自提碼(py66)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
from PySide2.QtWidgets import QApplication, QFileDialog, QMessageBox
from PySide2.QtUiTools import QUiLoader
from PySide2.QtCore import QFile
from win32com.client import constants, gencache
import fitz
from docx import Document
from docx.shared import Pt
import os


class WordTransform:

    def __init__(self):
        """
        載入ui檔案,初始化按鈕等觸發事件回應對接執行函式
        """
        file = QFile('./word_ppt.ui')
        file.open(QFile.ReadOnly)
        file.close()
        self.window = QUiLoader().load(file)
        # 設定單行文字框唯讀
        self.window.lineEdit.setReadOnly(True)
        # 設定多行文字框唯讀
        self.window.plainTextEdit.setReadOnly(True)
        # 當按鈕「開啟檔案」被點選觸發事件,執行對應函式
        self.window.pushButton1.clicked.connect(self.get_filepath)
        # 當按鈕「單個轉化」被點選觸發事件,執行對應函式
        self.window.pushButton2.clicked.connect(self.create_pdf_word)
        # 當按鈕「開啟檔案」被點選觸發事件,執行對應函式
        self.window.pushButton3.clicked.connect(self.get_filepaths)
        # 當按鈕「批量轉化」被點選觸發事件,執行對應函式
        self.window.pushButton4.clicked.connect(self.create_pdfs_wrods)
        # 當按鈕「開啟pdf中圖像」被點選觸發事件,執行對應函式
        self.window.pushButton5.clicked.connect(self.open_pdf_image)

    def word_to_pdf(self, path):
        """
        word檔案轉化pdf檔案主功能函式
        """
        pdf_path = path.split('.')[0] + '.pdf'
        word = gencache.EnsureDispatch('Word.Application')
        doc = word.Documents.Open(path, ReadOnly=1)
        # 轉化方法
        doc.ExportAsFixedFormat(pdf_path, constants.wdExportFormatPDF)
        word.Quit()

    def pdf_to_word(self, path):
        """
        pdf檔案轉化word檔案主功能函式
        註:該函式木器中能識別pdf中的純文字和圖像訊息,表格等其他識別不出
        """
        pic_path = './pdf_word_images'
        if not os.path.exists(pic_path):
            os.mkdir(pic_path)
        else:
            pass
        document = Document()
        word_path = path.split('.')[0] + '.docx'
        doc = fitz.open(path)
        for n in range(doc.page_count):
            page = doc.load_page(n)
            document.add_paragraph(page.getText('text'))
        self.window.progressBar.setValue(1)
        for i in range(doc.page_count):
            for image in doc.get_page_images(i):
                xref = image[0]
                pix = fitz.Pixmap(doc, xref)
                if pix.n < 5:
                    pix.writePNG(os.path.join(pic_path, 'page%s-%s.png' % (i, xref)))
                    document.add_picture(os.path.join(pic_path, 'page%s-%s.png' % (i, xref)), Pt(400), Pt(200))
                # 否則先轉換CMYK
                else:
                    pix0 = fitz.Pixmap(fitz.csRGB, pix)
                    pix0.writePNG(os.path.join(pic_path, 'page%s-%s.png' % (i, xref)))
                    document.add_picture(os.path.join(pic_path, 'page%s-%s.png' % (i, xref)), Pt(400), Pt(200))
                    pix0 = None
                    # 釋放資源
                    pix = None
        document.save(word_path)

    def get_filepath(self):
        """
        跳出檔案路徑核選框,取得所選擇的單個檔案路徑並寫入到單行文字框中
        """
        try:
            mode = self.window.buttonGroup.checkedButton().text()
            if mode == 'word 轉 pdf':
                filepath, _ = QFileDialog.getOpenFileName(
                    self.window,  # 父視窗物件
                    "選擇上傳檔案",  # 視窗的標題
                    r"C:UsersAdministratorDesktop2個白嫖檔案",  # 起始目錄
                    "word檔案型別 (*.docx *.doc )"  # 選擇型別過濾項,過濾內容在括弧中
                )
                self.window.lineEdit.setReadOnly(False)
                self.window.lineEdit.setText(filepath)
                self.window.lineEdit.setReadOnly(True)
            elif mode == 'pdf 轉 word':
                filepath, _ = QFileDialog.getOpenFileName(
                    self.window,  # 父視窗物件
                    "選擇上傳檔案",  # 視窗的標題
                    r"C:UsersAdministratorDesktop2個白嫖檔案",  # 起始目錄
                    "word檔案型別 (*.pdf)"  # 選擇型別過濾項,過濾內容在括弧中
                )
                self.window.lineEdit.setReadOnly(False)
                self.window.lineEdit.setText(filepath)
                self.window.lineEdit.setReadOnly(True)
        except:
            QMessageBox.critical(self.window, '錯誤提示', '請選擇轉換模式!!!')

    def get_filepaths(self):
        """
        跳出檔案路徑核選框,取得所選擇的多個檔案路徑並寫入到多行文字框中
        """
        try:
            self.list_path = []
            mode = self.window.buttonGroup.checkedButton().text()
            if mode == 'word 轉 pdf':
                filepaths, _ = QFileDialog.getOpenFileNames(
                    self.window,
                    "選擇你要上傳的多個圖像",
                    r"C:UsersAdministratorDesktop2個白嫖檔案",
                    "word檔案型別 (*.docx *.doc )"
                )
                self.window.plainTextEdit.setReadOnly(False)
                self.window.plainTextEdit.clear()
                for word_path in filepaths:
                    self.window.plainTextEdit.appendPlainText(word_path)
                    self.list_path.append(word_path)
                self.window.plainTextEdit.setReadOnly(True)
            elif mode == 'pdf 轉 word':
                filepaths, _ = QFileDialog.getOpenFileNames(
                        self.window,  # 父視窗物件
                        "選擇你要上傳的多個圖像",  # 視窗的標題
                        r"C:UsersAdministratorDesktop2個白嫖檔案",  # 起始目錄
                        "word檔案型別 (*.pdf)"  # 選擇型別過濾項,過濾內容在括弧中
                )
                self.window.plainTextEdit.setReadOnly(False)
                self.window.plainTextEdit.clear()
                for word_path in filepaths:
                    self.window.plainTextEdit.appendPlainText(word_path)
                    self.list_path.append(word_path)
                self.window.plainTextEdit.setReadOnly(True)
        except:
            QMessageBox.critical(self.window, '錯誤提示', '請選擇轉換模式!!!')

    def create_pdf_word(self):
        """
        執行單個word檔案和pdf檔案互轉
        """
        path = self.window.lineEdit.text()
        if path:
            try:
                mode = self.window.buttonGroup.checkedButton().text()
                if path and (mode == 'word 轉 pdf'):
                    self.window.progressBar.setRange(0, 2)
                    # 設定進度條顯示進度訊息(0-2)對應不同的進度訊息
                    self.window.progressBar.setValue(1)
                    self.word_to_pdf(path)
                    # 設定進度條顯示進度訊息(0-2)對應不同的進度訊息
                    self.window.progressBar.setValue(2)
                    # 將進度條倒退到開頭
                    self.window.progressBar.reset()
                    self.window.lineEdit.clear()
                elif path and (mode == 'pdf 轉 word'):
                    self.window.progressBar.setRange(0, 2)
                    # 設定進度條顯示進度訊息(0-2)對應不同的進度訊息
                    self.window.progressBar.setValue(1)
                    self.pdf_to_word(path)
                    # 設定進度條顯示進度訊息(0-2)對應不同的進度訊息
                    self.window.progressBar.setValue(2)
                    # 將進度條倒退到開頭
                    self.window.progressBar.reset()
                    self.window.lineEdit.clear()
            except:
                QMessageBox.critical(self.window, '錯誤提示', '請選擇轉換模式!!!')
        else:
            QMessageBox.critical(self.window, '錯誤提示', '檔案路徑不能為空!!!')

    def create_pdfs_wrods(self):
        """
        執行多個word檔案和pdf檔案互轉
        """
        text = self.window.plainTextEdit.toPlainText()
        if text:
            try:
                self.window.progressBar.setRange(0, len(self.list_path))
                mode = self.window.buttonGroup.checkedButton().text()
                if mode == 'word 轉 pdf':
                    i = 1
                    for path in self.list_path:
                        self.word_to_pdf(path)
                        # 設定進度條顯示進度訊息(0-3)對應不同的進度訊息
                        self.window.progressBar.setValue(i)
                        i += 1
                    # 將進度條倒退到開頭
                    self.window.progressBar.reset()
                    self.window.plainTextEdit.clear()
                elif mode == 'pdf 轉 word':
                    i = 1
                    for path in self.list_path:
                        self.pdf_to_word(path)
                        # 設定進度條顯示進度訊息(0-3)對應不同的進度訊息
                        self.window.progressBar.setValue(i)
                        i += 1
                    # 將進度條倒退到開頭
                    self.window.progressBar.reset()
                    self.window.plainTextEdit.clear()
            except:
                QMessageBox.critical(self.window, '錯誤提示', '請選擇轉換模式!!!')
        else:
            QMessageBox.critical(self.window, '錯誤提示', '檔案路徑不能為空!!!')

    def open_pdf_image(self):
        """
        開啟已取得的pdf中的圖像
        """
        filepath, _ = QFileDialog.getOpenFileName(
            self.window,  # 父視窗物件
            "選擇上傳檔案",  # 視窗的標題
            r"./pdf_word_images",  # 起始目錄
            "word檔案型別 (*.png *.jpg)"  # 選擇型別過濾項,過濾內容在括弧中
        )
        if filepath:
            os.system(f'start {filepath}')
        else:
            pass


if __name__ == '__main__':
    app = QApplication([])
    new_word = WordTransform()
    new_word.window.show()
    app.exec_()

總結

1、word 轉pdf 還是可以的,可以單個轉,也可以批量轉,還是挺方便的
2、pdf 轉word 目前還不知道怎麼識別pdf中的表格,只能識別文字和圖像,希望有大佬可以指點下,謝謝!
3、目前還沒進去大批量的測試,如果需要可以進行多執行緒來實現