From 13769d11654b531cbe1e06a59e136e69718b791a Mon Sep 17 00:00:00 2001 From: ks-go-copilot Date: Thu, 13 Aug 2026 16:02:52 +0800 Subject: [PATCH 1/7] Move existing project files into V1 folder --- V1/1.make_csdrg_pdf.vbs | 2 + V1/2.run_pdf_validation.vbs | 16 +++ V1/README.md | 23 +++++ V1/Report.html | 98 ++++++++++++++++++ V1/make_csdrg_pdf.py | 139 +++++++++++++++++++++++++ V1/pdf_checker.py | 199 ++++++++++++++++++++++++++++++++++++ 6 files changed, 477 insertions(+) create mode 100644 V1/1.make_csdrg_pdf.vbs create mode 100644 V1/2.run_pdf_validation.vbs create mode 100644 V1/README.md create mode 100644 V1/Report.html create mode 100644 V1/make_csdrg_pdf.py create mode 100644 V1/pdf_checker.py diff --git a/V1/1.make_csdrg_pdf.vbs b/V1/1.make_csdrg_pdf.vbs new file mode 100644 index 0000000..d4bab42 --- /dev/null +++ b/V1/1.make_csdrg_pdf.vbs @@ -0,0 +1,2 @@ +Set objShell = CreateObject("WScript.Shell") +objShell.Run "python.exe """ & CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName) & "\make_csdrg_pdf.py""", 1, True diff --git a/V1/2.run_pdf_validation.vbs b/V1/2.run_pdf_validation.vbs new file mode 100644 index 0000000..e4a318c --- /dev/null +++ b/V1/2.run_pdf_validation.vbs @@ -0,0 +1,16 @@ +Option Explicit + +Dim shell +Dim fso +Dim folder + +Set shell = CreateObject("WScript.Shell") +Set fso = CreateObject("Scripting.FileSystemObject") + +folder = fso.GetParentFolderName(WScript.ScriptFullName) + +shell.CurrentDirectory = folder + +shell.Run "py pdf_checker.py", 0, True + +MsgBox "PDF QA Finished!", vbInformation diff --git a/V1/README.md b/V1/README.md new file mode 100644 index 0000000..c0818a0 --- /dev/null +++ b/V1/README.md @@ -0,0 +1,23 @@ +# Create-PDF-via-Python +1.Not yet validated +Not yet validated or confirmed by the Takeda team. However, based on the conversion results, the output appears to comply with the FDA Portable Document Format (PDF) Specifications and other applicable guidelines. Additional compliance verification is currently being pursued. + +2.Core process +Adobe Acrobat Pro: +Word → [Word COM ExportAsFixedFormat] → PDF → Acrobat Pro Modify properties + +Python: +Word → [Word COM ExportAsFixedFormat] → PDF → Python pikepdf Modify properties + +3.Must executed in J drive +Must be executed from the J: drive, as the Python environment is already configured there. The .vbs and .py files can be copied to any folder on the J: drive and then executed. To run the tool locally, the Python environment must be configured manually. + +4.Run +- Double-click the .vbs files in the order of Steps 1 and 2, then wait for several seconds for the process to complete. +- The Fast Web View optimization must be completed manually by using the Save As function. + +Note: 2.vbs supports batch checking of all PDF files in a folder (excluding subfolders). This can be helpful for quickly validating PDF files when an ADaM eCRT package contains a large number of PDFs. + +------------------------------------------------ +2026-08-04: +The tool may also be supported in the SCE folder once Satori provides Python environment support. diff --git a/V1/Report.html b/V1/Report.html new file mode 100644 index 0000000..a6b8308 --- /dev/null +++ b/V1/Report.html @@ -0,0 +1,98 @@ + + + + + + + + +PDF QA Validation Report + + + + + + + +

PDF QA Validation Report

+ +
+ +
+ +Folder
+ +J:\bdm\sandbox\kevin\RG + +

+ +Total PDF : 1
+PASS : 0
+FAIL : 1 + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FilePagesFast Web ViewTitleAuthorSubjectKeywordsResultReason
csdrg.pdf27NoEmptyEmptyEmptyEmptyFAILFast Web View
+ + + + diff --git a/V1/make_csdrg_pdf.py b/V1/make_csdrg_pdf.py new file mode 100644 index 0000000..a683d67 --- /dev/null +++ b/V1/make_csdrg_pdf.py @@ -0,0 +1,139 @@ +""" +make_csdrg_pdf.py +================= +Converts csdrg.docx -> csdrg.pdf following CSDRG Completion Guidelines v1.4: + + - Uses Microsoft Word COM (ExportAsFixedFormat) to preserve heading bookmarks + - Sets initial view to show Bookmarks Panel on open + - Clears Title / Author / Subject / Keywords per CSDRG guidelines (p.21) + - Verifies PDF version <= 1.7 (FDA eCTD requirement) + +Requirements: pip install pywin32 pikepdf +""" + +import os +import sys +import shutil +import time + +try: + import win32com.client + import pikepdf + from pikepdf import Dictionary, Name +except ImportError as e: + print(f"Missing library: {e}") + print("Run: python -m pip install pywin32 pikepdf") + sys.exit(1) + +# ── Paths ────────────────────────────────────────────────────────────────────── +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +DOCX_SRC = os.path.join(SCRIPT_DIR, "csdrg.docx") +FINAL_PDF = os.path.join(SCRIPT_DIR, "csdrg.pdf") +TEMP_DIR = os.path.join(os.environ.get("TEMP", "C:\\Temp"), "csdrg_build") +TEMP_DOCX = os.path.join(TEMP_DIR, "csdrg.docx") +TEMP_PDF = os.path.join(TEMP_DIR, "csdrg.pdf") + +# ── Step 1: Copy docx to temp (avoids OneDrive/space path issues) ────────────── +print("=" * 60) +print("CSDRG PDF Builder") +print("=" * 60) + +if not os.path.exists(DOCX_SRC): + print(f"ERROR: csdrg.docx not found at:\n {DOCX_SRC}") + sys.exit(1) + +os.makedirs(TEMP_DIR, exist_ok=True) +shutil.copy2(DOCX_SRC, TEMP_DOCX) +print(f"[1/4] Copied docx to temp: {TEMP_DOCX}") + +# ── Step 2: Word COM -> PDF with heading bookmarks ───────────────────────────── +print("[2/4] Converting Word -> PDF via Microsoft Word...") +word = win32com.client.Dispatch("Word.Application") +word.Visible = False +try: + doc = word.Documents.Open(TEMP_DOCX) + doc.ExportAsFixedFormat( + OutputFileName = TEMP_PDF, + ExportFormat = 17, # wdExportFormatPDF + OpenAfterExport = False, + OptimizeFor = 0, # wdExportOptimizeForPrint + Range = 0, # wdExportAllDocument + From = 1, + To = 1, + Item = 0, # wdExportDocumentContent + IncludeDocProps = True, + KeepIRM = True, + CreateBookmarks = 1, # wdExportCreateHeadingBookmarks + DocStructureTags = True, + BitmapMissingFonts = True, + UseISO19005_1 = False, + ) + doc.Close(False) + print(f" PDF created: {TEMP_PDF}") +finally: + word.Quit() + +time.sleep(2) + +# ── Step 3: pikepdf post-processing ─────────────────────────────────────────── +print("[3/4] Setting PDF properties (bookmarks panel + clear metadata)...") +with pikepdf.open(TEMP_PDF, allow_overwriting_input=True) as pdf: + + # Show Bookmarks Panel when opened (CSDRG guideline requirement) + pdf.Root["/PageMode"] = Name("/UseOutlines") + + # ViewerPreferences: default page layout and magnification + if "/ViewerPreferences" not in pdf.Root: + pdf.Root["/ViewerPreferences"] = Dictionary() + + # Clear Title, Author, Subject, Keywords (CSDRG Completion Guidelines p.21) + info = pdf.docinfo + for key in ["/Title", "/Author", "/Subject", "/Keywords", "/Creator", "/Producer"]: + if key in info: + info[key] = "" + + # Report bookmark count + if "/Outlines" in pdf.Root: + print(" Bookmarks: found OK") + else: + print(" WARNING: No bookmarks found.") + print(" Ensure csdrg.docx uses built-in Word Heading 1/2/3 styles.") + + pdf.save(TEMP_PDF) + +# ── Step 4: Verify PDF version and copy to destination ──────────────────────── +print("[4/4] Verifying PDF version...") +with open(TEMP_PDF, "rb") as f: + header = f.read(8).decode("ascii", errors="replace").strip() +print(f" PDF header: {header}") + +version_ok = any(v in header for v in ["1.4", "1.5", "1.6", "1.7"]) +if version_ok: + print(" Version <= 1.7: OK") +else: + print(f" WARNING: Version may exceed 1.7. Check before submission.") + +# Copy to final destination (retry if locked) +for attempt in range(5): + try: + shutil.copy2(TEMP_PDF, FINAL_PDF) + break + except PermissionError: + if attempt < 4: + print(f" File locked, retrying in 3s... (attempt {attempt+1}/5)") + time.sleep(3) + else: + print(f"\nERROR: Could not write to {FINAL_PDF}") + print("Please close any program that has csdrg.pdf open, then re-run.") + sys.exit(1) + +print() +print("=" * 60) +print(f"Done! Output: {FINAL_PDF}") +print() +print("Checklist:") +print(f" [{'OK' if version_ok else '!!'}] PDF version <= 1.7") +print( " [OK] Bookmarks panel shown on open") +print( " [OK] Title/Author/Subject/Keywords cleared") +print( " [OK] File named csdrg.pdf") +print("=" * 60) diff --git a/V1/pdf_checker.py b/V1/pdf_checker.py new file mode 100644 index 0000000..92bbf58 --- /dev/null +++ b/V1/pdf_checker.py @@ -0,0 +1,199 @@ +from pathlib import Path +import html +import webbrowser +import pikepdf + + +ROOT = Path.cwd() +REPORT = ROOT / "Report.html" + + +def is_linearized(pdf_file): + """ + Detect Fast Web View (Linearized PDF) + """ + try: + with open(pdf_file, "rb") as f: + header = f.read(4096) + return b"/Linearized" in header + except Exception: + return False + + +def get_metadata(pdf_file): + + result = { + "Pages": "", + "Title": "", + "Author": "", + "Subject": "", + "Keywords": "", + "Fast Web View": "No" + } + + try: + + with pikepdf.open(pdf_file) as pdf: + + info = pdf.docinfo + + result["Pages"] = len(pdf.pages) + result["Title"] = str(info.get("/Title", "") or "") + result["Author"] = str(info.get("/Author", "") or "") + result["Subject"] = str(info.get("/Subject", "") or "") + result["Keywords"] = str(info.get("/Keywords", "") or "") + + if is_linearized(pdf_file): + result["Fast Web View"] = "Yes" + + except Exception as e: + + result["Error"] = str(e) + + return result + + +pdfs = sorted(ROOT.glob("*.pdf")) + +rows = [] + +pass_count = 0 +fail_count = 0 + +for pdf in pdfs: + + m = get_metadata(pdf) + + issues = [] + + if m["Title"] != "": + issues.append("Title") + + if m["Author"] != "": + issues.append("Author") + + if m["Subject"] != "": + issues.append("Subject") + + if m["Keywords"] != "": + issues.append("Keywords") + + if m["Fast Web View"] != "Yes": + issues.append("Fast Web View") + + result = "PASS" if len(issues) == 0 else "FAIL" + + if result == "PASS": + pass_count += 1 + else: + fail_count += 1 + + rows.append(f""" + +{html.escape(pdf.name)} +{m["Pages"]} +{m["Fast Web View"]} +{"Empty" if m["Title"]=="" else "Exists"} +{"Empty" if m["Author"]=="" else "Exists"} +{"Empty" if m["Subject"]=="" else "Exists"} +{"Empty" if m["Keywords"]=="" else "Exists"} +{result} +{", ".join(issues)} + +""") + + +html_text = f""" + + + + + + + + +PDF QA Validation Report + + + + + + + +

PDF QA Validation Report

+ +
+ +
+ +Folder
+ +{ROOT} + +

+ +Total PDF : {len(pdfs)}
+PASS : {pass_count}
+FAIL : {fail_count} + +
+ + + + + + + + + + + + + + + +{''.join(rows)} + +
FilePagesFast Web ViewTitleAuthorSubjectKeywordsResultReason
+ + + + +""" + +REPORT.write_text(html_text, encoding="utf-8") + +print("Finished.") + +webbrowser.open(REPORT.as_uri()) From 122128a95d7442a8093e7b050dd1ab052ef4690c Mon Sep 17 00:00:00 2001 From: ks-go-copilot Date: Thu, 13 Aug 2026 16:02:58 +0800 Subject: [PATCH 2/7] Remove root README after moving to V1 folder --- README.md | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index c0818a0..0000000 --- a/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Create-PDF-via-Python -1.Not yet validated -Not yet validated or confirmed by the Takeda team. However, based on the conversion results, the output appears to comply with the FDA Portable Document Format (PDF) Specifications and other applicable guidelines. Additional compliance verification is currently being pursued. - -2.Core process -Adobe Acrobat Pro: -Word → [Word COM ExportAsFixedFormat] → PDF → Acrobat Pro Modify properties - -Python: -Word → [Word COM ExportAsFixedFormat] → PDF → Python pikepdf Modify properties - -3.Must executed in J drive -Must be executed from the J: drive, as the Python environment is already configured there. The .vbs and .py files can be copied to any folder on the J: drive and then executed. To run the tool locally, the Python environment must be configured manually. - -4.Run -- Double-click the .vbs files in the order of Steps 1 and 2, then wait for several seconds for the process to complete. -- The Fast Web View optimization must be completed manually by using the Save As function. - -Note: 2.vbs supports batch checking of all PDF files in a folder (excluding subfolders). This can be helpful for quickly validating PDF files when an ADaM eCRT package contains a large number of PDFs. - ------------------------------------------------- -2026-08-04: -The tool may also be supported in the SCE folder once Satori provides Python environment support. From f4f2e33e52220cabf9793203a262caff46eadc7c Mon Sep 17 00:00:00 2001 From: ks-go-copilot Date: Thu, 13 Aug 2026 16:03:00 +0800 Subject: [PATCH 3/7] Remove root script after moving to V1 folder --- 1.make_csdrg_pdf.vbs | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 1.make_csdrg_pdf.vbs diff --git a/1.make_csdrg_pdf.vbs b/1.make_csdrg_pdf.vbs deleted file mode 100644 index dbdf2a3..0000000 --- a/1.make_csdrg_pdf.vbs +++ /dev/null @@ -1,2 +0,0 @@ -Set objShell = CreateObject("WScript.Shell") -objShell.Run "python.exe """ & CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName) & "\make_csdrg_pdf.py""", 1, True From b66c79da4d4e80b7aed06c36886e2041de7f2806 Mon Sep 17 00:00:00 2001 From: ks-go-copilot Date: Thu, 13 Aug 2026 16:03:02 +0800 Subject: [PATCH 4/7] Remove root report after moving to V1 folder --- Report.html | 99 ----------------------------------------------------- 1 file changed, 99 deletions(-) delete mode 100644 Report.html diff --git a/Report.html b/Report.html deleted file mode 100644 index 578bdf8..0000000 --- a/Report.html +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - -PDF QA Validation Report - - - - - - - -

PDF QA Validation Report

- -
- -
- -Folder
- -J:\bdm\sandbox\kevin\RG - -

- -Total PDF : 1
-PASS : 0
-FAIL : 1 - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FilePagesFast Web ViewTitleAuthorSubjectKeywordsResultReason
csdrg.pdf27NoEmptyEmptyEmptyEmptyFAILFast Web View
- - - - From 39149a7b7dfc403036866a6d8bfec9bfe818554f Mon Sep 17 00:00:00 2001 From: ks-go-copilot Date: Thu, 13 Aug 2026 16:03:03 +0800 Subject: [PATCH 5/7] Remove root Python script after moving to V1 folder --- make_csdrg_pdf.py | 139 ---------------------------------------------- 1 file changed, 139 deletions(-) delete mode 100644 make_csdrg_pdf.py diff --git a/make_csdrg_pdf.py b/make_csdrg_pdf.py deleted file mode 100644 index 2e1f070..0000000 --- a/make_csdrg_pdf.py +++ /dev/null @@ -1,139 +0,0 @@ -""" -make_csdrg_pdf.py -================= -Converts csdrg.docx -> csdrg.pdf following CSDRG Completion Guidelines v1.4: - - - Uses Microsoft Word COM (ExportAsFixedFormat) to preserve heading bookmarks - - Sets initial view to show Bookmarks Panel on open - - Clears Title / Author / Subject / Keywords per CSDRG guidelines (p.21) - - Verifies PDF version <= 1.7 (FDA eCTD requirement) - -Requirements: pip install pywin32 pikepdf -""" - -import os -import sys -import shutil -import time - -try: - import win32com.client - import pikepdf - from pikepdf import Dictionary, Name -except ImportError as e: - print(f"Missing library: {e}") - print("Run: python -m pip install pywin32 pikepdf") - sys.exit(1) - -# ── Paths ────────────────────────────────────────────────────────────────────── -SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) -DOCX_SRC = os.path.join(SCRIPT_DIR, "csdrg.docx") -FINAL_PDF = os.path.join(SCRIPT_DIR, "csdrg.pdf") -TEMP_DIR = os.path.join(os.environ.get("TEMP", "C:\\Temp"), "csdrg_build") -TEMP_DOCX = os.path.join(TEMP_DIR, "csdrg.docx") -TEMP_PDF = os.path.join(TEMP_DIR, "csdrg.pdf") - -# ── Step 1: Copy docx to temp (avoids OneDrive/space path issues) ────────────── -print("=" * 60) -print("CSDRG PDF Builder") -print("=" * 60) - -if not os.path.exists(DOCX_SRC): - print(f"ERROR: csdrg.docx not found at:\n {DOCX_SRC}") - sys.exit(1) - -os.makedirs(TEMP_DIR, exist_ok=True) -shutil.copy2(DOCX_SRC, TEMP_DOCX) -print(f"[1/4] Copied docx to temp: {TEMP_DOCX}") - -# ── Step 2: Word COM -> PDF with heading bookmarks ───────────────────────────── -print("[2/4] Converting Word -> PDF via Microsoft Word...") -word = win32com.client.Dispatch("Word.Application") -word.Visible = False -try: - doc = word.Documents.Open(TEMP_DOCX) - doc.ExportAsFixedFormat( - OutputFileName = TEMP_PDF, - ExportFormat = 17, # wdExportFormatPDF - OpenAfterExport = False, - OptimizeFor = 0, # wdExportOptimizeForPrint - Range = 0, # wdExportAllDocument - From = 1, - To = 1, - Item = 0, # wdExportDocumentContent - IncludeDocProps = True, - KeepIRM = True, - CreateBookmarks = 1, # wdExportCreateHeadingBookmarks - DocStructureTags = True, - BitmapMissingFonts = True, - UseISO19005_1 = False, - ) - doc.Close(False) - print(f" PDF created: {TEMP_PDF}") -finally: - word.Quit() - -time.sleep(2) - -# ── Step 3: pikepdf post-processing ─────────────────────────────────────────── -print("[3/4] Setting PDF properties (bookmarks panel + clear metadata)...") -with pikepdf.open(TEMP_PDF, allow_overwriting_input=True) as pdf: - - # Show Bookmarks Panel when opened (CSDRG guideline requirement) - pdf.Root["/PageMode"] = Name("/UseOutlines") - - # ViewerPreferences: default page layout and magnification - if "/ViewerPreferences" not in pdf.Root: - pdf.Root["/ViewerPreferences"] = Dictionary() - - # Clear Title, Author, Subject, Keywords (CSDRG Completion Guidelines p.21) - info = pdf.docinfo - for key in ["/Title", "/Author", "/Subject", "/Keywords", "/Creator", "/Producer"]: - if key in info: - info[key] = "" - - # Report bookmark count - if "/Outlines" in pdf.Root: - print(" Bookmarks: found OK") - else: - print(" WARNING: No bookmarks found.") - print(" Ensure csdrg.docx uses built-in Word Heading 1/2/3 styles.") - - pdf.save(TEMP_PDF) - -# ── Step 4: Verify PDF version and copy to destination ──────────────────────── -print("[4/4] Verifying PDF version...") -with open(TEMP_PDF, "rb") as f: - header = f.read(8).decode("ascii", errors="replace").strip() -print(f" PDF header: {header}") - -version_ok = any(v in header for v in ["1.4", "1.5", "1.6", "1.7"]) -if version_ok: - print(" Version <= 1.7: OK") -else: - print(f" WARNING: Version may exceed 1.7. Check before submission.") - -# Copy to final destination (retry if locked) -for attempt in range(5): - try: - shutil.copy2(TEMP_PDF, FINAL_PDF) - break - except PermissionError: - if attempt < 4: - print(f" File locked, retrying in 3s... (attempt {attempt+1}/5)") - time.sleep(3) - else: - print(f"\nERROR: Could not write to {FINAL_PDF}") - print("Please close any program that has csdrg.pdf open, then re-run.") - sys.exit(1) - -print() -print("=" * 60) -print(f"Done! Output: {FINAL_PDF}") -print() -print("Checklist:") -print(f" [{'OK' if version_ok else '!!'}] PDF version <= 1.7") -print( " [OK] Bookmarks panel shown on open") -print( " [OK] Title/Author/Subject/Keywords cleared") -print( " [OK] File named csdrg.pdf") -print("=" * 60) From 5b02233bc912df5e4777e5c0a71dcbfb8584c2a6 Mon Sep 17 00:00:00 2001 From: ks-go-copilot Date: Thu, 13 Aug 2026 16:03:05 +0800 Subject: [PATCH 6/7] Remove root script after moving to V1 folder --- 2.run_pdf_validation.vbs | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 2.run_pdf_validation.vbs diff --git a/2.run_pdf_validation.vbs b/2.run_pdf_validation.vbs deleted file mode 100644 index fa86a74..0000000 --- a/2.run_pdf_validation.vbs +++ /dev/null @@ -1,16 +0,0 @@ -Option Explicit - -Dim shell -Dim fso -Dim folder - -Set shell = CreateObject("WScript.Shell") -Set fso = CreateObject("Scripting.FileSystemObject") - -folder = fso.GetParentFolderName(WScript.ScriptFullName) - -shell.CurrentDirectory = folder - -shell.Run "py pdf_checker.py", 0, True - -MsgBox "PDF QA Finished!", vbInformation \ No newline at end of file From cd8e44367376f6fe8217319cbad1aecd44649203 Mon Sep 17 00:00:00 2001 From: ks-go-copilot Date: Thu, 13 Aug 2026 16:03:07 +0800 Subject: [PATCH 7/7] Remove root Python script after moving to V1 folder --- pdf_checker.py | 199 ------------------------------------------------- 1 file changed, 199 deletions(-) delete mode 100644 pdf_checker.py diff --git a/pdf_checker.py b/pdf_checker.py deleted file mode 100644 index 2d74318..0000000 --- a/pdf_checker.py +++ /dev/null @@ -1,199 +0,0 @@ -from pathlib import Path -import html -import webbrowser -import pikepdf - - -ROOT = Path.cwd() -REPORT = ROOT / "Report.html" - - -def is_linearized(pdf_file): - """ - Detect Fast Web View (Linearized PDF) - """ - try: - with open(pdf_file, "rb") as f: - header = f.read(4096) - return b"/Linearized" in header - except Exception: - return False - - -def get_metadata(pdf_file): - - result = { - "Pages": "", - "Title": "", - "Author": "", - "Subject": "", - "Keywords": "", - "Fast Web View": "No" - } - - try: - - with pikepdf.open(pdf_file) as pdf: - - info = pdf.docinfo - - result["Pages"] = len(pdf.pages) - result["Title"] = str(info.get("/Title", "") or "") - result["Author"] = str(info.get("/Author", "") or "") - result["Subject"] = str(info.get("/Subject", "") or "") - result["Keywords"] = str(info.get("/Keywords", "") or "") - - if is_linearized(pdf_file): - result["Fast Web View"] = "Yes" - - except Exception as e: - - result["Error"] = str(e) - - return result - - -pdfs = sorted(ROOT.glob("*.pdf")) - -rows = [] - -pass_count = 0 -fail_count = 0 - -for pdf in pdfs: - - m = get_metadata(pdf) - - issues = [] - - if m["Title"] != "": - issues.append("Title") - - if m["Author"] != "": - issues.append("Author") - - if m["Subject"] != "": - issues.append("Subject") - - if m["Keywords"] != "": - issues.append("Keywords") - - if m["Fast Web View"] != "Yes": - issues.append("Fast Web View") - - result = "PASS" if len(issues) == 0 else "FAIL" - - if result == "PASS": - pass_count += 1 - else: - fail_count += 1 - - rows.append(f""" - -{html.escape(pdf.name)} -{m["Pages"]} -{m["Fast Web View"]} -{"Empty" if m["Title"]=="" else "Exists"} -{"Empty" if m["Author"]=="" else "Exists"} -{"Empty" if m["Subject"]=="" else "Exists"} -{"Empty" if m["Keywords"]=="" else "Exists"} -{result} -{", ".join(issues)} - -""") - - -html_text = f""" - - - - - - - - -PDF QA Validation Report - - - - - - - -

PDF QA Validation Report

- -
- -
- -Folder
- -{ROOT} - -

- -Total PDF : {len(pdfs)}
-PASS : {pass_count}
-FAIL : {fail_count} - -
- - - - - - - - - - - - - - - -{''.join(rows)} - -
FilePagesFast Web ViewTitleAuthorSubjectKeywordsResultReason
- - - - -""" - -REPORT.write_text(html_text, encoding="utf-8") - -print("Finished.") - -webbrowser.open(REPORT.as_uri()) \ No newline at end of file