Release ZipBundler 1.0.0 with guided recompression and complete Windows build

This commit is contained in:
2026-09-17 16:22:18 +02:00
parent ca934fe4b9
commit 66e14f72c3
6 changed files with 851 additions and 155 deletions

86
verify_exe.py Normal file
View File

@@ -0,0 +1,86 @@
"""Smoke-test the complete frozen package without external Python/Ghostscript on PATH."""
import io
import os
from pathlib import Path
import subprocess
import tempfile
import zipfile
import fitz
from PIL import Image
from PyInstaller.archive.readers import CArchiveReader
def main():
executable = Path(__file__).parent / "dist" / "ZipBundler.exe"
archive = CArchiveReader(str(executable))
names = [name.replace("\\", "/").lower() for name in archive.toc]
for fragment in ("ghostscript/bin/gswin64c.exe", "ghostscript/bin/gsdll64.dll",
"python314.dll", "pythoncom314.dll", "pywintypes314.dll",
"customtkinter/assets/themes/blue.json", "assets/splash.png"):
if not any(fragment in name for name in names):
raise AssertionError(f"Missing bundled component: {fragment}")
print("Embedded components: OK")
with tempfile.TemporaryDirectory(prefix="zipbundler-exe-test-") as directory:
root = Path(directory)
source = root / "source"
source.mkdir()
output = root / "output"
noise = Image.effect_noise((1800, 2400), 80)
image_bytes = io.BytesIO()
noise.save(image_bytes, format="PNG")
pdf = source / "native-scan.pdf"
with fitz.open() as document:
page = document.new_page(width=600, height=800)
page.insert_image(page.rect, stream=image_bytes.getvalue())
page.insert_text((20, 30), ("Searchable native text for bundled engine verification.\n" * 20), fontsize=8)
document.save(pdf)
noise.save(source / "photo.jpg", quality=98)
environment = os.environ.copy()
windows = Path(environment.get("SystemRoot", r"C:\Windows"))
environment["PATH"] = os.pathsep.join((str(windows / "System32"), str(windows)))
for key in ("PYTHONPATH", "PYTHONHOME", "GS_LIB", "GS_FONTPATH"):
environment.pop(key, None)
startup = subprocess.STARTUPINFO()
startup.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startup.wShowWindow = 0
completed = subprocess.run(
[str(executable), str(source), "--output", str(output), "--size-mb", "0.6"],
cwd=root, env=environment, startupinfo=startup, timeout=60,
)
if completed.returncode:
raise AssertionError(f"EXE exited with {completed.returncode}")
archives = sorted(output.glob("pacchetto_*.zip"))
if not archives:
raise AssertionError("No ZIP packages were produced")
found_pdf = found_image = False
for path in archives:
if path.stat().st_size > int(0.6 * 1024 * 1024):
raise AssertionError(f"Oversized archive: {path}")
with zipfile.ZipFile(path) as zipped:
if zipped.testzip() is not None:
raise AssertionError("Corrupt ZIP member")
for name in zipped.namelist():
data = zipped.read(name)
if name.endswith(".pdf"):
with fitz.open(stream=data, filetype="pdf") as document:
if "Searchable native text" not in document[0].get_text():
raise AssertionError("Native PDF text was lost")
found_pdf = True
elif name.endswith(".jpg"):
with Image.open(io.BytesIO(data)) as image:
image.load()
if image.format != "JPEG":
raise AssertionError("Image format changed")
found_image = True
print(f"{path.name}: {path.stat().st_size} bytes, OK")
if not (found_pdf and found_image):
raise AssertionError("Missing optimized PDF or JPEG")
print("Frozen EXE: PDF with searchable text and JPEG compression OK; external tools absent from PATH")
if __name__ == "__main__":
main()