# -*-coding:utf-8 -* import tkinter as tk from tkinter import filedialog from tkinter import messagebox from tkinter import ttk from pdfembannersrc.wmark import Wmark import configparser from subprocess import Popen, CalledProcessError from pdfembannersrc import strings from pdfembannersrc import subwindows import shlex import os.path import random import logging import PyPDF2 logger = logging.getLogger() class Interface(tk.Toplevel): """ Main window """ def __init__(self, parent, **kwargs): tk.Toplevel.__init__(self, parent) self.transient(parent) self.grab_set() self.title("PDF Embanner : watermark") self.geometry("800x400") self.protocol("WM_DELETE_WINDOW", self.close) self.bind("", self.close) self.bind("", self.open) self.bind("", self.open_markfile) self.bind("", self.saveas) self.bind("", self.editmetadata) self.bind("", self.add) self.bind("", self.do) self.file = None self.npages=0 self.box=None self.markfile = None self.save_file = None self.wmarks = [] self.output_produced=False self.metadata = {'/Title': '', '/Author': '', '/Subject': '', '/Creator': 'PDF Embanner'} self.f = tk.Frame(self, width=768, height=576, **kwargs) self.f.pack(fill=tk.BOTH) # Création de nos widgets self.f.columnconfigure(1, weight=1) self.f.rowconfigure(8, weight=1) tk.Button(self.f, text="Open", command=self.open).grid(row=0, column=0) tk.Button(self.f, text="Close", command=self.close).grid(row=0, column=4, sticky=tk.E) self.file_label = tk.Label(self.f, text="-" if self.file is None else self.file) self.file_label.grid(row=0, column=1, columnspan=4, sticky=tk.W) ttk.Separator(self.f, orient="horizontal").grid(row=1, column=0, columnspan=6, sticky=tk.W+tk.E, padx=5, pady=5) tk.Label(self.f, text="Watermark with an other PDF", bg="blue", fg="white", padx=20).grid(row=2, column=0, columnspan=5, sticky=tk.W) tk.Button(self.f, text="File", command=self.open_markfile).grid(row=3, column=0) self.markfile_label = tk.Label(self.f, text="-" if self.markfile is None else self.markfile) self.markfile_label.grid(row=3, column=1, columnspan=2, sticky=tk.W) tk.Label(self.f, text="Select pages").grid(row=3, column=3, sticky=tk.W) self.select_page_markfile = tk.StringVar() tk.Entry(self.f, textvariable=self.select_page_markfile).grid(row=3, column=4) self.all_pages_markfile = tk.IntVar() self.all_pages_markfile.set(0) tk.Radiobutton(self.f, text="Apply on first page(s) only", variable=self.all_pages_markfile, value=0).grid(row=4, column=0, columnspan=2, sticky=tk.W) tk.Radiobutton(self.f, text="Apply on all pages", variable=self.all_pages_markfile, value=1).grid(row=5, column=0, columnspan=2, sticky=tk.W) self.markfile_bottom = tk.IntVar() self.markfile_bottom.set(0) tk.Radiobutton(self.f, text="Apply on top", variable=self.markfile_bottom, value=0).grid(row=4, column=2, columnspan=3, sticky=tk.W) tk.Radiobutton(self.f, text="Apply on bottom", variable=self.markfile_bottom, value=1).grid(row=5, column=2, columnspan=3, sticky=tk.W) ttk.Separator(self.f, orient="horizontal").grid(row=6, column=0, columnspan=6, sticky=tk.W+tk.E, padx=5, pady=5) tk.Label(self.f, text="Text watermark", bg="blue", fg="white", padx=20).grid(row=7, column=0, columnspan=5, sticky=tk.W) tk.Button(self.f, text="Add", command=self.add).grid(row=7, column=4) vsb = tk.Scrollbar(self.f, orient=tk.VERTICAL) vsb.grid(row=8, column=5, sticky=tk.N+tk.S) self.c = tk.Canvas(self.f,yscrollcommand=vsb.set) self.c.grid(row=8, column=0, columnspan=5, sticky="news") vsb.config(command=self.c.yview) self.frame_wmark = tk.Frame(self.c) self.c.create_window(0, 0, window=self.frame_wmark, anchor=tk.NW) self.frame_wmark.update_idletasks() self.c.config(scrollregion=self.c.bbox("all")) self.frame_wmark.columnconfigure(3, weight=1) ttk.Separator(self.f, orient="horizontal").grid(row=9, column=0, columnspan=6, sticky=tk.W+tk.E, padx=5, pady=5) tk.Button(self.f, text="Save as", command=self.saveas).grid(row=10, column=0) self.save_label = tk.Label(self.f, text="-" if self.save_file is None else self.save_file) self.save_label.grid(row=10, column=1, columnspan=3, sticky=tk.W) tk.Button(self.f, text="Metadata", command=self.editmetadata).grid(row=10, column=4, sticky=tk.E) tk.Button(self.f, text="Generate PDF", fg="blue", command=self.do).grid(row=11, column=3, columnspan=3, sticky=tk.E) self.message = tk.Label(self.f, text="Welcome !") self.message.grid(row=12, column=0, columnspan=6, sticky=tk.W) def add(self, *args): """ Add watermark """ wm = Wmark(None) i = len(self.wmarks) self.wmarks.append(wm) wm.add_widgets(self.frame_wmark, self, i) self.frame_wmark.update_idletasks() self.c.config(scrollregion=self.c.bbox("all")) self.message["text"] = "Added watermark" def do(self, *args): """ Do watermarking with correct options ! """ if(self.file is None): messagebox.showwarning(title="PDF Output", message="Please open an input PDF file before !") return elif(self.save_file is None): messagebox.showwarning(title="PDF Output", message="Please define the 'Save As' path before !") return if(len(self.wmarks)>0): # Generate PDF for watermarking with Latex err, use_pages_generated, pdfgeneratedname = generate_pdf(self.wmarks, self.save_file, self.npages) if(err>0 and err<100): self.message["text"] = "Error : no output generated" if(err==1): logger.error("Watermark :: Could not write in output folder") messagebox.showerror(title="PDF Output", message="Could not write in output folder") elif(err==2): logger.error("Watermark :: Could not parse compiler config file") messagebox.showerror(title="PDF Output", message="Could not parse compiler config file") elif(err==3): logger.error("Watermark :: No latex compiler found") messagebox.showerror(title="PDF Output", message="No latex compiler found. Check your compiler.conf file") elif(err==4): logger.error("Watermark :: Latex compilation error") messagebox.showerror(title="PDF Output", message="Latex compilation error. You may have put an incorrect caracter in text area.") elif(err==5): logger.error("Watermark :: IOError during compilation") messagebox.showerror(title="PDF Output", message="IOError during compilation. Check rights on output folder.") return elif(err==100): logger.info("Watermark :: There were errors in your page ranges. Some page ranges not taken in consideration.") messagebox.showinfo(title="PDF Output", message="There were errors in your page ranges. Some page ranges not taken in consideration.") genpdf=True else: genpdf=False logger.debug("Genpdf is set to {}".format(genpdf)) if(self.markfile is not None): try: self.message["text"] = "Opening {}".format(self.markfile) with open(self.markfile, "rb") as in_f: input2 = PyPDF2.PdfFileReader(in_f) markf_npages = input2.getNumPages() correct, use_pages_markf = parse_range(self.select_page_markfile.get(), markf_npages) if(not correct): messagebox.showerror(title="Watermark file", message="Incorrect 'Select page' range. Please correct it!".format(self.markfile)) return if(len(use_pages_markf)==0): use_pages_markf = list(range(1,markf_npages+1)) except (PyPDF2.utils.PdfReadError, EOFError, IOError, NotImplementedError): self.message["text"] = "Failed to open {}".format(self.markfile) messagebox.showerror(title="PDF Open", message="Impossible to read PDF input file ! {}".format(self.markfile)) logger.warning("Wartermark : Error while opening {}".format(self.markfile)) return markf = True else: markf=False use_pages_markf = [] logger.debug("Markf is set to {} with pages {}".format(markf, use_pages_markf)) genpdf_f = None markf_f = None try: if(markf): markf_f = open(self.markfile, 'rb') input_mark = PyPDF2.PdfFileReader(markf_f) if(genpdf): genpdf_f = open(pdfgeneratedname, 'rb') input_gen = PyPDF2.PdfFileReader(genpdf_f) output = PyPDF2.PdfFileWriter() with open(self.file,'rb') as in_f: input_ref = PyPDF2.PdfFileReader(in_f) for i in range(self.npages): # Adding i-th page ! if(markf and (self.all_pages_markfile.get()==1 or i0 and int(e[0])0 and i0 and i0 and i0): return erreurs+1, None, None return err, use_pages_generated, pdfgeneratedname def wmbypage(wmarks, npages): """ Return a list indexed by page number (from 0 to npages-1) in which element i is a list of Wmark to put on the i+1 page. """ ret = [] correct = True for i in range(npages): ret.append([]) for m in wmarks: correct1, onlyp = parse_range(m.onlypages, npages) correct2, notp = parse_range(m.notpages, npages) correct = correct and correct1 and correct2 if((1 not in notp and m.onlyfirstpage) or (1 in onlyp) or (len(onlyp)==0 and not m.onlyfirstpage and not m.onlylastpage and 1 not in notp)): ret[0].append(m) for i in range(1,npages-1): if((i+1 not in notp and len(onlyp)==0 and not m.onlyfirstpage and not m.onlylastpage) or (i+1 in onlyp)): ret[i].append(m) if((npages not in notp and m.onlylastpage) or (npages in onlyp) or (len(onlyp)==0 and not m.onlyfirstpage and not m.onlylastpage and npages not in notp)): ret[-1].append(m) return correct, ret def genpagetex(wmarks): """ Return a string to be inserted in tex file to generate one page with marks given in wmarks (list of Wmark) """ headrule = False footrule = False lhead =[] chead =[] rhead =[] lfoot =[] cfoot =[] rfoot =[] custom = [] for m in wmarks: if(m.position==strings.topleft): lhead.append(m.format_tex()) elif(m.position==strings.topcenter): chead.append(m.format_tex()) elif(m.position==strings.topright): rhead.append(m.format_tex()) elif(m.position==strings.botleft): lfoot.append(m.format_tex()) elif(m.position==strings.botcenter): cfoot.append(m.format_tex()) elif(m.position==strings.botright): rfoot.append(m.format_tex()) elif(m.position==strings.custom): custom.append([m.userposition, m.format_tex()]) else: rhead.append(m.format_tex()) if(m.lined and m.position in [strings.top]): headrule = True elif(m.lined and m.position in [strings.bot]): footrule = True s = "\n\\newpage" s += "\n\\lhead{" + ' '.join(lhead) + "}" s += "\n\\chead{" + ' '.join(chead) + "}" s += "\n\\rhead{" + ' '.join(rhead) + "}" s += "\n\\lfoot{" + ' '.join(lfoot) + "}" s += "\n\\cfoot{" + ' '.join(cfoot) + "}" s += "\n\\rfoot{" + ' '.join(rfoot) + "}" if(headrule): s += "\n\\renewcommand{\\headrulewidth}{0.4pt}" else: s += "\n\\renewcommand{\\headrulewidth}{0pt}" if(footrule): s += "\n\\renewcommand{\\footrulewidth}{0.4pt}" else: s += "\n\\renewcommand{\\footrulewidth}{0pt}" for e in custom: s += "\n\\begin{textblock}{1}"+"({},{})".format(e[0][0]*21, e[0][1]*29.7) s += "\n" + e[1] s += "\n\\end{textblock}" s += "\n\\null\n" return s def compiletex(texoutname, deletetex=False, deletetemp=True): """ Compile the tex file texoutname Rerurns : error number, pdf_filename error number : 0 : No error 1 : Could not parse config file 2 : No compiler available 3 : Error during compilation 4 : IOError """ err = 0 pdfgeneratedname = texoutname[:-4] + ".pdf" curdir = os.getcwd() os.chdir(os.path.dirname(texoutname)) texbasename = os.path.basename(texoutname) try: config = configparser.ConfigParser() config.read('pdfembannersrc/compiler.conf') except configparser.Error: logger.error("Watermark :: configparser failed to parse compiler.conf") return 1, None for compiler in config.sections(): if 'cmd' not in config[compiler]: logger.error("Watermark :: cmd entry not found for compiler {}".format(compiler)) return 1, None cmd1 = config[compiler]['cmd'] if 'args' in config[compiler]: cmd1 += ' ' + config[compiler]['args'] cmd1+=' '+texbasename cmd = shlex.split(cmd1) try: logger.debug("Try {}".format(cmd1)) p = Popen(cmd) p.wait() p = Popen(cmd) p.wait() if(p.returncode>0): logger.error("Watermark :: Latex Error") return 3, None logger.info("Watermark :: Compiled successfully with {}".format(cmd1)) break # On a trouve le bon compilo except OSError: logger.warn("Watermark :: Failed to compile with {}. Compiler not found.".format(cmd1)) continue except ValueError: logger.warn("Watermark :: Failed to compile with {}. Value Error.".format(cmd1)) continue except CalledProcessError: return 3, None except IOError: logger.error("Watermark :: IOError during compilation") return 4, None else: logger.error("Watermark :: No latex compilater found after trying all!") return 2, None # Delete temp files if(deletetemp): if('clean_ext' in config[compiler]): for ext in config[compiler]['clean_ext'].split(): todel = texoutname[:-4]+'.'+ext logger.debug("Trying to del {}".format(todel)) if(os.path.exists(todel)): try: os.remove(todel) except (OSError, IOError): logger.error("Watermark :: Error while deleting {}".format(todel)) # Delete tex file if(deletetex): try: os.remove(texoutname) except (OSError, IOError): logger.error("Error while deleting {}".format(texoutname)) os.chdir(curdir) return err, pdfgeneratedname