Use temp dir without changing into it
Dieser Commit ist enthalten in:
Ursprung
c499826141
Commit
ba9cdb2e77
1 geänderte Dateien mit 23 neuen und 30 gelöschten Zeilen
53
pdf-sign
53
pdf-sign
|
@ -2,20 +2,21 @@
|
||||||
|
|
||||||
#Dependencies: python3, pdftk, gs, mv, pdfinfo
|
#Dependencies: python3, pdftk, gs, mv, pdfinfo
|
||||||
|
|
||||||
import contextlib, os, queue, re, subprocess, sys, tempfile, threading, time, tkinter as tk
|
import os, queue, re, subprocess, sys, tempfile, threading, time, tkinter as tk
|
||||||
|
|
||||||
signatureDir=os.path.expanduser(os.environ['PDF_SIGNATURE_DIR'] if 'PDF_SIGNATURE_DIR' in os.environ else "~/.pdf_signatures")
|
signatureDir=os.path.expanduser(os.environ['PDF_SIGNATURE_DIR'] if 'PDF_SIGNATURE_DIR' in os.environ else "~/.pdf_signatures")
|
||||||
|
|
||||||
# Inspired by https://unix.stackexchange.com/a/141496
|
# Inspired by https://unix.stackexchange.com/a/141496
|
||||||
def main(filePath, pagestr=None):
|
def main(filePath, pagestr=None):
|
||||||
fileAbsPath=os.path.abspath(filePath)
|
#filePath=os.path.expanduser(filePath)
|
||||||
with inTmpDir():
|
with tempfile.TemporaryDirectory() as tempdir:
|
||||||
|
intmp=lambda fileName: os.path.join(tempdir, fileName)
|
||||||
# Flatten (make forms non-editable) before signing
|
# Flatten (make forms non-editable) before signing
|
||||||
flatPDF=Cell(lambda: subprocess.run(['pdftk', fileAbsPath, 'output', 'flat.pdf', 'flatten'], check=True) and 'flat.pdf')
|
flatPDF=Cell(lambda: subprocess.run(['pdftk', filePath, 'output', intmp('flat.pdf'), 'flatten'], check=True) and intmp('flat.pdf'))
|
||||||
# The chosen page
|
# The chosen page
|
||||||
pageCount=pdfCountPages(flatPDF())
|
pageCount=pdfCountPages(flatPDF())
|
||||||
pageNumber=Cell(int(pagestr) if pagestr else pageCount)
|
pageNumber=Cell(int(pagestr) if pagestr else pageCount)
|
||||||
pagePDF=Cell(lambda: subprocess.run(['pdftk', flatPDF(), 'cat', str(pageNumber()), 'output', 'page.pdf'], check=True) and 'page.pdf')
|
pagePDF=Cell(lambda: subprocess.run(['pdftk', flatPDF(), 'cat', str(pageNumber()), 'output', intmp('page.pdf')], check=True) and intmp('page.pdf'))
|
||||||
pageSize=Cell(lambda: pdfGetSize(pagePDF()))
|
pageSize=Cell(lambda: pdfGetSize(pagePDF()))
|
||||||
# The chosen signature
|
# The chosen signature
|
||||||
signatures=[*filter(lambda x: m("^.*\.pdf$", x), os.listdir(signatureDir))]
|
signatures=[*filter(lambda x: m("^.*\.pdf$", x), os.listdir(signatureDir))]
|
||||||
|
@ -32,22 +33,23 @@ def main(filePath, pagestr=None):
|
||||||
resize=1.1**signatureScale()*min(w/sw, h/sh)/3
|
resize=1.1**signatureScale()*min(w/sw, h/sh)/3
|
||||||
dx=w*signaturePositionX()/resize - sw/2
|
dx=w*signaturePositionX()/resize - sw/2
|
||||||
dy=h*(1-signaturePositionY())/resize - sh/2
|
dy=h*(1-signaturePositionY())/resize - sh/2
|
||||||
|
outFile=intmp('signature-positioned.pdf')
|
||||||
subprocess.run([
|
subprocess.run([
|
||||||
'gs', '-dBATCH', '-dNOPAUSE', '-dSAFER', '-dQUIET',
|
'gs', '-dBATCH', '-dNOPAUSE', '-dSAFER', '-dQUIET',
|
||||||
'-sOutputFile=page.signature.pdf',
|
f'-sOutputFile={outFile}',
|
||||||
'-sDEVICE=pdfwrite',
|
'-sDEVICE=pdfwrite',
|
||||||
f'-dDEVICEWIDTHPOINTS={w}', f'-dDEVICEHEIGHTPOINTS={h}', '-dFIXEDMEDIA',
|
f'-dDEVICEWIDTHPOINTS={w}', f'-dDEVICEHEIGHTPOINTS={h}', '-dFIXEDMEDIA',
|
||||||
'-c', f'<</BeginPage{{{resize} {resize} scale {dx} {dy} translate}}>> setpagedevice',
|
'-c', f'<</BeginPage{{{resize} {resize} scale {dx} {dy} translate}}>> setpagedevice',
|
||||||
'-f', signatureAbsPath(),
|
'-f', signatureAbsPath(),
|
||||||
], check=True)
|
], check=True)
|
||||||
return 'page.signature.pdf'
|
return outFile
|
||||||
# The signed page
|
# The signed page
|
||||||
signedPagePDF=Cell(lambda: subprocess.run([
|
signedPagePDF=Cell(lambda: subprocess.run([
|
||||||
'pdftk',
|
'pdftk',
|
||||||
pagePDF(),
|
pagePDF(),
|
||||||
'stamp', signaturePositionedPDF(),
|
'stamp', signaturePositionedPDF(),
|
||||||
'output', 'page.signed.pdf',
|
'output', intmp('signed-page.pdf'),
|
||||||
], check=True) and 'page.signed.pdf')
|
], check=True) and intmp('signed-page.pdf'))
|
||||||
# The signed page as PNG, for GUI use
|
# The signed page as PNG, for GUI use
|
||||||
displayMaxSize=Cell((400, 800))
|
displayMaxSize=Cell((400, 800))
|
||||||
@Cell
|
@Cell
|
||||||
|
@ -59,15 +61,16 @@ def main(filePath, pagestr=None):
|
||||||
@Cell
|
@Cell
|
||||||
def displayPNG():
|
def displayPNG():
|
||||||
(w, h)=displaySize()
|
(w, h)=displaySize()
|
||||||
|
outFile=intmp('display.png')
|
||||||
subprocess.run([
|
subprocess.run([
|
||||||
'gs', '-dBATCH', '-dNOPAUSE', '-dSAFER', '-dQUIET',
|
'gs', '-dBATCH', '-dNOPAUSE', '-dSAFER', '-dQUIET',
|
||||||
'-sOutputFile=page.display.png',
|
f'-sOutputFile={outFile}',
|
||||||
'-sDEVICE=pngalpha',
|
'-sDEVICE=pngalpha',
|
||||||
'-dMaxBitmap=2147483647',
|
'-dMaxBitmap=2147483647',
|
||||||
f'-dDEVICEWIDTHPOINTS={w}', f'-dDEVICEHEIGHTPOINTS={h}', '-dFIXEDMEDIA', '-dPDFFitPage',
|
f'-dDEVICEWIDTHPOINTS={w}', f'-dDEVICEHEIGHTPOINTS={h}', '-dFIXEDMEDIA', '-dPDFFitPage',
|
||||||
'-f', signedPagePDF(),
|
'-f', signedPagePDF(),
|
||||||
], check=True)
|
], check=True)
|
||||||
return './page.display.png'
|
return outFile
|
||||||
# GUI
|
# GUI
|
||||||
doSign=True
|
doSign=True
|
||||||
gui=True
|
gui=True
|
||||||
|
@ -201,16 +204,16 @@ def main(filePath, pagestr=None):
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
# End of GUI
|
# End of GUI
|
||||||
if doSign:
|
if doSign:
|
||||||
[ignored, pathPart1, pathPart2] = m("^(.*)(\.[Pp][Dd][Ff])$", fileAbsPath)
|
[ignored, pathPart1, pathPart2] = m("^(.*)(\.[Pp][Dd][Ff])$", filePath)
|
||||||
signedFileAbsPath=f'{pathPart1}.signed{pathPart2}'
|
signedFilePath=f'{pathPart1}.signed{pathPart2}'
|
||||||
if os.path.exists(signedFileAbsPath):
|
if os.path.exists(signedFilePath):
|
||||||
backupFileAbsPath=f'{pathPart1}.signed.backup{time.strftime("%Y%m%d_%H%M%S")}{pathPart2}'
|
backupFilePath=f'{pathPart1}.signed.backup{time.strftime("%Y%m%d_%H%M%S")}{pathPart2}'
|
||||||
subprocess.run([
|
subprocess.run([
|
||||||
'mv',
|
'mv',
|
||||||
signedFileAbsPath,
|
signedFilePath,
|
||||||
backupFileAbsPath,
|
backupFilePath,
|
||||||
], check=True)
|
], check=True)
|
||||||
print(f'Renamed {signedFileAbsPath} to {backupFileAbsPath}')
|
print(f'Renamed {signedFilePath} to {backupFilePath}')
|
||||||
pnr=pageNumber()
|
pnr=pageNumber()
|
||||||
subprocess.run([
|
subprocess.run([
|
||||||
'pdftk',
|
'pdftk',
|
||||||
|
@ -220,9 +223,9 @@ def main(filePath, pagestr=None):
|
||||||
*([f'A1-{pnr-1}'] if 1 < pnr else []),
|
*([f'A1-{pnr-1}'] if 1 < pnr else []),
|
||||||
'B',
|
'B',
|
||||||
*([f'A{pnr+1}-end'] if pnr < pageCount else []),
|
*([f'A{pnr+1}-end'] if pnr < pageCount else []),
|
||||||
'output', signedFileAbsPath,
|
'output', signedFilePath,
|
||||||
], check=True)
|
], check=True)
|
||||||
print(f'Signed document saved as {signedFileAbsPath}')
|
print(f'Signed document saved as {signedFilePath}')
|
||||||
else:
|
else:
|
||||||
print(f'Aborted')
|
print(f'Aborted')
|
||||||
|
|
||||||
|
@ -276,16 +279,6 @@ def m(pattern, string):
|
||||||
ret.append(match.group(index))
|
ret.append(match.group(index))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def inTmpDir():
|
|
||||||
olddir = os.getcwd()
|
|
||||||
with tempfile.TemporaryDirectory() as tempdir:
|
|
||||||
try:
|
|
||||||
os.chdir(tempdir)
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
os.chdir(olddir)
|
|
||||||
|
|
||||||
def fromCmdOutput(cmd, pattern):
|
def fromCmdOutput(cmd, pattern):
|
||||||
sp=subprocess.run(cmd, check=True, capture_output=True)
|
sp=subprocess.run(cmd, check=True, capture_output=True)
|
||||||
result=sp.stdout.decode('utf-8')
|
result=sp.stdout.decode('utf-8')
|
||||||
|
|
Laden …
Tabelle hinzufügen
In neuem Issue referenzieren