Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Extract page ranges from a PDF, optionally rotating and/or compressing pages."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
||||
def parse_pages(spec: str, page_count: int) -> list[int]:
|
||||
"""Parse a 1-based page spec like '1-3,5,9-' into 0-based indices."""
|
||||
indices: list[int] = []
|
||||
for part in spec.split(","):
|
||||
part = part.strip()
|
||||
if not part:
|
||||
continue
|
||||
if "-" in part:
|
||||
start_s, _, end_s = part.partition("-")
|
||||
start = int(start_s) if start_s else 1
|
||||
end = int(end_s) if end_s else page_count
|
||||
else:
|
||||
start = end = int(part)
|
||||
if start < 1 or end > page_count or start > end:
|
||||
raise ValueError(f"Page range {part!r} out of bounds (1-{page_count})")
|
||||
indices.extend(range(start - 1, end))
|
||||
return indices
|
||||
|
||||
|
||||
def main() -> int:
|
||||
for stream in (sys.stdout, sys.stderr):
|
||||
try:
|
||||
stream.reconfigure(encoding="utf-8")
|
||||
except Exception:
|
||||
pass
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Split/extract pages from a PDF (pypdf). Pages are 1-based: '1-3,5,9-'.")
|
||||
parser.add_argument("pdf", help="Input PDF path")
|
||||
parser.add_argument("--pages", required=True, help="1-based page spec, e.g. '1-3,5,9-'")
|
||||
parser.add_argument("-o", "--output", required=True, help="Output PDF path")
|
||||
parser.add_argument("--rotate", type=int, default=0,
|
||||
help="Rotate extracted pages clockwise (multiple of 90)")
|
||||
parser.add_argument("--compress", action="store_true",
|
||||
help="Deflate content streams (modest savings; does not recompress images)")
|
||||
parser.add_argument("--password", help="Password if the input is encrypted")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.rotate % 90 != 0:
|
||||
print("Error: --rotate must be a multiple of 90", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
try:
|
||||
from pypdf import PdfReader, PdfWriter
|
||||
except ImportError:
|
||||
print("Missing dependency: install with 'python3 -m pip install pypdf'", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
reader = PdfReader(args.pdf)
|
||||
if reader.is_encrypted:
|
||||
if args.password is None or not reader.decrypt(args.password):
|
||||
print("Error: input is encrypted; pass --password", file=sys.stderr)
|
||||
return 3
|
||||
try:
|
||||
indices = parse_pages(args.pages, len(reader.pages))
|
||||
except ValueError as exc:
|
||||
print(f"Error: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
writer = PdfWriter()
|
||||
for idx in indices:
|
||||
page = reader.pages[idx]
|
||||
if args.rotate:
|
||||
page.rotate(args.rotate)
|
||||
writer.add_page(page)
|
||||
if args.compress:
|
||||
for page in writer.pages:
|
||||
page.compress_content_streams()
|
||||
with open(args.output, "wb") as fh:
|
||||
writer.write(fh)
|
||||
print(json.dumps({"output": args.output, "page_count": len(indices), "rotated": args.rotate}))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user