scanlib 1.0.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.
scanlib-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Angelo Mottola
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.
scanlib-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: scanlib
3
+ Version: 1.0.0
4
+ Summary: A multiplatform document scanning library for Python
5
+ Author-email: Angelo Mottola <a.mottola@gmail.com>
6
+ License: MIT
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: comtypes>=1.4; sys_platform == "win32"
11
+ Requires-Dist: pyobjc-framework-ImageCaptureCore; sys_platform == "darwin"
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest; extra == "dev"
14
+ Requires-Dist: pytest-timeout; extra == "dev"
15
+ Requires-Dist: pre-commit; extra == "dev"
16
+ Provides-Extra: docs
17
+ Requires-Dist: sphinx; extra == "docs"
18
+ Requires-Dist: furo; extra == "docs"
19
+ Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
20
+ Dynamic: license-file
21
+
22
+ # scanlib
23
+
24
+ [![Tests](https://github.com/amottola/scanlib/actions/workflows/test.yml/badge.svg)](https://github.com/amottola/scanlib/actions/workflows/test.yml)
25
+ [![Build & Publish](https://github.com/amottola/scanlib/actions/workflows/wheels.yml/badge.svg)](https://github.com/amottola/scanlib/actions/workflows/wheels.yml)
26
+ [![Documentation](https://readthedocs.org/projects/python-scanlib/badge/?version=latest)](https://python-scanlib.readthedocs.io/)
27
+
28
+ A multiplatform document scanning library for Python with platform-native scanning backends and minimal dependencies.
29
+
30
+ ## Features
31
+
32
+ - **Cross-platform** — unified API across Windows (WIA 2.0), macOS (ImageCaptureCore), and Linux (SANE)
33
+ - **Output to PDF** — assemble scanned pages into a PDF and control page encoding (JPEG or PNG)
34
+ - **Minimal dependencies** — no external image or PDF processing libraries; JPEG uses platform-native encoders, PNG uses stdlib `zlib`, PDF assembly uses only the standard library
35
+ - **Multi-page scanning** — automatic document feeder support and flatbed multi-page with a simple callback
36
+ - **Page-level control** — preview, rotate, reorder, and encode individual pages as JPEG or PNG before assembling the final PDF
37
+ - **Thread-safe** — call from any thread; backend threading is handled internally
38
+ - **Progress & cancellation** — monitor scan progress and abort mid-scan via callback
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install scanlib
44
+ ```
45
+
46
+ Python 3.9+. Pre-built wheels available for all major platforms. On Linux, `libsane` and `libjpeg-turbo` are required at runtime (`apt install libsane-dev libturbojpeg0-dev`); on other platforms, no additional dependencies are required.
47
+
48
+ ## Quick Start
49
+
50
+ ```python
51
+ import scanlib
52
+
53
+ scanners = scanlib.list_scanners()
54
+
55
+ with scanners[0] as scanner:
56
+ doc = scanner.scan()
57
+
58
+ with open("output.pdf", "wb") as f:
59
+ f.write(doc.data)
60
+ ```
61
+
62
+ ## Documentation
63
+
64
+ Full documentation is available at [python-scanlib.readthedocs.io](https://python-scanlib.readthedocs.io/).
65
+
66
+ ## About
67
+
68
+ Created by Angelo Mottola, with the help of [Claude Code](https://claude.ai/code).
69
+
70
+ This project was started to fill a void in the Python scanning ecosystem, which I found to be very much fragmented. It is also my first experiment in heavily AI-assisted software development (I still hesitate to use the term "vibe" coding), where I mostly did code review and direction.
71
+
72
+ ## License
73
+
74
+ MIT
@@ -0,0 +1,53 @@
1
+ # scanlib
2
+
3
+ [![Tests](https://github.com/amottola/scanlib/actions/workflows/test.yml/badge.svg)](https://github.com/amottola/scanlib/actions/workflows/test.yml)
4
+ [![Build & Publish](https://github.com/amottola/scanlib/actions/workflows/wheels.yml/badge.svg)](https://github.com/amottola/scanlib/actions/workflows/wheels.yml)
5
+ [![Documentation](https://readthedocs.org/projects/python-scanlib/badge/?version=latest)](https://python-scanlib.readthedocs.io/)
6
+
7
+ A multiplatform document scanning library for Python with platform-native scanning backends and minimal dependencies.
8
+
9
+ ## Features
10
+
11
+ - **Cross-platform** — unified API across Windows (WIA 2.0), macOS (ImageCaptureCore), and Linux (SANE)
12
+ - **Output to PDF** — assemble scanned pages into a PDF and control page encoding (JPEG or PNG)
13
+ - **Minimal dependencies** — no external image or PDF processing libraries; JPEG uses platform-native encoders, PNG uses stdlib `zlib`, PDF assembly uses only the standard library
14
+ - **Multi-page scanning** — automatic document feeder support and flatbed multi-page with a simple callback
15
+ - **Page-level control** — preview, rotate, reorder, and encode individual pages as JPEG or PNG before assembling the final PDF
16
+ - **Thread-safe** — call from any thread; backend threading is handled internally
17
+ - **Progress & cancellation** — monitor scan progress and abort mid-scan via callback
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install scanlib
23
+ ```
24
+
25
+ Python 3.9+. Pre-built wheels available for all major platforms. On Linux, `libsane` and `libjpeg-turbo` are required at runtime (`apt install libsane-dev libturbojpeg0-dev`); on other platforms, no additional dependencies are required.
26
+
27
+ ## Quick Start
28
+
29
+ ```python
30
+ import scanlib
31
+
32
+ scanners = scanlib.list_scanners()
33
+
34
+ with scanners[0] as scanner:
35
+ doc = scanner.scan()
36
+
37
+ with open("output.pdf", "wb") as f:
38
+ f.write(doc.data)
39
+ ```
40
+
41
+ ## Documentation
42
+
43
+ Full documentation is available at [python-scanlib.readthedocs.io](https://python-scanlib.readthedocs.io/).
44
+
45
+ ## About
46
+
47
+ Created by Angelo Mottola, with the help of [Claude Code](https://claude.ai/code).
48
+
49
+ This project was started to fill a void in the Python scanning ecosystem, which I found to be very much fragmented. It is also my first experiment in heavily AI-assisted software development (I still hesitate to use the term "vibe" coding), where I mostly did code review and direction.
50
+
51
+ ## License
52
+
53
+ MIT
@@ -0,0 +1,52 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "scanlib"
7
+ version = "1.0.0"
8
+ description = "A multiplatform document scanning library for Python"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [{name = "Angelo Mottola", email = "a.mottola@gmail.com"}]
12
+ requires-python = ">=3.9"
13
+ dependencies = [
14
+ "comtypes>=1.4; sys_platform == 'win32'",
15
+ "pyobjc-framework-ImageCaptureCore; sys_platform == 'darwin'",
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ dev = ["pytest", "pytest-timeout", "pre-commit"]
20
+ docs = ["sphinx", "furo", "sphinx-autodoc-typehints"]
21
+
22
+ [tool.pytest.ini_options]
23
+ markers = ["hardware: tests requiring a physical scanner"]
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["src"]
27
+
28
+ [tool.black]
29
+ line-length = 88
30
+ target-version = ["py39"]
31
+
32
+ [tool.cibuildwheel]
33
+ build = "cp39-* cp314t-*"
34
+ skip = "*-musllinux_*"
35
+ test-requires = ["pytest", "pytest-timeout"]
36
+ test-command = "pytest {project}/tests --ignore={project}/tests/test_hardware.py -v"
37
+ enable = ["cpython-freethreading"]
38
+
39
+ [tool.cibuildwheel.linux]
40
+ archs = ["x86_64", "aarch64"]
41
+ before-build = [
42
+ "yum install -y libjpeg-turbo-devel 2>/dev/null || apk add libjpeg-turbo-dev 2>/dev/null || true",
43
+ ]
44
+ before-test = [
45
+ "yum install -y libjpeg-turbo-devel 2>/dev/null || apk add libjpeg-turbo-dev 2>/dev/null || true",
46
+ ]
47
+
48
+ [tool.cibuildwheel.macos]
49
+ archs = ["universal2"]
50
+
51
+ [tool.cibuildwheel.windows]
52
+ archs = ["AMD64"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
scanlib-1.0.0/setup.py ADDED
@@ -0,0 +1,34 @@
1
+ import sys
2
+ import sysconfig
3
+
4
+ from setuptools import Extension, setup
5
+
6
+ define_macros = []
7
+ libraries = []
8
+
9
+ if sys.platform == "linux":
10
+ define_macros.append(("HAVE_JPEGLIB", "1"))
11
+ libraries.append("jpeg")
12
+
13
+ # Use stable ABI (abi3) for non-free-threaded builds
14
+ free_threaded = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
15
+ py_limited_api = not free_threaded
16
+ if py_limited_api:
17
+ define_macros.append(("Py_LIMITED_API", "0x03090000"))
18
+
19
+ options = {}
20
+ if py_limited_api:
21
+ options["bdist_wheel"] = {"py_limited_api": "cp39"}
22
+
23
+ setup(
24
+ ext_modules=[
25
+ Extension(
26
+ "_scanlib_accel",
27
+ sources=["src/accel/_scanlib_accel.c"],
28
+ define_macros=define_macros,
29
+ libraries=libraries,
30
+ py_limited_api=py_limited_api,
31
+ )
32
+ ],
33
+ options=options,
34
+ )