pith-image 0.1.1b1__py3-none-win_amd64.whl

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.
pith_image/__init__.py ADDED
@@ -0,0 +1,151 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 pith-hash
3
+ """pith-image SDK: the 64-bit image perceptual hash through ctypes.
4
+
5
+ The single Rust core (the ``pith-image`` cdylib built by
6
+ ``cargo build --release``) is loaded at runtime; this package carries
7
+ no third-party dependency — ``ctypes`` is the standard library.
8
+
9
+ Discovery order (the suite's cdylib convention):
10
+
11
+ 1. ``PITH_CDYLIB`` — an explicit cdylib *file* path;
12
+ 2. ``PITH_CDYLIB_DIR`` — a *directory* scanned for the cdylib names
13
+ (the CD pipeline points this at ``target/release``);
14
+ 3. the package directory itself (the built wheel ships the cdylib as
15
+ package data);
16
+ 4. ``<repo root>/target/release`` — the repository working-tree layout,
17
+ so a source checkout runs against a local cargo build with no
18
+ configuration.
19
+
20
+ The vectors in ``reference.json`` at the repository root are the
21
+ hex-exact cross-language source of truth; the conformance tests under
22
+ ``tests/`` replay all of them through this binding.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import ctypes
28
+ import os
29
+ from pathlib import Path
30
+
31
+ __all__ = [
32
+ "FfiError",
33
+ "LibraryNotFoundError",
34
+ "find_cdylib",
35
+ "image_phash",
36
+ "LAYOUT_GRAY8",
37
+ "LAYOUT_GRAY16",
38
+ "LAYOUT_RGB8",
39
+ "LAYOUT_RGB16",
40
+ "LAYOUT_RGBA8",
41
+ "STATUS_OK",
42
+ "STATUS_INVALID",
43
+ "STATUS_REJECTED",
44
+ ]
45
+
46
+ #: Status: success.
47
+ STATUS_OK = 0
48
+ #: Status: a caller argument is invalid (null pointer, unknown layout
49
+ #: code, length/geometry mismatch).
50
+ STATUS_INVALID = -1
51
+ #: Status: the core pipeline refused the input.
52
+ STATUS_REJECTED = -2
53
+
54
+ #: Raw dump layouts, in ``RawLayout`` declaration order.
55
+ LAYOUT_GRAY8 = 0
56
+ LAYOUT_GRAY16 = 1
57
+ LAYOUT_RGB8 = 2
58
+ LAYOUT_RGB16 = 3
59
+ LAYOUT_RGBA8 = 4
60
+
61
+ #: Every cdylib file name cargo may drop into the build directory, per
62
+ #: platform (windows / linux / macOS).
63
+ CDYLIB_NAMES = ("pith_image.dll", "libpith_image.so", "libpith_image.dylib")
64
+
65
+
66
+ class LibraryNotFoundError(OSError):
67
+ """No cdylib was found through the discovery chain."""
68
+
69
+
70
+ class FfiError(Exception):
71
+ """A non-zero status code came back from the cdylib."""
72
+
73
+ def __init__(self, op: str, status: int) -> None:
74
+ kind = {
75
+ STATUS_INVALID: "invalid argument",
76
+ STATUS_REJECTED: "input rejected",
77
+ }.get(status, "unknown failure")
78
+ super().__init__(f"{op} failed: {kind} (status {status})")
79
+ #: The raw status code the FFI returned.
80
+ self.status = status
81
+
82
+
83
+ def find_cdylib() -> Path:
84
+ """Locates the cdylib through the suite's discovery chain."""
85
+ explicit = os.environ.get("PITH_CDYLIB")
86
+ if explicit:
87
+ p = Path(explicit)
88
+ if p.is_file():
89
+ return p
90
+ env_dir = os.environ.get("PITH_CDYLIB_DIR")
91
+ candidates: list[Path] = []
92
+ if env_dir:
93
+ env_dir_path = Path(env_dir)
94
+ candidates.append(env_dir_path)
95
+ if not env_dir_path.is_absolute():
96
+ # CD and local runs invoke tools from the repository root or
97
+ # from sdk/<lang>; resolve the env value against both.
98
+ candidates.append(Path.cwd() / env_dir_path)
99
+ candidates.append(Path(__file__).resolve().parents[3] / env_dir_path)
100
+ candidates.append(Path(__file__).resolve().parent) # packaged wheel
101
+ candidates.append(Path(__file__).resolve().parents[3] / "target" / "release")
102
+ for directory in candidates:
103
+ for name in CDYLIB_NAMES:
104
+ p = directory / name
105
+ if p.is_file():
106
+ return p
107
+ raise LibraryNotFoundError(
108
+ "no pith-image cdylib found (searched PITH_CDYLIB, PITH_CDYLIB_DIR, "
109
+ "the package directory and <repo>/target/release); "
110
+ "run `cargo build --release` first"
111
+ )
112
+
113
+
114
+ _lib: ctypes.CDLL | None = None
115
+
116
+
117
+ def _load() -> ctypes.CDLL:
118
+ global _lib
119
+ if _lib is None:
120
+ lib = ctypes.CDLL(str(find_cdylib()))
121
+ lib.pith_image_phash.argtypes = [
122
+ ctypes.c_void_p, # data
123
+ ctypes.c_size_t, # len
124
+ ctypes.c_uint32, # width
125
+ ctypes.c_uint32, # height
126
+ ctypes.c_uint32, # layout
127
+ ctypes.POINTER(ctypes.c_uint64), # out hash
128
+ ]
129
+ lib.pith_image_phash.restype = ctypes.c_int32
130
+ _lib = lib
131
+ return _lib
132
+
133
+
134
+ def image_phash(dump: bytes, width: int, height: int, layout: int) -> int:
135
+ """Computes the 64-bit perceptual hash of a raw pixel dump.
136
+
137
+ ``dump`` is a flat, row-major, channel-interleaved buffer of
138
+ ``width * height * channels`` samples (little-endian for the 16-bit
139
+ layouts) — the format the fixtures under ``tests/fixtures/phash/``
140
+ commit. Returns the hash as an ``int``; render it with
141
+ ``format(hash, "016x")`` to compare against ``reference.json``.
142
+ """
143
+ if width <= 0 or height <= 0:
144
+ raise ValueError("width and height must be positive")
145
+ if layout not in (LAYOUT_GRAY8, LAYOUT_GRAY16, LAYOUT_RGB8, LAYOUT_RGB16, LAYOUT_RGBA8):
146
+ raise ValueError(f"unknown layout code {layout}")
147
+ out = ctypes.c_uint64()
148
+ status = _load().pith_image_phash(dump, len(dump), width, height, layout, ctypes.byref(out))
149
+ if status != STATUS_OK:
150
+ raise FfiError("pith_image_phash", status)
151
+ return out.value
Binary file
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.4
2
+ Name: pith-image
3
+ Version: 0.1.1b1
4
+ Summary: pith image lane SDK: 64-bit image perceptual hash via the pith-image Rust cdylib (ctypes, zero-dep)
5
+ License-Expression: MIT
6
+ Project-URL: Repository, https://github.com/pith-hash/pith-image
7
+ Project-URL: Homepage, https://pith-image.n24q02m.com
8
+ Keywords: phash,image,hashing,perceptual-hash,pith
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Rust
11
+ Classifier: Topic :: Multimedia :: Graphics
12
+ Classifier: Topic :: Security :: Cryptography
13
+ Requires-Python: >=3.9
@@ -0,0 +1,6 @@
1
+ pith_image/__init__.py,sha256=4xE09x3oy4vPRbovEoPJkiSnUlReQGo2GHnJ4jlS-H8,5184
2
+ pith_image/pith_image.dll,sha256=dEHhqJ_BH-9fjcQrYAXKXOohva73Iki0YHHxaUW2nlI,158208
3
+ pith_image-0.1.1b1.dist-info/METADATA,sha256=7ufUcp-akPt5EHMUK8uL7IhDDqcFVpOqzKx_lI9ADXA,574
4
+ pith_image-0.1.1b1.dist-info/WHEEL,sha256=Zx98gwb_dQKckJK3HEOVKnxxD52EfU_PXDG_usMJ2ng,98
5
+ pith_image-0.1.1b1.dist-info/top_level.txt,sha256=KD_tHNh7_TBtQzOVdU3sV0EDLt6qH1yrDNXFzrmD3Is,11
6
+ pith_image-0.1.1b1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64
5
+
@@ -0,0 +1 @@
1
+ pith_image