Di era transisi ke alur kerja digital, kasus-kasus lucu muncul ketika digitalisasi tampaknya ada, tetapi tampaknya tidak. Salah satu kasusnya adalah ketika karyawan mencetak kontrak yang dikirim melalui email, membubuhkan faksimili atau stempel pada hasil cetak, kemudian memindai dan mengirimkannya kembali.
Untuk memperbaiki kesalahpahaman ini, menurut saya mungkin dalam dua cara: dengan beralih ke tanda tangan digital, yang akan memerlukan perubahan alur kerja untuk kedua belah pihak, atau dengan memasukkan gambar cetak secara terprogram. Mengingat ketidakmungkinan mempengaruhi alur kerja klien, saya harus menggunakan cara kedua, memasukkan gambar secara terprogram ke dalam dokumen.
Ada banyak program untuk bekerja dengan pdf, tetapi memasukkan gambar ke dalamnya berbayar atau terbatas. Tugas saat ini membutuhkan kemampuan tak terbatas untuk mengedit dokumen dan antarmuka yang paling sederhana sehingga siapa pun dapat segera menggunakan program ini tanpa pelatihan apa pun.
Jadi, saya memutuskan untuk menulis aplikasi saya untuk memasukkan gambar ke dalam pdf yang memenuhi semua persyaratan di atas. Dan karena ukuran aplikasi dan kecepatan kerja (dalam alasan!) Bukan kunci, menurut saya optimal untuk menulis aplikasi dengan python dan kemudian membungkusnya dalam file yang dapat dieksekusi.
Jadi, aplikasinya. Untuk membuat antarmuka grafis, modul tkinter digunakan, karena dikuasai "on the fly", dan tampilan aplikasi dikorbankan demi kecepatan pengembangan. Jadi hal seperti ini terjadi:
: . - pdf, . poppler - pdf2image, convert_from_path pdf . , , ( 768*768 ) . = / max( , ). , . :
. pdf reportlab, , pdf , , , . pdf , pdf, PIL, , . : ( ), tkinter- 'coord' , . ( paste PIL Image). .
, python . pyinstaller, python . : - pdf poppler, exe , exe . -noconsole , . , :
from tkinter import *
from tkinter import filedialog
from PIL import ImageTk, Image
from pathlib import Path
from pdf2image import convert_from_path
import os
canvas_size = 768
document_type = (("document file", "*.jpg *.jpeg *.pdf"),
("pdf files", "*.pdf"), ("image files", "*.jpg *.jpeg"))
sign_type = (("stamp file","*.png"),)
class DocCanv(Canvas):
#Document
DocumentList=None
DocumentImage = None
DocResize = 1
DocImgLink = None
CurentPage=0
#Signature
SignImage = None
SignResize = DocResize
SignImgLink = None
SignObj = None
def DocFile(self, use_in_func=False):
if use_in_func is False:
doc_path = filedialog.askopenfilename(filetypes=document_type)
if (Path(doc_path).suffix).lower() == '.pdf':
try:
#try to use poppler from pyinstaller bundle temp directory
self.DocumentList=convert_from_path(doc_path, poppler_path = os.path.join(sys._MEIPASS, "poppler") )
except:
#reserve for poppler
self.DocumentList=convert_from_path(doc_path, poppler_path = "poppler" )
self.DocumentImage=self.DocumentList[0]
else:
self.DocumentImage = Image.open(doc_path)
self.DocumentList = [self.DocumentImage]
(width, height) = self.DocumentImage.size
self.DocResize = canvas_size / max(height, width)
self.DocImgLink=ImageTk.PhotoImage(
self.DocumentImage.resize((int(width * self.DocResize), int(height * self.DocResize)), Image.ANTIALIAS))
self.create_image(0, 0, image=self.DocImgLink, anchor=NW)
def SignFile(self, sign_path=None):
if self.SignImage is not None:
self.MergeFile()
self.DocFile(True)
if sign_path is None:
sign_path = filedialog.askopenfilename(filetypes = sign_type)
self.SignImage = Image.open(sign_path)
(width, height) = self.SignImage.size
self.SignResize=self.DocResize
self.SignImgLink=ImageTk.PhotoImage(
self.SignImage.resize((int(width * self.SignResize), int(height * self.SignResize)), Image.ANTIALIAS))
self.SignObj = self.create_image(0, 0, image=self.SignImgLink, anchor=NW)
def MoveSign(self, event):
self.coords(self.SignObj, event.x, event.y)
def ResizeSign(self, event):
if event.delta > 0:
self.SignResize = self.SignResize + 0.1
else:
self.SignResize = self.SignResize - 0.1
(width, height) = self.SignImage.size
self.SignImage.resize((int(width * self.SignResize), int(height * self.SignResize)), Image.ANTIALIAS)
self.SignImgLink=ImageTk.PhotoImage(
self.SignImage.resize((int(width * self.SignResize), int(height * self.SignResize)), Image.ANTIALIAS) )
x, y = self.coords(self.SignObj)
self.SignObj = self.create_image(x, y, image=self.SignImgLink, anchor=NW)
def MergeFile(self):
sign_coords =self.coords(self.SignObj)
sign_coords = [(int)(x / self.DocResize) for x in sign_coords]
(width, height) = self.SignImage.size
width=int((width * self.SignResize)/self.DocResize)
height=int((height * self.SignResize) / self.DocResize)
ResizedSign=self.SignImage.resize((width,height), Image.ANTIALIAS)
self.DocumentImage.paste(ResizedSign, box=sign_coords , mask=ResizedSign.convert('RGBA'))
def SaveFile(self,f_type="jpg"):
try:
self.MergeFile()
except:
pass
SavePath=filedialog.asksaveasfilename()
if (SavePath.split('.'))[-1]!=f_type:
SavePath=(SavePath.split('.'))[0]+'.'+f_type
if f_type == 'pdf':
self.DocumentList[0].save(SavePath,save_all=True,append_images=self.DocumentList[1:])
else:
self.DocumentImage.save(SavePath)
def NextPage(self):
try:
self.MergeFile()
self.DocumentList[self.CurentPage]=self.DocumentImage
except:
pass
if (len(self.DocumentList)-1) > self.CurentPage:
self.CurentPage+=1
self.DocumentImage=self.DocumentList[self.CurentPage]
self.SignImage = None
self.SignImgLink = None
self.SignObj = None
self.DocFile(True)
def PrevPage(self):
try:
self.MergeFile()
self.DocumentList[self.CurentPage]=self.DocumentImage
except:
pass
if self.CurentPage>0:
self.CurentPage-=1
self.DocumentImage=self.DocumentList[self.CurentPage]
self.SignImage = None
self.SignImgLink = None
self.SignObj = None
self.DocFile(True)
root = Tk()
root.title("Documents signer")
DocCan = DocCanv(root, width=canvas_size, height=canvas_size)
DocCan.pack(side='right', fill=BOTH, expand=1)
MenuFrame = Frame(root, width=120, bg='gray22')
MenuFrame.pack(side='right', fill=Y)
OpenDocBtn = Button(MenuFrame, text='Open Document',command=DocCan.DocFile)
OpenDocBtn.pack(fill=X, padx=5,pady=3)
SignDocBtn = Button(MenuFrame, text='Open sign',command=DocCan.SignFile)
SignDocBtn.pack(fill=X, padx=5,pady=3)
SavePDFBtn = Button(MenuFrame, text='Save as pdf',command = lambda arg1=DocCan, arg2='pdf': DocCanv.SaveFile(arg1,arg2))
SavePDFBtn.pack(fill=X, padx=5,pady=3)
SaveJPGBtn = Button(MenuFrame, text='Save as jpg',command = lambda arg1=DocCan, arg2='jpg': DocCanv.SaveFile(arg1,arg2))
SaveJPGBtn.pack(fill=X, padx=5,pady=3)
NextPageBtn = Button(MenuFrame, text='Next page',command = DocCan.NextPage)
NextPageBtn.pack(fill=X, padx=5,pady=3)
PrevPageBtn = Button(MenuFrame, text='Prev page',command = DocCan.PrevPage)
PrevPageBtn.pack(fill=X, padx=5,pady=3)
DocCan.bind("<B1-Motion>", DocCan.MoveSign)
DocCan.bind("<MouseWheel>", DocCan.ResizeSign)
root.mainloop()
git : https://github.com/mostdefaultusername/SignPDF/releases/tag/1.0