- Сообщения
- 14,053
- Решения
- 1
- Реакции
- 5,745
Всем привет.
Поступила вот такая интересная задача - "сделать программу что бы удобно было файлы конвертировать и точно без вирусов".
Это и есть основная программа.
Далее потребовалось, что бы все это запускалось по расписанию, само решало какие файлы надо конвертировать и - внимание - отправлять в нужные чаты в аське, ой, mail.agent.
Зачем? Да лучше не спрашивайте))
Это стало, собственно, второй задачей и второй программой. Для этой второй задачи я написал бота для mail.agent и он там уже должен успешно рулить процессом, в общем.
Болталку к нему не прикручивал - хотя теперь стало интересно и болталку сделать.
Вернемся к изначальной теме теперь.
Вот так конвертер по итогу у меня сейчас выглядит:
Неказисто, но практично)
Кому лень или не хочется читать о том, как это сделано - внизу темы исходники. Можно пользоваться сразу - кому надо, могут сразу упаковать в EXE, я это делаю вот этой штукой:
Python exe packer - программа для сборки скриптов Python в exe файлы 1.1.0
Итак, для работы программы нам потребуются следующие библиотеки:
Что то идет из коробки, что то надо установить. Тем, кто пользуется 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 выделен отдельным блоком и хорошо читается - но если у кого то возникнут вопросы, то без проблем отвечу на них.
В остальном же идея предельно проста: когда пользователь с помощью кнопок и комбобоксов выставил нужные параметры, то просто жмет кнопку "Выполнить".
Для бота я делал небольшие изменения - ему кнопка не нужна, так что он использует программу как импортируемый модуль.
Именно поэтому здесь так важно проверять, как именно запущена программа - за это отвечает код в строке:
Дословно - если программу запускает пользователь, то идет загрузка всего интерфейса и юзеру больше ни о чем думать не надо)
После нажатия заветной кнопки "Выполнить" мы стартуем функцию run_all, которая перебирает файлы по заданным параметрам и передает их в остальные функции для обработки.
Если выбран каталог - берутся все файлы с нужным расширением, если отдельные файлы - поочередно обрабатывается то, что выбрал пользователь.
Большинство преобразований можно было произвести с помощью win32com, но вот с картинками пришлось повозиться... и пилить отдельную функцию pdf_jpg.
Да, цифра в pages - это количество точек на выходе, так что вес файла можно отрегулировать под себя.
О результатах работы мы узнаем из информационного окна.
Это, собственно и все - если кому то еще, кроме меня это будет полезным, то я буду доволен))
Поступила вот такая интересная задача - "сделать программу что бы удобно было файлы конвертировать и точно без вирусов".
Это и есть основная программа.
Далее потребовалось, что бы все это запускалось по расписанию, само решало какие файлы надо конвертировать и - внимание - отправлять в нужные чаты в аське, ой, mail.agent.
Зачем? Да лучше не спрашивайте))
Это стало, собственно, второй задачей и второй программой. Для этой второй задачи я написал бота для mail.agent и он там уже должен успешно рулить процессом, в общем.
Болталку к нему не прикручивал - хотя теперь стало интересно и болталку сделать.
Вернемся к изначальной теме теперь.
Вот так конвертер по итогу у меня сейчас выглядит:
Неказисто, но практично)
Кому лень или не хочется читать о том, как это сделано - внизу темы исходники. Можно пользоваться сразу - кому надо, могут сразу упаковать в 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 - это количество точек на выходе, так что вес файла можно отрегулировать под себя.
О результатах работы мы узнаем из информационного окна.
Это, собственно и все - если кому то еще, кроме меня это будет полезным, то я буду доволен))
Вложения
Последнее редактирование: