From f49afa78235eb627d3b780cc619b709558598672 Mon Sep 17 00:00:00 2001 From: Plom Heller Date: Tue, 29 Sep 2026 14:28:23 +0200 Subject: [PATCH] Structure like my other installables. --- .gitmodules | 3 + install.sh | 2 + plomlib | 1 + bookmaker.py => src/bookmaker/misc.py | 71 +++--------------------- src/plomlib/setup.py | 1 + requirements.txt => src/requirements.txt | 0 src/run.py | 68 +++++++++++++++++++++++ 7 files changed, 84 insertions(+), 62 deletions(-) create mode 100644 .gitmodules create mode 100755 install.sh create mode 160000 plomlib rename bookmaker.py => src/bookmaker/misc.py (93%) create mode 120000 src/plomlib/setup.py rename requirements.txt => src/requirements.txt (100%) create mode 100755 src/run.py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..42cf7f3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "plomlib"] + path = plomlib + url = https://plomlompom.com/repos/clone/plomlib diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..976e3f4 --- /dev/null +++ b/install.sh @@ -0,0 +1,2 @@ +#!/usr/bin/sh +./plomlib/sh/install.sh bookmaker diff --git a/plomlib b/plomlib new file mode 160000 index 0000000..8692e6d --- /dev/null +++ b/plomlib @@ -0,0 +1 @@ +Subproject commit 8692e6dd3c9f5803def5f42b570c5a5f8027f11e diff --git a/bookmaker.py b/src/bookmaker/misc.py similarity index 93% rename from bookmaker.py rename to src/bookmaker/misc.py index e43d754..9fa1921 100755 --- a/bookmaker.py +++ b/src/bookmaker/misc.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python3 -""" -bookmaker.py helps optimizing PDFs for the production of small self-printed, -self-bound physical books; towards this goal offers various PDF manipulation -options that may also be used indepéndently and for other purposes. -""" +# standard libs from argparse import ( ArgumentParser, Namespace as ArgsNamespace, @@ -11,28 +6,15 @@ from argparse import ( ) from io import BufferedReader, BytesIO from os.path import isfile -from sys import exit as sys_exit from typing import Optional, Self - - -def handled_error_exit( - msg: str - ) -> None: - 'Print msg, then exit(1).' - print(f'ERROR: {msg}') - sys_exit(1) - - -try: - from pypdf import ( - PageObject as PdfPage, - PdfReader, - PdfWriter, - Transformation as PdfTransformation - ) - from pypdf.errors import PdfStreamError -except ImportError: - handled_error_exit('Can\'t run at all without pypdf installed.') +# non-standard libs +from pypdf import ( + PageObject as PdfPage, + PdfReader, + PdfWriter, + Transformation as PdfTransformation + ) +from pypdf.errors import PdfStreamError try: from reportlab.pdfgen.canvas import Canvas GOT_CANVAS = True @@ -767,38 +749,3 @@ def resort_pages_for_nup4( new_page_order += [eight_pack[n]] n_eights += 1 pages[:] = new_page_order[:] - - -def main( - ) -> None: - 'Full program run to be wrapped into ArgFail catcher.' - args = parse_args() - validate_args_syntax(args) - if args.nup4 and not GOT_CANVAS: - raise ArgFail('n', 'need reportlab.pdfgen.canvas installed for --nup4') - pages, opened_files = args_to_pagelist( - args.input_file, args.page_range, args.analyze) - validate_ranges(args, len(pages)) - rotate_pages(pages, args.rotate_page, args.analyze) - if not args.keep_mediabox: - normalize_pages_to_a4(pages, args.analyze) - if args.nup4: - pad_pages_to_multiple_of_8(pages) - collect_page_croppings(pages, - args.crops, args.keep_mediabox, args.symmetry) - writer = PdfWriter() - if args.nup4: - build_nup4_output(writer, pages, args.print_margin, args.analyze) - else: - build_single_pages_output(writer, pages, args.analyze) - for file in opened_files: - file.close() - with open(args.output_file, 'wb') as output_file: - writer.write(output_file) - - -if __name__ == '__main__': - try: - main() - except ArgFail as e: - handled_error_exit(f'-{e.arg_char}: {e.msg}') diff --git a/src/plomlib/setup.py b/src/plomlib/setup.py new file mode 120000 index 0000000..4a26f80 --- /dev/null +++ b/src/plomlib/setup.py @@ -0,0 +1 @@ +../../plomlib/py/setup.py \ No newline at end of file diff --git a/requirements.txt b/src/requirements.txt similarity index 100% rename from requirements.txt rename to src/requirements.txt diff --git a/src/run.py b/src/run.py new file mode 100755 index 0000000..37fd4c4 --- /dev/null +++ b/src/run.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +""" +bookmaker.py helps optimizing PDFs for the production of small self-printed, +self-bound physical books; towards this goal offers various PDF manipulation +options that may also be used indepéndently and for other purposes. +""" + +# standard libs +from sys import exit as sys_exit +# ourselves +from plomlib.setup import dependency_hint +try: + from bookmaker.misc import ( + ArgFail, + GOT_CANVAS, + PdfWriter, + args_to_pagelist, + build_nup4_output, + build_single_pages_output, + collect_page_croppings, + normalize_pages_to_a4, + pad_pages_to_multiple_of_8, + parse_args, + rotate_pages, + validate_args_syntax, + validate_ranges, + ) +except ModuleNotFoundError as e: + dependency_hint(e) + + +def main( + ) -> None: + 'Full program run to be wrapped into ArgFail catcher.' + args = parse_args() + validate_args_syntax(args) + if args.nup4 and not GOT_CANVAS: + raise ArgFail('n', 'need reportlab.pdfgen.canvas installed for --nup4') + + pages, opened_files = args_to_pagelist( + args.input_file, args.page_range, args.analyze) + validate_ranges(args, len(pages)) + + rotate_pages(pages, args.rotate_page, args.analyze) + if not args.keep_mediabox: + normalize_pages_to_a4(pages, args.analyze) + if args.nup4: + pad_pages_to_multiple_of_8(pages) + collect_page_croppings(pages, + args.crops, args.keep_mediabox, args.symmetry) + writer = PdfWriter() + if args.nup4: + build_nup4_output(writer, pages, args.print_margin, args.analyze) + else: + build_single_pages_output(writer, pages, args.analyze) + + for file in opened_files: + file.close() + with open(args.output_file, 'wb') as output_file: + writer.write(output_file) + + +if __name__ == '__main__': + try: + main() + except ArgFail as e: + print(f'ERROR: -{e.arg_char}: {e.msg}') + sys_exit(1) -- 2.30.2