imrw 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.
imrw-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,5 @@
1
+ Metadata-Version: 2.4
2
+ Name: imrw
3
+ Version: 0.1.0
4
+ Requires-Dist: numpy
5
+ Requires-Dist: pillow
imrw-0.1.0/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # imrw
2
+ Minimal image I/O library for Python.
3
+
4
+ ## Features
5
+ - Read/Write images via `Pillow` & `numpy`.
6
+ - Clean and simple interface.
7
+ - `imread` always returns an RGB (`H x W x 3`) numpy array.
8
+ - `imwrite` expects a `uint8` array with shape `H x W`, `H x W x 1`, `H x W x 3`, or `H x W x 4`.
9
+
10
+ ## Quick Start
11
+ ```bash
12
+ pip install imrw
13
+ ```
14
+
15
+ ```python
16
+ from imrw import imread, imwrite
17
+
18
+ image = imread("input.png")
19
+ imwrite("output.png", image)
20
+ ```
@@ -0,0 +1,14 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "imrw"
7
+ version = "0.1.0"
8
+ dependencies = [
9
+ "numpy",
10
+ "pillow",
11
+ ]
12
+
13
+ [tool.setuptools.packages.find]
14
+ where = ["src"]
imrw-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ from .ops import imread, imwrite
2
+
3
+ __all__ = ["imread", "imwrite"]
@@ -0,0 +1,33 @@
1
+ import numpy as np
2
+
3
+ from typing import Any
4
+ from pathlib import Path
5
+ from PIL import Image
6
+
7
+
8
+ def imread(path: str | Path) -> np.ndarray:
9
+ with Image.open(path) as img:
10
+ return np.array(img.convert("RGB"))
11
+
12
+
13
+ def imwrite(path: str | Path, img: np.ndarray, **kwargs: Any) -> None:
14
+ if img.dtype != np.uint8:
15
+ raise ValueError(
16
+ f"imwrite expects a uint8 numpy array, got dtype={img.dtype}"
17
+ )
18
+
19
+ if img.ndim not in (2, 3):
20
+ raise ValueError(
21
+ f"imwrite expects a 2D or 3D array, got shape={img.shape}"
22
+ )
23
+
24
+ if img.ndim == 3 and img.shape[2] not in (1, 3, 4):
25
+ raise ValueError(
26
+ "imwrite expects channel count in {1, 3, 4}, "
27
+ f"got shape={img.shape}"
28
+ )
29
+
30
+ if img.ndim == 3 and img.shape[2] == 1:
31
+ img = img[:, :, 0]
32
+
33
+ Image.fromarray(img).save(path, **kwargs)
@@ -0,0 +1,5 @@
1
+ Metadata-Version: 2.4
2
+ Name: imrw
3
+ Version: 0.1.0
4
+ Requires-Dist: numpy
5
+ Requires-Dist: pillow
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/imrw/__init__.py
4
+ src/imrw/ops.py
5
+ src/imrw.egg-info/PKG-INFO
6
+ src/imrw.egg-info/SOURCES.txt
7
+ src/imrw.egg-info/dependency_links.txt
8
+ src/imrw.egg-info/requires.txt
9
+ src/imrw.egg-info/top_level.txt
10
+ tests/test_ops.py
@@ -0,0 +1,2 @@
1
+ numpy
2
+ pillow
@@ -0,0 +1 @@
1
+ imrw
@@ -0,0 +1,65 @@
1
+ import numpy as np
2
+ import pytest
3
+ from pathlib import Path
4
+ from imrw import imread, imwrite
5
+
6
+
7
+ def test_im_ops_roundtrip(tmp_path: Path):
8
+ path = tmp_path / "test.png"
9
+ img = np.zeros((10, 10, 3), dtype=np.uint8)
10
+ img[0, 0] = [255, 0, 0]
11
+
12
+ imwrite(path, img)
13
+ assert path.exists()
14
+
15
+ loaded = imread(path)
16
+ assert np.array_equal(img, loaded)
17
+
18
+
19
+ def test_imwrite_rejects_non_uint8(tmp_path: Path):
20
+ path = tmp_path / "bad_dtype.png"
21
+ img = np.zeros((10, 10, 3), dtype=np.float32)
22
+
23
+ with pytest.raises(ValueError, match="uint8"):
24
+ imwrite(path, img)
25
+
26
+
27
+ def test_imwrite_rejects_invalid_ndim(tmp_path: Path):
28
+ path = tmp_path / "bad_ndim.png"
29
+ img = np.zeros((4, 4, 3, 1), dtype=np.uint8)
30
+
31
+ with pytest.raises(ValueError, match="2D or 3D"):
32
+ imwrite(path, img)
33
+
34
+
35
+ def test_imwrite_rejects_invalid_channel_count(tmp_path: Path):
36
+ path = tmp_path / "bad_channels.png"
37
+ img = np.zeros((10, 10, 2), dtype=np.uint8)
38
+
39
+ with pytest.raises(ValueError, match="channel count"):
40
+ imwrite(path, img)
41
+
42
+
43
+ def test_imwrite_grayscale_2d(tmp_path: Path):
44
+ path = tmp_path / "gray.png"
45
+ img = np.full((10, 10), 128, dtype=np.uint8)
46
+
47
+ imwrite(path, img)
48
+ assert path.exists()
49
+
50
+
51
+ def test_imwrite_grayscale_3d(tmp_path: Path):
52
+ path = tmp_path / "gray3d.png"
53
+ img = np.full((10, 10, 1), 128, dtype=np.uint8)
54
+
55
+ imwrite(path, img)
56
+ assert path.exists()
57
+
58
+
59
+ def test_imwrite_rgba(tmp_path: Path):
60
+ path = tmp_path / "rgba.png"
61
+ img = np.zeros((10, 10, 4), dtype=np.uint8)
62
+ img[..., 3] = 255
63
+
64
+ imwrite(path, img)
65
+ assert path.exists()