Compare commits

...

2 Commits

4 changed files with 89 additions and 16 deletions

2
.gitignore vendored
View File

@ -4,6 +4,8 @@ __pycache__/
*.py[cod]
*$py.class
config.json
# C extensions
*.so

View File

@ -16,6 +16,12 @@ def clip(value, min_value, max_value):
value = max_value
return value
def parse_workdir(filepath):
workdir = '/'.join('/'.join(filepath.split('\\')).split('/')[:-1])
if workdir == '':
workdir = '.'
return workdir
def crop(args):
infile = args.input
# process filepath
@ -31,9 +37,8 @@ def crop(args):
thresh = args.thresh
# parse working dir.
workdir = '/'.join('/'.join(infile.split('\\')).split('/')[:-1])
if workdir == '':
workdir = '.'
inworkdir = parse_workdir(infile)
outworkdir = parse_workdir(outfile)
if infile.split('.')[-1].lower() in ['ppt', 'pptx']:
# lets process pptx.
@ -46,7 +51,7 @@ def crop(args):
print('convert {0} to {1}'.format(infile, inbase + '.pdf'))
slides.SaveAs(inbase + '.pdf', 32)
slides.close()
powerpoint.Quit()
# powerpoint.Quit()
# read comments.
ppt = Presentation(infile)
slides = ppt.slides
@ -119,7 +124,7 @@ def crop(args):
names = ['{0}_{1}.pdf'.format(outbase, i+1) for i in range(len(pdf))]
if args.names is not None:
names = args.names
namesfile = os.path.join(workdir, names)
namesfile = os.path.join(inworkdir, names)
if os.path.isfile(namesfile) and names.split('.')[-1] == 'txt':
with open(namesfile, 'r', encoding='utf-8') as f:
names = f.read()
@ -131,7 +136,7 @@ def crop(args):
names = [n + '.pdf' if n[:-4] != '.pdf' else n for n in names]
if len(names) < len(pdf):
names += ['{0}_{1}.pdf'.format(outbase, i+1) for i in range(len(names), len(pdf))]
names = [os.path.join(workdir, name) for name in names]
names = [os.path.join(outworkdir, name) for name in names]
for i, (name, page) in enumerate(zip(names, pdf)):
page_pdf = fitz.Document()
page_pdf.insertPDF(pdf, from_page=i, to_page=i)

50
main.py
View File

@ -86,10 +86,34 @@ def parse_and_crop(conf):
# parser.add_argument('--mute', '-m', default=False, action='store_true', help='do not display output file path.')
# args = parser.parse_args()
import os
import json
from ui import Loader
defaults = {
"input": "",
"output": "",
"background_color": "255,255,255",
"border": "0.0",
"zoom": "1.0",
"thresh": "1.0",
"split": "true",
"names": "",
"visual": "false",
"mute": "false"
}
config_path = 'config.json'
if os.path.isfile(config_path):
with open(config_path, 'r', encoding='utf-8') as f:
updater = json.load(f)
defaults.update(updater)
else:
with open(config_path, 'w+', encoding='utf-8') as f:
json.dump(defaults, f, ensure_ascii=False, indent=4)
conf = {
"input": {"name": "源文件", "type": "readfile", "extension": ("PDF & PPT", ".pdf .pptx")},
"output": {"name": "保存路径", "type": "savefile"},
"output": {"name": "保存路径", "type": "savefile", "initial": "output.pdf"},
"background_color": {"name": "背景颜色", "type": "color", "default": "255,255,255"},
"border": {"name": "留白", "type": "str", "default": "0.0"},
"zoom": {"name": "缩放等级", "type": "str", "default": "1.0"},
@ -99,6 +123,28 @@ conf = {
"visual": {"name": "显示裁切框", "type": "str", "default": "false"},
"mute": {"name": "显示保存文件", "type": "str", "default": "false"},
}
introduction = [
"==== 使用说明 ====",
"- 源文件输入的文件可以为PDF或者PPT如果是PPT会首先自动调用PowerPoint将给定的PPT转变为PDF然后进行裁剪PPT裁剪第一次需要调用COM对象因此速度稍慢建议耐心等待裁切一次后速度会恢复到正常水平",
"- 保存路径:保存的文件名,仅适用于非拆分模式。如果留空,则保存路径为源文件所在目录,保存的文件名为\"源文件名_crop.pdf\"",
"- 背景颜色:哪一种颜色会被认为是背景",
"- 留白:不紧贴有效内容裁切,预留一个给定大小的白边。",
"- 缩放等级裁切是基于视觉裁切的因此裁切过程中会首先渲染PDF采用默认值即可更高的缩放会将PDF渲染为更高分辨率的图片从而提高裁剪精度但计算时间也会相应增加。",
"- 阈值:像素值差异多少会被认为是前景。",
"- 拆分:是否将源文件自动拆分为每页一个的单个文件。默认文件名采取下划线+数字命名。如果源文件是PPT且PPT备注不为空则首先采用PPT的备注作为当前页保存的文件名。",
"- 页名称手动指定拆分模式下每一页的名称具有最高优先级用逗号分隔。留空则使用默认的文件名或者PPT中备注的文件名。",
"- 显示裁切框:在右侧的日志区域输出裁切框坐标",
"- 显示保存文件:显示保存的文件名。",
]
help_msg = '\n'.join(introduction)
# write defaults.
for key in defaults:
conf[key]['default'] = defaults[key]
root = tk.Tk()
Loader(master=root, conf=conf, execution=parse_and_crop, title="PDF/PPT自动裁边")
Loader(master=root, conf=conf, execution=parse_and_crop, title="PDF/PPT自动裁边", help_msg=help_msg)
print(help_msg)
root.mainloop()

36
ui.py
View File

@ -29,7 +29,7 @@ def text_on_image(img, text, pos, size=16, color='#000000'):
return img
class Loader(tk.Frame):
def __init__(self, master=None, conf={}, execution=None, title=None):
def __init__(self, master=None, conf={}, execution=None, title=None, help_msg=None):
super().__init__(master)
self.master = master
self.conf = conf
@ -44,7 +44,7 @@ class Loader(tk.Frame):
# self.font = tk.Font(family='', size=40,weight='',slant='',underline='',overstrike='')
if self.title is not None:
self.master.title(self.title)
self.help_msg = help_msg
def add_resource(self, obj, name):
if name in self.resources:
print('Name [{0}] Repeated.'.format(name))
@ -137,6 +137,12 @@ class Loader(tk.Frame):
conf[name] = self.resources[key].get()
self.execution(conf)
def clear(self):
self.resources['textbox_log'].delete("1.0", 'end')
def showhelp(self):
print(self.help_msg)
def create_widgets(self):
self.rowcount = 0
for key, value in self.conf.items():
@ -153,7 +159,7 @@ class Loader(tk.Frame):
destination = 'entry_' + key
if dtype in ['readfile', 'savefile', 'directory']:
extension = value.get('extension', None)
initialfile = default
initialfile = value.get('initial', None)
args = {
"dst": destination,
"choose_type": dtype,
@ -161,7 +167,7 @@ class Loader(tk.Frame):
"initial_file": initialfile
}
self.add_button(
text="选择文件",
text="<选择文件",
command=lambda args=args:self.choose_file(**args),
size=(16, 16),
layout={"row":self.rowcount, "column": 2, "padx": 5},
@ -171,7 +177,7 @@ class Loader(tk.Frame):
self.conf[key]['type'] = 'str'
elif dtype == 'color':
self.add_button(
text="选择颜色",
text="<选择颜色",
command=lambda dst=destination:self.choose_color(dst),
size=(16, 16),
layout={"row":self.rowcount, "column": 2, "padx": 5},
@ -181,15 +187,29 @@ class Loader(tk.Frame):
self.rowcount += 1
self.add_button(
text=" 裁剪 ",
text="清空输出>",
command=self.clear,
size=(16, 16),
layout={"row":self.rowcount-2, "column": 2, "pady": 5, "sticky": "e"},
name='clear_output'
)
self.add_button(
text="显示帮助>",
command=self.showhelp,
size=(16, 16),
layout={"row":self.rowcount-1, "column": 2, "pady": 5, "sticky": "e"},
name='show_help'
)
self.add_button(
text=" 开始裁剪 ",
command=self.execute,
size=(16, 16),
layout={"row":self.rowcount, "column": 0, "columnspan": 2, "pady": 5},
layout={"row":self.rowcount, "column": 0, "columnspan": "3", "pady": 5},
name='execute_final'
)
self.add_textbox(
width=40,
layout={"row":0, "column": 3, "rowspan": self.rowcount, "padx": 5, "pady": 0},
layout={"row":0, "column": 3, "rowspan": self.rowcount + 1, "padx": 5, "pady": 5, "sticky": "ns"},
name="textbox_log"
)
sys.stdout = StdSimulator(self.resources['textbox_log'])