Skip to content

Commit 329cea3

Browse files
committed
Read pixels with get_flattened_data before Pillow 14 removes getdata
getdata() is deprecated since Pillow 12.1.0 and goes away in Pillow 14. The pinned 12.3.0 already ships the replacement, which returns the same pixels, and these three calls were every warning in the headless suite.
1 parent 1d49b91 commit 329cea3

4 files changed

Lines changed: 12 additions & 4 deletions

File tree

‎docs/updates/2026-09.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,10 @@ Index and query commands: [README.md](README.md). New entries go at the end.
153153
- **Result / numbers**: 24 → 0 unjustified handlers; 3 tests. No handler behavior changed, so no CHANGELOG entry.
154154
- **Files**: 11 modules under `je_auto_control/` (`utils/chaos`, `utils/failure_bundle`, `utils/hotkey/backends/linux_backend.py`, `utils/outbox`, `utils/remote_desktop/{file_transfer,host_client,viewer}.py`, `utils/saga`, `utils/usbip/libusb_backend.py`, `wrapper/auto_control_{keyboard,mouse}.py`), `test/unit_test/headless/test_broad_except_reasons.py` (new), `CLAUDE.md`.
155155
- **Open items**: none.
156+
157+
## U-20260923-04 · 2026-09-23 · Pillow getdata → get_flattened_data (removed in Pillow 14) · #migration #deps
158+
159+
- **What**: `Image.getdata()` is deprecated since Pillow 12.1.0 and removed in Pillow 14 (2027-10-15); `get_flattened_data()`, added in the same release, returns the same pixels as a tuple ([12.1.0 notes](https://pillow.readthedocs.io/en/stable/releasenotes/12.1.0.html), [deprecations](https://pillow.readthedocs.io/en/stable/deprecations.html)). The three calls — `utils/color_stats/color_stats.py` and both hashes in `utils/image_dedup/perceptual_hash.py` — now use it; the package pins `pillow==12.3.0`, so no fallback is needed. Checked on 12.3.0 that both return identical sequences for RGB and L images.
160+
- **Result / numbers**: these three calls were the source of all 13 warnings in the last full headless run (8,166 passed). `-k "color_stats or perceptual or dedup or hash or facade_import" -W error::DeprecationWarning`: 76 passed, 3 skipped. Also found the local `.venv` on Pillow 12.2.0 (the version with the 13 CVEs) despite the pin, and reinstalled 12.3.0.
161+
- **Files**: `je_auto_control/utils/color_stats/color_stats.py`, `je_auto_control/utils/image_dedup/perceptual_hash.py`.
162+
- **Open items**: none.

‎docs/updates/README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ In the same commit: delete the item from `Progress.md`, add a `#done` entry here
5858

5959
| ID | Date | Title | Tags | Batch |
6060
|---|---|---|---|---|
61+
| U-20260923-04 | 2026-09-23 | Pillow getdata → get_flattened_data (removed in Pillow 14) | #migration #deps | [2026-09](2026-09.md) |
6162
| U-20260923-03 | 2026-09-23 | Every swallowing broad except says why; AST gate in CI | #done #quality | [2026-09](2026-09.md) |
6263
| U-20260923-02 | 2026-09-23 | USB watcher: a stopped (not superseded) run still primes | #incident #usb #ci | [2026-09](2026-09.md) |
6364
| U-20260923-01 | 2026-09-23 | Log file out of the cwd: home default, JE_AUTOCONTROL_LOG_FILE | #done #logging | [2026-09](2026-09.md) |
@@ -108,7 +109,7 @@ In the same commit: delete the item from `Progress.md`, add a `#done` entry here
108109

109110
| File | Period | Entries |
110111
|---|---|---:|
111-
| [2026-09.md](2026-09.md) | 2026-09 | 19 |
112+
| [2026-09.md](2026-09.md) | 2026-09 | 20 |
112113
| [2026-08-f.md](2026-08-f.md) | 2026-08 | 1 |
113114
| [2026-08-e.md](2026-08-e.md) | 2026-08 | 2 |
114115
| [2026-08-d.md](2026-08-d.md) | 2026-08 | 2 |

‎je_auto_control/utils/color_stats/color_stats.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def region_color_stats(source: ImageSource,
8181
left, top, right, bottom = (int(v) for v in region)
8282
image = image.crop((left, top, right, bottom))
8383
image.thumbnail((128, 128))
84-
pixels: List[RGB] = list(image.getdata())
84+
pixels: List[RGB] = list(image.get_flattened_data())
8585
count = len(pixels)
8686
if count == 0:
8787
return ColorStats((0, 0, 0), (0, 0, 0), 0.0, 0)

‎je_auto_control/utils/image_dedup/perceptual_hash.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ def _bits_to_hex(bits: str) -> str:
2626

2727
def average_hash(image: Any, hash_size: int = 8) -> str:
2828
"""Average-hash an image to a hex fingerprint (brightness vs. the mean)."""
29-
pixels = list(_gray_resized(image, (hash_size, hash_size)).getdata())
29+
pixels = list(_gray_resized(image, (hash_size, hash_size)).get_flattened_data())
3030
average = sum(pixels) / len(pixels)
3131
return _bits_to_hex("".join("1" if p > average else "0" for p in pixels))
3232

3333

3434
def dhash(image: Any, hash_size: int = 8) -> str:
3535
"""Difference-hash an image (each pixel brighter than its right neighbour)."""
3636
width = hash_size + 1
37-
pixels = list(_gray_resized(image, (width, hash_size)).getdata())
37+
pixels = list(_gray_resized(image, (width, hash_size)).get_flattened_data())
3838
bits = [
3939
"1" if pixels[row * width + col] > pixels[row * width + col + 1]
4040
else "0"

0 commit comments

Comments
 (0)