Пишем конвертер word файлов в разные форматы - JPEG, HTML, PDF и прочие

Кирилл

Команда форума
Администратор
Ассоциация VN
Сообщения
14,053
Решения
1
Реакции
5,745
Всем привет.
Поступила вот такая интересная задача - "сделать программу что бы удобно было файлы конвертировать и точно без вирусов".
Это и есть основная программа.

Далее потребовалось, что бы все это запускалось по расписанию, само решало какие файлы надо конвертировать и - внимание - отправлять в нужные чаты в аське, ой, mail.agent.
Зачем? Да лучше не спрашивайте))

Это стало, собственно, второй задачей и второй программой. Для этой второй задачи я написал бота для mail.agent и он там уже должен успешно рулить процессом, в общем.
Болталку к нему не прикручивал - хотя теперь стало интересно и болталку сделать.
Вернемся к изначальной теме теперь.

Вот так конвертер по итогу у меня сейчас выглядит:

1583597291464.png


Неказисто, но практично)
Кому лень или не хочется читать о том, как это сделано - внизу темы исходники. Можно пользоваться сразу - кому надо, могут сразу упаковать в EXE, я это делаю вот этой штукой:
Python exe packer - программа для сборки скриптов Python в exe файлы 1.1.0

Итак, для работы программы нам потребуются следующие библиотеки:

  • tkinter, ttk
  • os
  • win32com
  • pdf2image
  • poppler

Что то идет из коробки, что то надо установить. Тем, кто пользуется Anaconda будет полегче.

Вот, собственно, и сам код:

[CODE lang="python" title="Word format converter"]# -*- coding: utf-8 -*-
"""
word file converter
url: safezone.cc
@author: Кирилл
"""

from tkinter import ttk
from tkinter import filedialog as fd
import os
import win32com.client
from pdf2image import convert_from_path

'''
Для работы программы требуются библиотеки:
tkinter, ttk
os, win32com
pdf2image, poppler
list format files:
https://docs.microsoft.com/ru-ru/office/vba/api/word.wdsaveformat

{'wdFormatDOSText':4, # Microsoft DOS text format.
'wdFormatEncodedText':7, # Encoded text format.
'wdFormatHTML':8, # Standard HTML format
'wdFormatUnicodeText':7, # Unicode text format
'wdFormatPDF':17, # PDF format
}
'''

format_file = {'HTML': 8, 'PDF': 17, 'JPG': 'JPG', 'text_unicode': 7}


class FormConvert(ttk.Frame):

def __init__(self, root):
self.root = root
self.root.geometry('600x500')
self.default_path = 'Выберите каталог или файлы...'
self.entry_text_input = ttk.tkinter.StringVar()
self.entry_text_output = ttk.tkinter.StringVar()
self.log_text = ttk.tkinter.StringVar()
self.input_folder = ''

def navigation(self):
'''
Метод для создания элементов управления на форме и
обращения к ним
'''

self.lb = ttk.Label(root, text='Что будете конвертировать?')
self.lb.place(x=10, y=25)

###################################################################

# Радиокнопка выбора файл / папка с файлами
self.combo_menu = ttk.Combobox(root, values=[
u"Все файлы в каталоге",
u"Один или несколько файлов"],
height=3, width=30,
state='readonly')

self.combo_menu.set(u"Все файлы в каталоге")
self.combo_menu.place(x=10, y=50)
self.combo_menu.bind('<<ComboboxSelected>>', self.change_combo)

###################################################################

# Текстовое поле с указанием пути к исходным файлам
self.text_path_input = ttk.Entry(root,
textvariable=self.entry_text_input,
state='disabled',)
self.text_path_input.place(x=10, y=80, width=300, height=25)
# Пишем каталог по умолчанию в текстовое поле
self.entry_text_input.set(self.default_path)

# Кнопка выбора с указанием пути к исходным файлам
self.bt_dialog_input = ttk.Button(text='Выбрать ...')
self.bt_dialog_input.place(x=310, y=80, height=25,)
self.bt_dialog_input.bind('<Button-1>', self.file_dialog_input)

###################################################################

# Текстовое поле с указанием пути сохранения файла
self.text_path_output = ttk.Entry(root,
textvariable=self.entry_text_output,
state='disabled',)
self.text_path_output.place(x=10, y=110, width=300, height=25)
# Пишем каталог по умолчанию в текстовое поле
self.entry_text_output.set('Укажите, где сохранить файлы...')

# Кнопка выбора каталога или файла
self.bt_dialog_output = ttk.Button(text='Выбрать ...')
self.bt_dialog_output.place(x=310, y=110, height=25,)
self.bt_dialog_output.bind('<Button-1>', self.file_dialog_output)

###################################################################

# Радиокнопка выбора типа файла на выходе
self.combo_type = ttk.Combobox(root, values=[
u"Конвертировать в JPG",
u"Конвертировать в PDF",
u"Конвертировать в HTML", ],
height=3, width=30,
state='readonly')

self.combo_type.set(u"Конвертировать в JPG")
self.combo_type.place(x=10, y=140)
self.combo_type.bind('<<ComboboxSelected>>', self.change_combo)

###################################################################

# Текстовое поле общего назначения
self.text_log = ttk.tkinter.Text(root)
self.text_log.place(x=10, y=180,
relwidth=0.95, relheight=0.7)

###################################################################

# Кнопка выполнить
self.bt_run_ = ttk.Button(text='Выполнить')
self.bt_run_.place(x=505, y=140, height=40,)
self.bt_run_.bind('<Button-1>', run_all)

def file_dialog_input(self, event):
# Кнопка "Выбрать..." - исходные файлы
if self.combo_menu.get() == u"Все файлы в каталоге":
self.input_folder = fd.askdirectory()
else:
self.input_folder = fd.askopenfilenames(defaultextension='.docx',
filetypes=[
('Word files',
('*.docx', '*.doc')), ],
multiple=True)
self.entry_text_input.set(self.input_folder)

def file_dialog_output(self, event):
# Кнопка "Выбрать..." - папка для сохранения файлов
self.output_folder = fd.askdirectory()
self.entry_text_output.set('Save to: ' + self.output_folder)

def change_combo(self, event):
print(event.widget.get())
return event.widget.get()

############################### END CLASS #####################################


def pdf_jpg(file):
pages = convert_from_path(file, 500)
for page in pages:
try:
page.save(file[:-8] + '.jpeg', 'JPEG')
except:
MyApp.text_log.insert('end', os.path.basename(file) + ' Отказ' + '\n')
MyApp.text_log.insert('end', os.path.basename(file)[:-8] + '.jpeg' + ' --> Успех' + '\n')
os.remove(file)


def is_word(file):
type_file = MyApp.combo_type.get().split()[-1]
if file.lower().endswith('.docx'):
return MyApp.output_folder + '/' + file[:-5] + '.' + type_file
if file.lower().endswith('.doc'):
return MyApp.output_folder + '/' + file[:-4] + '.' + type_file


def convert(subdir, file, save_file):
'''
Функция принимает в качестве параметров текущий каталог
и имя исходного файла, путь и формат файла на выходе, а так же
вычисляет соответствующий номер требуемого формата для
конвертации файла.
'''

word = win32com.client.Dispatch('Word.Application')
word.Visible = 0

doc = word.Documents.Open(os.path.abspath(subdir + '//' + file))
if format_file[MyApp.combo_type.get().split()[-1]] == 'JPG':
doc.SaveAs(os.path.abspath(save_file[:-4]+'_tmp.pdf'), FileFormat=17)
save_file = save_file[:-4]+'_tmp.pdf'
else:
try:
doc.SaveAs(os.path.abspath(save_file), FileFormat=format_file[
MyApp.combo_type.get().split()[-1]])
MyApp.text_log.insert('end', file + ' --> ' + '\n --> ' + os.path.basename(save_file))
MyApp.text_log.insert('end', ' : Успех' + '\n')
except:
MyApp.text_log.insert('end', os.path.basename(file) + 'Отказ' + '\n')

doc.Close()
word.Quit()
if format_file[MyApp.combo_type.get().split()[-1]] == 'JPG':
pdf_jpg(save_file)


def run_all(event):
if not MyApp.text_path_input.get().endswith('...'):
if not MyApp.text_path_output.get().endswith('...'):
if MyApp.combo_menu.get() == 'Все файлы в каталоге':
for subdir, dirs, files in os.walk(MyApp.text_path_input.get()):
for file in files:
if not file.startswith('~$'):
save_file = is_word(file)
if save_file:
convert(subdir, file, save_file)

else:
for file in MyApp.input_folder:
save_file = is_word(os.path.basename(file))
convert(os.path.dirname(file), os.path.basename(file),
save_file)


if __name__ == '__main__':
root = ttk.tkinter.Tk()
root.title('Word format converter')
root.resizable(0, 0)
MyApp = FormConvert(root)
MyApp.navigation()
root.mainloop()
[/CODE]

Как обычно, все основные элементы управления на форме я упаковал в класс - при дальнейшей модернизации программы это сильно облегчает жизнь.

Сам класс FormConvert выделен отдельным блоком и хорошо читается - но если у кого то возникнут вопросы, то без проблем отвечу на них.

В остальном же идея предельно проста: когда пользователь с помощью кнопок и комбобоксов выставил нужные параметры, то просто жмет кнопку "Выполнить".
Для бота я делал небольшие изменения - ему кнопка не нужна, так что он использует программу как импортируемый модуль.

Именно поэтому здесь так важно проверять, как именно запущена программа - за это отвечает код в строке:

if __name__ == '__main__':

Дословно - если программу запускает пользователь, то идет загрузка всего интерфейса и юзеру больше ни о чем думать не надо)

После нажатия заветной кнопки "Выполнить" мы стартуем функцию run_all, которая перебирает файлы по заданным параметрам и передает их в остальные функции для обработки.
Если выбран каталог - берутся все файлы с нужным расширением, если отдельные файлы - поочередно обрабатывается то, что выбрал пользователь.
Большинство преобразований можно было произвести с помощью win32com, но вот с картинками пришлось повозиться... и пилить отдельную функцию pdf_jpg.
Да, цифра в pages - это количество точек на выходе, так что вес файла можно отрегулировать под себя.
О результатах работы мы узнаем из информационного окна.

Это, собственно и все - если кому то еще, кроме меня это будет полезным, то я буду доволен))
 

Вложения

Последнее редактирование:
Назад
Сверху Снизу