Metadata-Version: 2.5
Name: adb-scrollshot
Version: 0.1.0
Summary: Lossless Android scrolling screenshots with automatic capture and overlap removal
Project-URL: Repository, https://github.com/vishalnagda1/adb-scrollshot
Project-URL: Documentation, https://github.com/vishalnagda1/adb-scrollshot/blob/main/README.md
License-Expression: MIT
License-File: LICENSE
Keywords: adb,android,image-stitching,screenshot,scrolling
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture
Requires-Python: >=3.11
Requires-Dist: numpy<3,>=2
Requires-Dist: opencv-python<6,>=4.10
Description-Content-Type: text/markdown

# ADB Scrollshot

Capture a sharp, continuous scrolling screenshot from an Android phone. The
command automatically swipes, captures lossless PNG screenshots, removes
matching overlap, and stops when the selected content stops moving.

The final image keeps the original captured pixel resolution. Optional shorter
PNG pages make long captures easier to view and share.

## Requirements

- Python 3.11 or newer and [uv](https://docs.astral.sh/uv/).
- Android Platform Tools (`adb`) on your PATH.
- An unlocked Android phone with USB debugging enabled and this computer authorized.
- A desktop session for interactive area selection; use `--roi` otherwise.

On macOS, install ADB with `brew install android-platform-tools`. On other
platforms, install Android Platform Tools and add it to PATH. Confirm that
`adb devices` lists your phone with the state `device`, not `unauthorized`.
`adb` is a separate system prerequisite and is not included in this package.

## Install from PyPI

```sh
python -m pip install adb-scrollshot
adb-scrollshot --select --keep-frames --tile-height 3120 --output captures/high_quality.png
```

For an isolated command-line installation, use `uv tool install adb-scrollshot`.
For Python programs, install into your project's virtual environment and import
`adb_scrollshot`. Python 3.11 or newer is required.

## Quick start

From this project directory:

```sh
uv sync --locked
uv run adb-scrollshot --select --keep-frames --tile-height 3120 --output captures/high_quality.png
```

1. Open the desired page on your phone and return to its top.
2. Run the command. Draw a rectangle around **only the scrolling content**,
   excluding fixed toolbars, status bars, navigation bars, and sticky headers.
3. Press **Enter**. Leave the phone untouched while it scrolls and captures.
4. Find `captures/high_quality.png`, its original screenshots in
   `captures/high_quality_frames/`, and shorter PNGs in `captures/high_quality_pages/`.

`scrcpy` is optional; it can mirror the phone while ADB captures directly.
Without `--output`, the destination is `captures/long_screenshot.png`.
Use a fresh output name for each run; existing output files may be overwritten.
Use a fresh name especially with frame/page export to avoid leftover files
from a previous, longer capture.

The original launcher still works:

```sh
uv run python adb_scrollshot.py --select --keep-frames --tile-height 3120
```

You can also use `uv run python -m adb_scrollshot --help`.

## Common options

Run `uv run adb-scrollshot --help` for all options.

| Option | Purpose |
| --- | --- |
| `--select` | Draw the scrolling area; this is the default selection mode. |
| `--roi 0,250,1440,2500` | Specify x, y, width, height in source screenshot pixels. |
| `--whole-screen` | Use only if the entire screen scrolls without fixed UI. |
| `--serial DEVICE_ID` | Choose one device when several are connected. |
| `--keep-frames` | Keep original PNGs for inspection or troubleshooting. |
| `--tile-height 3120` | Also export native-resolution sections, at most 3120 pixels tall. |
| `--pause 1.5` | Wait longer for rendering after each swipe. |
| `--swipe-duration 900` | Make the upward swipe slower, in milliseconds. |
| `--max-swipes 80` | Raise the safety limit; the default is 45. |
| `--layout full-first` | Preserve the entire initial screen, including its footer, before appended content. |

The default `continuous` layout places the initial fixed header at the top and
its fixed footer at the end. When the selected region is narrower than the
screen, appended side margins are copied from the first screenshot; select the
full content width to avoid repeating unrelated side content.

## Quality and limits

View the PNG at **Actual Size / 100%** in your image viewer. Fitting a very tall
image into a window can make sharp text appear blurry. Some messaging apps
also shrink images; send the PNG as a file or share the shorter pages.

The area-selection preview is reduced for convenience, but the saved content
is not resized. PNG compression is lossless. Upscaling or recording at a higher
video bitrate cannot add detail missing from the source screenshots.

Overlap matching assumes vertically translating, static content. Animations,
video, sticky elements inside the selection, repeated patterns, or app layout
changes can prevent reliable matching. The tool stops and saves a partial PNG
when it cannot match safely. Page boundaries may cut through a line of text;
the continuous PNG remains available. Very long captures consume memory.

- **Ctrl+C:** saves progress captured so far.
- **Connection loss during scrolling:** attempts to save progress and exits with code 2.
- **Exit 0:** normal end, user interruption, or swipe limit reached; read the
  terminal message to see whether the bottom was actually detected.
- **Exit 1:** setup or output error; **exit 2:** invalid arguments or a partial
  capture caused by unreliable matching, display changes, or connection failure.

No image is uploaded by this application. Captures can contain private screen
content; they and recordings are excluded from Git and release archives.

## Development

```sh
uv sync --locked
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv build
uv run python scripts/package_release.py
```

The lockfile pins dependencies. CI checks Python 3.11 and 3.14 on Linux and builds
artifacts. The automated tests use synthetic screenshots and simulated ADB;
physical-device behavior still needs a manual smoke test.

```text
src/adb_scrollshot/
  adb.py          Device discovery, commands, and lossless screen capture
  cli.py          Argument parsing and automatic capture loop
  images.py       PNG composition and page export
  matching.py     Overlap matching and end detection
  selection.py    Interactive region selection and validation
  __main__.py     Python module entry point
tests/            Device-free regression tests
scripts/          Source-delivery ZIP builder
docs/             Delivery, installation, and manual validation guide
.github/workflows/ci.yml
```

See [docs/DELIVERY.md](docs/DELIVERY.md) for installation from a wheel, release
contents, a manual acceptance checklist, and Git handoff commands.

## Use as a Python library

Install with `python -m pip install adb-scrollshot` and import `adb_scrollshot`.
You can also install the supplied wheel with
`python -m pip install ./dist/adb_scrollshot-0.1.0-py3-none-any.whl`, or run these
examples inside this checkout with `uv run python`.

Capture a single lossless screen, without scrolling:

```python
from adb_scrollshot import capture_screenshot

image = capture_screenshot("captures/screen.png")
print(image.shape)  # (height, width, 3), uint8 BGR pixels
```

Stitch screenshots captured in top-to-bottom order (each must overlap the last):

```python
import cv2
from adb_scrollshot import export_pages, stitch_screenshots

frames = [cv2.imread(path) for path in ["screen1.png", "screen2.png", "screen3.png"]]
output = stitch_screenshots(
    frames,
    "captures/stitched.png",
    roi=(0, 250, 1440, 2500),  # adapt to your screenshots; exclude fixed UI
)
pages = export_pages(cv2.imread(str(output)), output, tile_height=3120)
```

`stitch_screenshots` accepts an iterable of OpenCV BGR arrays, skips unchanged
captures, and raises `ValueError` on invalid input or unreliable overlap. It
writes only after all frames have been accepted. `capture_screenshot` raises
`RuntimeError` for ADB errors; filesystem errors propagate as `OSError`.
For automatic scrolling, use the `adb-scrollshot` CLI. ADB is required for live
capture, but not for stitching existing frames or exporting pages.

Public PyPI publishing is configured separately. See
[docs/PUBLISHING.md](docs/PUBLISHING.md) for the one-time account setup and release procedure.

## License

MIT. See [LICENSE](LICENSE).
