Metadata-Version: 2.4
Name: scan-compress
Version: 0.1.0
Summary: Turn document photos into a clean, auto-enhanced PDF compressed under a target size in KB.
Project-URL: Homepage, https://github.com/shariquesshaikh/scan-compress
Project-URL: Repository, https://github.com/shariquesshaikh/scan-compress
Author-email: Sharique Shaikh <heysharique@gmail.com>
License: MIT
License-File: LICENSE
Keywords: compress,document,image,pdf,scan,scanner
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Requires-Dist: click>=8
Requires-Dist: numpy>=1.24
Requires-Dist: pillow>=10
Requires-Dist: reportlab>=4
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pypdf>=4; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# scan-compress

Turn document photos into a clean, auto-enhanced PDF compressed under a target
size **in KB** — from the command line or as a Python library.

- **Scan look** — adaptive background-whitening, contrast boost, and a subtle
  sharpen, so photographed pages look like real scans.
- **Size targeting** — pick a KB budget; it iteratively lowers JPEG quality and
  resolution until the PDF fits (or returns the smallest it can reach).
- **Local and dependency-light** — pure local image files in, one PDF out. No
  server, no network.

## Install

```bash
pip install scan-compress
```

## CLI

```bash
scan-compress [INPUTS]... -o out.pdf [options]
```

`INPUTS` can be image files, directories (all images, sorted), or glob patterns.
Each image becomes one page, in order.

| Option | Default | Description |
| --- | --- | --- |
| `--target-kb N` | `200` | Maximum PDF size in KB. |
| `-o, --output PATH` | `scan.pdf` | Output PDF path. |
| `--page-size` | `a4` | `a4`, `letter`, or `legal`. |
| `--no-enhance` | off | Skip the scan-style auto-enhancement. |
| `--quality FLOAT` | `0.6` | Initial JPEG quality (0..1) for the compression loop. |
| `--max-width INT` | `1200` | Initial max page-image width in px. |
| `--crop x0,y0,...,x3,y3` | — | Crop a single image to a quadrilateral (normalized 0..1 corners). |
| `-q, --quiet` | off | Suppress non-error output. |

Examples:

```bash
# Three photos into one A4 PDF under 200 KB
scan-compress page1.jpg page2.jpg page3.jpg -o doc.pdf

# Everything in a folder, compressed under 150 KB, no enhancement
scan-compress ./scans/ -o book.pdf --target-kb 150 --no-enhance

# A single image, cropped to the page corners
scan-compress photo.png -o cropped.pdf --crop 0.05,0.05,0.95,0.05,0.95,0.95,0.05,0.95
```

## Library

```python
from scan_compress import (
    load_image, auto_enhance_image, crop_image,
    compress_image, generate_compressed_pdf, build_pdf_from_paths,
)

# One-shot: paths -> compressed PDF
res = build_pdf_from_paths(["a.jpg", "b.jpg"], page_size="a4", target_kb=150)
with open("out.pdf", "wb") as f:
    f.write(res.data)
print(res.size_kb, "KB")

# Step by step
img = auto_enhance_image(load_image("a.jpg"))
res = generate_compressed_pdf([img], page_size="letter", target_kb=200)
```

### Public API

| Function | Returns |
| --- | --- |
| `auto_enhance_image(image, enabled=True)` | enhanced `PIL.Image` |
| `compress_image(image, max_width, quality)` | resized/compressed `PIL.Image` |
| `crop_image(image, corners)` | cropped `PIL.Image` (4 normalized corner points) |
| `generate_compressed_pdf(pages, page_size="a4", *, target_kb=200, ...)` | `PdfResult(data: bytes, size_kb: int)` |
| `build_pdf_from_paths(paths, *, page_size="a4", enhance=True, target_kb=200, ...)` | `PdfResult` |
| `load_image(path)` / `resolve_inputs(inputs)` | `PIL.Image` / `list[Path]` |

## How size targeting works

Starting at quality `0.6` and width `1200`, it builds the PDF and measures the
bytes. If the first pass is already within target, it is returned untouched.
Otherwise it repeatedly multiplies quality by `0.75` and width by `0.8` and
rebuilds, stopping as soon as the PDF is within `target_kb` (or after ten
attempts, returning the smallest result reached).

## Requirements

Python 3.9+. Depends on Pillow, NumPy, reportlab, and Click.

## License

MIT
