adb-scrollshot 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adb_scrollshot-0.1.0/.github/workflows/ci.yml +28 -0
- adb_scrollshot-0.1.0/.github/workflows/publish.yml +45 -0
- adb_scrollshot-0.1.0/.gitignore +37 -0
- adb_scrollshot-0.1.0/.python-version +1 -0
- adb_scrollshot-0.1.0/CHANGELOG.md +15 -0
- adb_scrollshot-0.1.0/LICENSE +21 -0
- adb_scrollshot-0.1.0/PKG-INFO +204 -0
- adb_scrollshot-0.1.0/README.md +186 -0
- adb_scrollshot-0.1.0/adb_scrollshot.py +26 -0
- adb_scrollshot-0.1.0/docs/DELIVERY.md +78 -0
- adb_scrollshot-0.1.0/docs/PUBLISHING.md +52 -0
- adb_scrollshot-0.1.0/pyproject.toml +46 -0
- adb_scrollshot-0.1.0/scripts/package_release.py +50 -0
- adb_scrollshot-0.1.0/src/adb_scrollshot/__init__.py +6 -0
- adb_scrollshot-0.1.0/src/adb_scrollshot/__main__.py +3 -0
- adb_scrollshot-0.1.0/src/adb_scrollshot/adb.py +54 -0
- adb_scrollshot-0.1.0/src/adb_scrollshot/api.py +118 -0
- adb_scrollshot-0.1.0/src/adb_scrollshot/cli.py +273 -0
- adb_scrollshot-0.1.0/src/adb_scrollshot/images.py +46 -0
- adb_scrollshot-0.1.0/src/adb_scrollshot/matching.py +91 -0
- adb_scrollshot-0.1.0/src/adb_scrollshot/selection.py +44 -0
- adb_scrollshot-0.1.0/tests/test_scrollshot.py +195 -0
- adb_scrollshot-0.1.0/uv.lock +299 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Checks
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
pull_request:
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
python: ['3.11', '3.14']
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: astral-sh/setup-uv@v6
|
|
16
|
+
with:
|
|
17
|
+
python-version: ${{ matrix.python }}
|
|
18
|
+
- run: uv sync --locked
|
|
19
|
+
- run: uv run ruff check .
|
|
20
|
+
- run: uv run ruff format --check .
|
|
21
|
+
- run: uv run pytest
|
|
22
|
+
- run: uv run adb-scrollshot --help
|
|
23
|
+
- run: uv build
|
|
24
|
+
- run: uv run python scripts/package_release.py
|
|
25
|
+
- uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: adb-scrollshot-python-${{ matrix.python }}
|
|
28
|
+
path: dist/
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
permissions:
|
|
5
|
+
contents: read
|
|
6
|
+
concurrency:
|
|
7
|
+
group: pypi-publish
|
|
8
|
+
cancel-in-progress: false
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
if: github.ref == 'refs/heads/main'
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
persist-credentials: false
|
|
17
|
+
- uses: astral-sh/setup-uv@v6
|
|
18
|
+
with:
|
|
19
|
+
python-version: '3.14'
|
|
20
|
+
- run: uv sync --locked
|
|
21
|
+
- run: uv run ruff check .
|
|
22
|
+
- run: uv run ruff format --check .
|
|
23
|
+
- run: uv run pytest
|
|
24
|
+
- run: uv build
|
|
25
|
+
- uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: pypi-distributions
|
|
28
|
+
path: |
|
|
29
|
+
dist/*.whl
|
|
30
|
+
dist/*.tar.gz
|
|
31
|
+
if-no-files-found: error
|
|
32
|
+
publish:
|
|
33
|
+
needs: build
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
environment:
|
|
36
|
+
name: pypi
|
|
37
|
+
url: https://pypi.org/p/adb-scrollshot
|
|
38
|
+
permissions:
|
|
39
|
+
id-token: write
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/download-artifact@v4
|
|
42
|
+
with:
|
|
43
|
+
name: pypi-distributions
|
|
44
|
+
path: dist/
|
|
45
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Tool caches
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.ruff_cache/
|
|
15
|
+
.coverage
|
|
16
|
+
htmlcov/
|
|
17
|
+
.DS_Store
|
|
18
|
+
|
|
19
|
+
# Local credentials and settings
|
|
20
|
+
.env
|
|
21
|
+
.env.*
|
|
22
|
+
!.env.example
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
25
|
+
|
|
26
|
+
# Captures may contain private phone content; never ship these.
|
|
27
|
+
captures/
|
|
28
|
+
*_frames/
|
|
29
|
+
*_pages/
|
|
30
|
+
*.png
|
|
31
|
+
*.jpg
|
|
32
|
+
*.jpeg
|
|
33
|
+
*.webp
|
|
34
|
+
*.mkv
|
|
35
|
+
*.mp4
|
|
36
|
+
*.mov
|
|
37
|
+
*.zip
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Add public Python functions for lossless screenshot capture, offline stitching,
|
|
6
|
+
and full-resolution page export, with device-free regression tests.
|
|
7
|
+
- Prepare a manually triggered PyPI Trusted Publishing workflow and setup guide.
|
|
8
|
+
- Support importing the library from the checkout alongside the legacy launcher.
|
|
9
|
+
- Package automatic ADB scrolling screenshots as the `adb-scrollshot` command.
|
|
10
|
+
- Separate device access, region selection, matching, and image export modules.
|
|
11
|
+
- Preserve native-resolution PNG output and optional full-resolution page export.
|
|
12
|
+
- Keep the original Python launcher for compatibility.
|
|
13
|
+
- Save captured progress on device-command failure during scrolling.
|
|
14
|
+
- Add locked dependencies, device-free regression tests, CI, and source delivery tooling.
|
|
15
|
+
- Exclude screen captures, recordings, local settings, and caches from Git and releases.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vishal Nagda
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: adb-scrollshot
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lossless Android scrolling screenshots with automatic capture and overlap removal
|
|
5
|
+
Project-URL: Repository, https://github.com/vishalnagda1/adb-scrollshot
|
|
6
|
+
Project-URL: Documentation, https://github.com/vishalnagda1/adb-scrollshot/blob/main/README.md
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: adb,android,image-stitching,screenshot,scrolling
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Requires-Dist: numpy<3,>=2
|
|
16
|
+
Requires-Dist: opencv-python<6,>=4.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# ADB Scrollshot
|
|
20
|
+
|
|
21
|
+
Capture a sharp, continuous scrolling screenshot from an Android phone. The
|
|
22
|
+
command automatically swipes, captures lossless PNG screenshots, removes
|
|
23
|
+
matching overlap, and stops when the selected content stops moving.
|
|
24
|
+
|
|
25
|
+
The final image keeps the original captured pixel resolution. Optional shorter
|
|
26
|
+
PNG pages make long captures easier to view and share.
|
|
27
|
+
|
|
28
|
+
## Requirements
|
|
29
|
+
|
|
30
|
+
- Python 3.11 or newer and [uv](https://docs.astral.sh/uv/).
|
|
31
|
+
- Android Platform Tools (`adb`) on your PATH.
|
|
32
|
+
- An unlocked Android phone with USB debugging enabled and this computer authorized.
|
|
33
|
+
- A desktop session for interactive area selection; use `--roi` otherwise.
|
|
34
|
+
|
|
35
|
+
On macOS, install ADB with `brew install android-platform-tools`. On other
|
|
36
|
+
platforms, install Android Platform Tools and add it to PATH. Confirm that
|
|
37
|
+
`adb devices` lists your phone with the state `device`, not `unauthorized`.
|
|
38
|
+
`adb` is a separate system prerequisite and is not included in this package.
|
|
39
|
+
|
|
40
|
+
## Install from PyPI
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
python -m pip install adb-scrollshot
|
|
44
|
+
adb-scrollshot --select --keep-frames --tile-height 3120 --output captures/high_quality.png
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For an isolated command-line installation, use `uv tool install adb-scrollshot`.
|
|
48
|
+
For Python programs, install into your project's virtual environment and import
|
|
49
|
+
`adb_scrollshot`. Python 3.11 or newer is required.
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
From this project directory:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
uv sync --locked
|
|
57
|
+
uv run adb-scrollshot --select --keep-frames --tile-height 3120 --output captures/high_quality.png
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
1. Open the desired page on your phone and return to its top.
|
|
61
|
+
2. Run the command. Draw a rectangle around **only the scrolling content**,
|
|
62
|
+
excluding fixed toolbars, status bars, navigation bars, and sticky headers.
|
|
63
|
+
3. Press **Enter**. Leave the phone untouched while it scrolls and captures.
|
|
64
|
+
4. Find `captures/high_quality.png`, its original screenshots in
|
|
65
|
+
`captures/high_quality_frames/`, and shorter PNGs in `captures/high_quality_pages/`.
|
|
66
|
+
|
|
67
|
+
`scrcpy` is optional; it can mirror the phone while ADB captures directly.
|
|
68
|
+
Without `--output`, the destination is `captures/long_screenshot.png`.
|
|
69
|
+
Use a fresh output name for each run; existing output files may be overwritten.
|
|
70
|
+
Use a fresh name especially with frame/page export to avoid leftover files
|
|
71
|
+
from a previous, longer capture.
|
|
72
|
+
|
|
73
|
+
The original launcher still works:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
uv run python adb_scrollshot.py --select --keep-frames --tile-height 3120
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
You can also use `uv run python -m adb_scrollshot --help`.
|
|
80
|
+
|
|
81
|
+
## Common options
|
|
82
|
+
|
|
83
|
+
Run `uv run adb-scrollshot --help` for all options.
|
|
84
|
+
|
|
85
|
+
| Option | Purpose |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `--select` | Draw the scrolling area; this is the default selection mode. |
|
|
88
|
+
| `--roi 0,250,1440,2500` | Specify x, y, width, height in source screenshot pixels. |
|
|
89
|
+
| `--whole-screen` | Use only if the entire screen scrolls without fixed UI. |
|
|
90
|
+
| `--serial DEVICE_ID` | Choose one device when several are connected. |
|
|
91
|
+
| `--keep-frames` | Keep original PNGs for inspection or troubleshooting. |
|
|
92
|
+
| `--tile-height 3120` | Also export native-resolution sections, at most 3120 pixels tall. |
|
|
93
|
+
| `--pause 1.5` | Wait longer for rendering after each swipe. |
|
|
94
|
+
| `--swipe-duration 900` | Make the upward swipe slower, in milliseconds. |
|
|
95
|
+
| `--max-swipes 80` | Raise the safety limit; the default is 45. |
|
|
96
|
+
| `--layout full-first` | Preserve the entire initial screen, including its footer, before appended content. |
|
|
97
|
+
|
|
98
|
+
The default `continuous` layout places the initial fixed header at the top and
|
|
99
|
+
its fixed footer at the end. When the selected region is narrower than the
|
|
100
|
+
screen, appended side margins are copied from the first screenshot; select the
|
|
101
|
+
full content width to avoid repeating unrelated side content.
|
|
102
|
+
|
|
103
|
+
## Quality and limits
|
|
104
|
+
|
|
105
|
+
View the PNG at **Actual Size / 100%** in your image viewer. Fitting a very tall
|
|
106
|
+
image into a window can make sharp text appear blurry. Some messaging apps
|
|
107
|
+
also shrink images; send the PNG as a file or share the shorter pages.
|
|
108
|
+
|
|
109
|
+
The area-selection preview is reduced for convenience, but the saved content
|
|
110
|
+
is not resized. PNG compression is lossless. Upscaling or recording at a higher
|
|
111
|
+
video bitrate cannot add detail missing from the source screenshots.
|
|
112
|
+
|
|
113
|
+
Overlap matching assumes vertically translating, static content. Animations,
|
|
114
|
+
video, sticky elements inside the selection, repeated patterns, or app layout
|
|
115
|
+
changes can prevent reliable matching. The tool stops and saves a partial PNG
|
|
116
|
+
when it cannot match safely. Page boundaries may cut through a line of text;
|
|
117
|
+
the continuous PNG remains available. Very long captures consume memory.
|
|
118
|
+
|
|
119
|
+
- **Ctrl+C:** saves progress captured so far.
|
|
120
|
+
- **Connection loss during scrolling:** attempts to save progress and exits with code 2.
|
|
121
|
+
- **Exit 0:** normal end, user interruption, or swipe limit reached; read the
|
|
122
|
+
terminal message to see whether the bottom was actually detected.
|
|
123
|
+
- **Exit 1:** setup or output error; **exit 2:** invalid arguments or a partial
|
|
124
|
+
capture caused by unreliable matching, display changes, or connection failure.
|
|
125
|
+
|
|
126
|
+
No image is uploaded by this application. Captures can contain private screen
|
|
127
|
+
content; they and recordings are excluded from Git and release archives.
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
uv sync --locked
|
|
133
|
+
uv run pytest
|
|
134
|
+
uv run ruff check .
|
|
135
|
+
uv run ruff format --check .
|
|
136
|
+
uv build
|
|
137
|
+
uv run python scripts/package_release.py
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The lockfile pins dependencies. CI checks Python 3.11 and 3.14 on Linux and builds
|
|
141
|
+
artifacts. The automated tests use synthetic screenshots and simulated ADB;
|
|
142
|
+
physical-device behavior still needs a manual smoke test.
|
|
143
|
+
|
|
144
|
+
```text
|
|
145
|
+
src/adb_scrollshot/
|
|
146
|
+
adb.py Device discovery, commands, and lossless screen capture
|
|
147
|
+
cli.py Argument parsing and automatic capture loop
|
|
148
|
+
images.py PNG composition and page export
|
|
149
|
+
matching.py Overlap matching and end detection
|
|
150
|
+
selection.py Interactive region selection and validation
|
|
151
|
+
__main__.py Python module entry point
|
|
152
|
+
tests/ Device-free regression tests
|
|
153
|
+
scripts/ Source-delivery ZIP builder
|
|
154
|
+
docs/ Delivery, installation, and manual validation guide
|
|
155
|
+
.github/workflows/ci.yml
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
See [docs/DELIVERY.md](docs/DELIVERY.md) for installation from a wheel, release
|
|
159
|
+
contents, a manual acceptance checklist, and Git handoff commands.
|
|
160
|
+
|
|
161
|
+
## Use as a Python library
|
|
162
|
+
|
|
163
|
+
Install with `python -m pip install adb-scrollshot` and import `adb_scrollshot`.
|
|
164
|
+
You can also install the supplied wheel with
|
|
165
|
+
`python -m pip install ./dist/adb_scrollshot-0.1.0-py3-none-any.whl`, or run these
|
|
166
|
+
examples inside this checkout with `uv run python`.
|
|
167
|
+
|
|
168
|
+
Capture a single lossless screen, without scrolling:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from adb_scrollshot import capture_screenshot
|
|
172
|
+
|
|
173
|
+
image = capture_screenshot("captures/screen.png")
|
|
174
|
+
print(image.shape) # (height, width, 3), uint8 BGR pixels
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Stitch screenshots captured in top-to-bottom order (each must overlap the last):
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
import cv2
|
|
181
|
+
from adb_scrollshot import export_pages, stitch_screenshots
|
|
182
|
+
|
|
183
|
+
frames = [cv2.imread(path) for path in ["screen1.png", "screen2.png", "screen3.png"]]
|
|
184
|
+
output = stitch_screenshots(
|
|
185
|
+
frames,
|
|
186
|
+
"captures/stitched.png",
|
|
187
|
+
roi=(0, 250, 1440, 2500), # adapt to your screenshots; exclude fixed UI
|
|
188
|
+
)
|
|
189
|
+
pages = export_pages(cv2.imread(str(output)), output, tile_height=3120)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`stitch_screenshots` accepts an iterable of OpenCV BGR arrays, skips unchanged
|
|
193
|
+
captures, and raises `ValueError` on invalid input or unreliable overlap. It
|
|
194
|
+
writes only after all frames have been accepted. `capture_screenshot` raises
|
|
195
|
+
`RuntimeError` for ADB errors; filesystem errors propagate as `OSError`.
|
|
196
|
+
For automatic scrolling, use the `adb-scrollshot` CLI. ADB is required for live
|
|
197
|
+
capture, but not for stitching existing frames or exporting pages.
|
|
198
|
+
|
|
199
|
+
Public PyPI publishing is configured separately. See
|
|
200
|
+
[docs/PUBLISHING.md](docs/PUBLISHING.md) for the one-time account setup and release procedure.
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# ADB Scrollshot
|
|
2
|
+
|
|
3
|
+
Capture a sharp, continuous scrolling screenshot from an Android phone. The
|
|
4
|
+
command automatically swipes, captures lossless PNG screenshots, removes
|
|
5
|
+
matching overlap, and stops when the selected content stops moving.
|
|
6
|
+
|
|
7
|
+
The final image keeps the original captured pixel resolution. Optional shorter
|
|
8
|
+
PNG pages make long captures easier to view and share.
|
|
9
|
+
|
|
10
|
+
## Requirements
|
|
11
|
+
|
|
12
|
+
- Python 3.11 or newer and [uv](https://docs.astral.sh/uv/).
|
|
13
|
+
- Android Platform Tools (`adb`) on your PATH.
|
|
14
|
+
- An unlocked Android phone with USB debugging enabled and this computer authorized.
|
|
15
|
+
- A desktop session for interactive area selection; use `--roi` otherwise.
|
|
16
|
+
|
|
17
|
+
On macOS, install ADB with `brew install android-platform-tools`. On other
|
|
18
|
+
platforms, install Android Platform Tools and add it to PATH. Confirm that
|
|
19
|
+
`adb devices` lists your phone with the state `device`, not `unauthorized`.
|
|
20
|
+
`adb` is a separate system prerequisite and is not included in this package.
|
|
21
|
+
|
|
22
|
+
## Install from PyPI
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
python -m pip install adb-scrollshot
|
|
26
|
+
adb-scrollshot --select --keep-frames --tile-height 3120 --output captures/high_quality.png
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For an isolated command-line installation, use `uv tool install adb-scrollshot`.
|
|
30
|
+
For Python programs, install into your project's virtual environment and import
|
|
31
|
+
`adb_scrollshot`. Python 3.11 or newer is required.
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
From this project directory:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
uv sync --locked
|
|
39
|
+
uv run adb-scrollshot --select --keep-frames --tile-height 3120 --output captures/high_quality.png
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
1. Open the desired page on your phone and return to its top.
|
|
43
|
+
2. Run the command. Draw a rectangle around **only the scrolling content**,
|
|
44
|
+
excluding fixed toolbars, status bars, navigation bars, and sticky headers.
|
|
45
|
+
3. Press **Enter**. Leave the phone untouched while it scrolls and captures.
|
|
46
|
+
4. Find `captures/high_quality.png`, its original screenshots in
|
|
47
|
+
`captures/high_quality_frames/`, and shorter PNGs in `captures/high_quality_pages/`.
|
|
48
|
+
|
|
49
|
+
`scrcpy` is optional; it can mirror the phone while ADB captures directly.
|
|
50
|
+
Without `--output`, the destination is `captures/long_screenshot.png`.
|
|
51
|
+
Use a fresh output name for each run; existing output files may be overwritten.
|
|
52
|
+
Use a fresh name especially with frame/page export to avoid leftover files
|
|
53
|
+
from a previous, longer capture.
|
|
54
|
+
|
|
55
|
+
The original launcher still works:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
uv run python adb_scrollshot.py --select --keep-frames --tile-height 3120
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
You can also use `uv run python -m adb_scrollshot --help`.
|
|
62
|
+
|
|
63
|
+
## Common options
|
|
64
|
+
|
|
65
|
+
Run `uv run adb-scrollshot --help` for all options.
|
|
66
|
+
|
|
67
|
+
| Option | Purpose |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `--select` | Draw the scrolling area; this is the default selection mode. |
|
|
70
|
+
| `--roi 0,250,1440,2500` | Specify x, y, width, height in source screenshot pixels. |
|
|
71
|
+
| `--whole-screen` | Use only if the entire screen scrolls without fixed UI. |
|
|
72
|
+
| `--serial DEVICE_ID` | Choose one device when several are connected. |
|
|
73
|
+
| `--keep-frames` | Keep original PNGs for inspection or troubleshooting. |
|
|
74
|
+
| `--tile-height 3120` | Also export native-resolution sections, at most 3120 pixels tall. |
|
|
75
|
+
| `--pause 1.5` | Wait longer for rendering after each swipe. |
|
|
76
|
+
| `--swipe-duration 900` | Make the upward swipe slower, in milliseconds. |
|
|
77
|
+
| `--max-swipes 80` | Raise the safety limit; the default is 45. |
|
|
78
|
+
| `--layout full-first` | Preserve the entire initial screen, including its footer, before appended content. |
|
|
79
|
+
|
|
80
|
+
The default `continuous` layout places the initial fixed header at the top and
|
|
81
|
+
its fixed footer at the end. When the selected region is narrower than the
|
|
82
|
+
screen, appended side margins are copied from the first screenshot; select the
|
|
83
|
+
full content width to avoid repeating unrelated side content.
|
|
84
|
+
|
|
85
|
+
## Quality and limits
|
|
86
|
+
|
|
87
|
+
View the PNG at **Actual Size / 100%** in your image viewer. Fitting a very tall
|
|
88
|
+
image into a window can make sharp text appear blurry. Some messaging apps
|
|
89
|
+
also shrink images; send the PNG as a file or share the shorter pages.
|
|
90
|
+
|
|
91
|
+
The area-selection preview is reduced for convenience, but the saved content
|
|
92
|
+
is not resized. PNG compression is lossless. Upscaling or recording at a higher
|
|
93
|
+
video bitrate cannot add detail missing from the source screenshots.
|
|
94
|
+
|
|
95
|
+
Overlap matching assumes vertically translating, static content. Animations,
|
|
96
|
+
video, sticky elements inside the selection, repeated patterns, or app layout
|
|
97
|
+
changes can prevent reliable matching. The tool stops and saves a partial PNG
|
|
98
|
+
when it cannot match safely. Page boundaries may cut through a line of text;
|
|
99
|
+
the continuous PNG remains available. Very long captures consume memory.
|
|
100
|
+
|
|
101
|
+
- **Ctrl+C:** saves progress captured so far.
|
|
102
|
+
- **Connection loss during scrolling:** attempts to save progress and exits with code 2.
|
|
103
|
+
- **Exit 0:** normal end, user interruption, or swipe limit reached; read the
|
|
104
|
+
terminal message to see whether the bottom was actually detected.
|
|
105
|
+
- **Exit 1:** setup or output error; **exit 2:** invalid arguments or a partial
|
|
106
|
+
capture caused by unreliable matching, display changes, or connection failure.
|
|
107
|
+
|
|
108
|
+
No image is uploaded by this application. Captures can contain private screen
|
|
109
|
+
content; they and recordings are excluded from Git and release archives.
|
|
110
|
+
|
|
111
|
+
## Development
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
uv sync --locked
|
|
115
|
+
uv run pytest
|
|
116
|
+
uv run ruff check .
|
|
117
|
+
uv run ruff format --check .
|
|
118
|
+
uv build
|
|
119
|
+
uv run python scripts/package_release.py
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The lockfile pins dependencies. CI checks Python 3.11 and 3.14 on Linux and builds
|
|
123
|
+
artifacts. The automated tests use synthetic screenshots and simulated ADB;
|
|
124
|
+
physical-device behavior still needs a manual smoke test.
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
src/adb_scrollshot/
|
|
128
|
+
adb.py Device discovery, commands, and lossless screen capture
|
|
129
|
+
cli.py Argument parsing and automatic capture loop
|
|
130
|
+
images.py PNG composition and page export
|
|
131
|
+
matching.py Overlap matching and end detection
|
|
132
|
+
selection.py Interactive region selection and validation
|
|
133
|
+
__main__.py Python module entry point
|
|
134
|
+
tests/ Device-free regression tests
|
|
135
|
+
scripts/ Source-delivery ZIP builder
|
|
136
|
+
docs/ Delivery, installation, and manual validation guide
|
|
137
|
+
.github/workflows/ci.yml
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
See [docs/DELIVERY.md](docs/DELIVERY.md) for installation from a wheel, release
|
|
141
|
+
contents, a manual acceptance checklist, and Git handoff commands.
|
|
142
|
+
|
|
143
|
+
## Use as a Python library
|
|
144
|
+
|
|
145
|
+
Install with `python -m pip install adb-scrollshot` and import `adb_scrollshot`.
|
|
146
|
+
You can also install the supplied wheel with
|
|
147
|
+
`python -m pip install ./dist/adb_scrollshot-0.1.0-py3-none-any.whl`, or run these
|
|
148
|
+
examples inside this checkout with `uv run python`.
|
|
149
|
+
|
|
150
|
+
Capture a single lossless screen, without scrolling:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from adb_scrollshot import capture_screenshot
|
|
154
|
+
|
|
155
|
+
image = capture_screenshot("captures/screen.png")
|
|
156
|
+
print(image.shape) # (height, width, 3), uint8 BGR pixels
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Stitch screenshots captured in top-to-bottom order (each must overlap the last):
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
import cv2
|
|
163
|
+
from adb_scrollshot import export_pages, stitch_screenshots
|
|
164
|
+
|
|
165
|
+
frames = [cv2.imread(path) for path in ["screen1.png", "screen2.png", "screen3.png"]]
|
|
166
|
+
output = stitch_screenshots(
|
|
167
|
+
frames,
|
|
168
|
+
"captures/stitched.png",
|
|
169
|
+
roi=(0, 250, 1440, 2500), # adapt to your screenshots; exclude fixed UI
|
|
170
|
+
)
|
|
171
|
+
pages = export_pages(cv2.imread(str(output)), output, tile_height=3120)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`stitch_screenshots` accepts an iterable of OpenCV BGR arrays, skips unchanged
|
|
175
|
+
captures, and raises `ValueError` on invalid input or unreliable overlap. It
|
|
176
|
+
writes only after all frames have been accepted. `capture_screenshot` raises
|
|
177
|
+
`RuntimeError` for ADB errors; filesystem errors propagate as `OSError`.
|
|
178
|
+
For automatic scrolling, use the `adb-scrollshot` CLI. ADB is required for live
|
|
179
|
+
capture, but not for stitching existing frames or exporting pages.
|
|
180
|
+
|
|
181
|
+
Public PyPI publishing is configured separately. See
|
|
182
|
+
[docs/PUBLISHING.md](docs/PUBLISHING.md) for the one-time account setup and release procedure.
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Compatibility launcher; preferred usage: uv run adb-scrollshot --select."""
|
|
3
|
+
|
|
4
|
+
import importlib.util
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
source = Path(__file__).resolve().parent / "src"
|
|
9
|
+
|
|
10
|
+
if __name__ == "__main__":
|
|
11
|
+
# Keep the original direct-script command working from a source release.
|
|
12
|
+
sys.path.insert(0, str(source))
|
|
13
|
+
from adb_scrollshot.cli import entrypoint
|
|
14
|
+
|
|
15
|
+
raise SystemExit(entrypoint())
|
|
16
|
+
else:
|
|
17
|
+
# A checkout-level launcher must not mask the importable src package.
|
|
18
|
+
spec = importlib.util.spec_from_file_location(
|
|
19
|
+
__name__,
|
|
20
|
+
source / "adb_scrollshot" / "__init__.py",
|
|
21
|
+
submodule_search_locations=[str(source / "adb_scrollshot")],
|
|
22
|
+
)
|
|
23
|
+
assert spec is not None and spec.loader is not None
|
|
24
|
+
package = importlib.util.module_from_spec(spec)
|
|
25
|
+
sys.modules[__name__] = package
|
|
26
|
+
spec.loader.exec_module(package)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Delivery and handoff
|
|
2
|
+
|
|
3
|
+
## Build
|
|
4
|
+
|
|
5
|
+
From a checkout or extracted source ZIP:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
uv sync --locked
|
|
9
|
+
uv run ruff check .
|
|
10
|
+
uv run ruff format --check .
|
|
11
|
+
uv run pytest
|
|
12
|
+
uv build
|
|
13
|
+
uv run python scripts/package_release.py
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`dist/` contains an installable wheel, a source distribution (`.tar.gz`), a
|
|
17
|
+
source-project ZIP, and its SHA256 checksum. The ZIP includes source, tests,
|
|
18
|
+
CI configuration, documentation, and the lockfile. It excludes screenshots,
|
|
19
|
+
recordings, credentials, virtual environments, caches, and Git history.
|
|
20
|
+
|
|
21
|
+
These are Python deliverables, not a standalone macOS app. Recipients need
|
|
22
|
+
Python, ADB, and a phone with USB debugging authorized. Installing Python
|
|
23
|
+
packages may require network access. The wheel includes the CLI and runtime
|
|
24
|
+
package; tests and development tools are in the source deliverables.
|
|
25
|
+
|
|
26
|
+
## Install the wheel
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
uv tool install ./adb_scrollshot-0.1.0-py3-none-any.whl
|
|
30
|
+
adb-scrollshot --help
|
|
31
|
+
adb-scrollshot --select --keep-frames --tile-height 3120 --output captures/result.png
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use the wheel's actual location, for example `./dist/adb_scrollshot-0.1.0-py3-none-any.whl`
|
|
35
|
+
when installing from the checkout. If the command is not on PATH after tool
|
|
36
|
+
installation, follow uv's PATH instructions or run `uv tool update-shell` and
|
|
37
|
+
open a new terminal.
|
|
38
|
+
|
|
39
|
+
Alternatively, unzip the source release, change into its directory, and use
|
|
40
|
+
`uv sync --locked` followed by `uv run adb-scrollshot ...`.
|
|
41
|
+
|
|
42
|
+
## Manual acceptance checklist
|
|
43
|
+
|
|
44
|
+
1. Confirm `adb devices` reports an authorized device.
|
|
45
|
+
2. Open a static page at its top and select only the scrolling viewport.
|
|
46
|
+
3. Capture several screens with `--keep-frames --tile-height 3120`.
|
|
47
|
+
4. Confirm headers/footers appear as intended, joins have no missing or repeated
|
|
48
|
+
content, and the final PNG width matches the original frame width.
|
|
49
|
+
5. Inspect text at Actual Size; confirm shorter pages retain the same detail.
|
|
50
|
+
6. Confirm the terminal reports bottom detection rather than a safety-limit stop.
|
|
51
|
+
7. On a disposable capture, press Ctrl+C and verify progress is saved.
|
|
52
|
+
|
|
53
|
+
Automated tests verify native-pixel overlap, lossless PNG round trips, device
|
|
54
|
+
selection errors, automatic end detection, and saving progress on interruption,
|
|
55
|
+
connection loss, or failed matching. They do not establish compatibility with
|
|
56
|
+
every app or physical phone. Linux CI is configured but must run on the hosting
|
|
57
|
+
service after push; macOS is the local development environment.
|
|
58
|
+
|
|
59
|
+
## Git handoff
|
|
60
|
+
|
|
61
|
+
The repository is initialized locally. Review and create your initial commit:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
git status --short
|
|
65
|
+
git add .gitignore .python-version pyproject.toml uv.lock README.md CHANGELOG.md adb_scrollshot.py src tests scripts docs .github
|
|
66
|
+
git diff --cached --stat
|
|
67
|
+
git commit -m "Package ADB Scrollshot with CLI, tests, and delivery tooling"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
After creating a remote repository under your account, add its URL and push:
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
git remote add origin YOUR_REPOSITORY_URL
|
|
74
|
+
git push -u origin main
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The project uses the MIT license, with copyright attributed to Vishal Nagda.
|
|
78
|
+
See [PUBLISHING.md](PUBLISHING.md) for public PyPI release instructions.
|