Skip to content

Commit 5e76568

Browse files
isarandiclaude
andcommitted
Add PNG-to-RLE with libdeflate and CI support
Direct PNG-to-RLE conversion for 8-bit grayscale PNGs using libdeflate, bypassing intermediate numpy arrays. Includes from_png, from_label_map_png, and rlesFromLabelMapPng for single-pass label map extraction from PNG. Updates setup.py with libdeflate linking (pkg-config + MSVC fallback), LIBDEFLATE_DIR env var, and removes standalone png_to_rle_cython extension. CI workflows install libdeflate on all platforms for builds and tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ee556e9 commit 5e76568

9 files changed

Lines changed: 665 additions & 8 deletions

File tree

.github/workflows/python-publish.yml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@ jobs:
2929
CIBW_SKIP: "*-musllinux_* pp*"
3030
CIBW_TEST_SKIP: "cp38-macosx_*:arm64"
3131
CIBW_TEST_COMMAND: python -c "import rlemasklib; print(rlemasklib.__version__)"
32+
CIBW_BEFORE_ALL_LINUX: >
33+
yum install -y cmake gcc gcc-c++ make &&
34+
cd /tmp &&
35+
curl -L https://github.com/ebiggers/libdeflate/archive/refs/tags/v1.22.tar.gz | tar xz &&
36+
cd libdeflate-1.22 &&
37+
cmake -B build -DCMAKE_BUILD_TYPE=Release &&
38+
cmake --build build --parallel &&
39+
cmake --install build
40+
CIBW_BEFORE_ALL_MACOS: brew install libdeflate
41+
CIBW_BEFORE_ALL_WINDOWS: >
42+
cd /d %TEMP% &&
43+
curl -L -o libdeflate.tar.gz https://github.com/ebiggers/libdeflate/archive/refs/tags/v1.22.tar.gz &&
44+
tar xzf libdeflate.tar.gz &&
45+
cd libdeflate-1.22 &&
46+
cmake -B build -DCMAKE_BUILD_TYPE=Release &&
47+
cmake --build build --config Release --parallel &&
48+
cmake --install build --prefix C:/libdeflate
49+
CIBW_ENVIRONMENT_WINDOWS: LIBDEFLATE_DIR=C:/libdeflate
3250

3351
- uses: actions/upload-artifact@v4
3452
with:
@@ -68,4 +86,4 @@ jobs:
6886
merge-multiple: true
6987

7088
- name: Publish to PyPI
71-
uses: pypa/gh-action-pypi-publish@release/v1
89+
uses: pypa/gh-action-pypi-publish@release/v1

.github/workflows/test.yml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,32 @@ jobs:
2626
with:
2727
python-version: ${{ matrix.python-version }}
2828

29+
- name: Install libdeflate (Linux)
30+
if: runner.os == 'Linux'
31+
run: sudo apt-get update && sudo apt-get install -y libdeflate-dev
32+
33+
- name: Install libdeflate (macOS)
34+
if: runner.os == 'macOS'
35+
run: brew install libdeflate
36+
37+
- name: Install libdeflate (Windows)
38+
if: runner.os == 'Windows'
39+
shell: bash
40+
run: |
41+
cd "$TEMP"
42+
curl -L -o libdeflate.tar.gz https://github.com/ebiggers/libdeflate/archive/refs/tags/v1.22.tar.gz
43+
tar xzf libdeflate.tar.gz
44+
cd libdeflate-1.22
45+
cmake -B build -DCMAKE_BUILD_TYPE=Release
46+
cmake --build build --config Release --parallel
47+
cmake --install build --prefix "C:/libdeflate"
48+
echo "LIBDEFLATE_DIR=C:/libdeflate" >> "$GITHUB_ENV"
49+
2950
- name: Install dependencies
3051
run: |
3152
python -m pip install --upgrade pip
3253
pip install "numpy${{ matrix.numpy-version }}"
3354
pip install .[test-headless]
3455
3556
- name: Run tests
36-
run: pytest tests/ -v
57+
run: pytest tests/ -v

setup.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
import subprocess
13
import sys
24
import numpy as np
35
from setuptools import setup, Extension
@@ -21,21 +23,52 @@
2123
"/O2",
2224
"/wd4505",
2325
] # /O2=optimize, /wd4505=disable unused function warning
26+
extra_link_args = []
2427
else:
2528
extra_compile_args = ["-Wno-cpp", "-Wno-unused-function", "-std=c99", "-O3"]
29+
extra_link_args = []
30+
31+
include_dirs = [np.get_include(), "src/rlemasklib/c"]
32+
library_dirs = []
33+
34+
# Support custom libdeflate install location via LIBDEFLATE_DIR env var
35+
libdeflate_dir = os.environ.get("LIBDEFLATE_DIR")
36+
if libdeflate_dir:
37+
include_dirs.append(os.path.join(libdeflate_dir, "include"))
38+
library_dirs.append(os.path.join(libdeflate_dir, "lib"))
39+
40+
# Check for libdeflate (required for PNG-to-RLE)
41+
try:
42+
deflate_cflags = subprocess.check_output(
43+
["pkg-config", "--cflags", "libdeflate"], stderr=subprocess.DEVNULL
44+
).decode().strip().split()
45+
deflate_libs = subprocess.check_output(
46+
["pkg-config", "--libs", "libdeflate"], stderr=subprocess.DEVNULL
47+
).decode().strip().split()
48+
extra_compile_args.extend(deflate_cflags)
49+
extra_link_args.extend(deflate_libs)
50+
except (subprocess.CalledProcessError, FileNotFoundError):
51+
if sys.platform == "win32":
52+
extra_link_args.append("deflate.lib")
53+
else:
54+
extra_link_args.append("-ldeflate")
2655

2756
ext_modules = [
2857
Extension(
2958
"rlemasklib.rlemasklib_cython",
3059
sources=["src/rlemasklib/rlemasklib_cython.pyx"] + c_files,
31-
include_dirs=[np.get_include(), "src/rlemasklib/c"],
60+
include_dirs=include_dirs,
61+
library_dirs=library_dirs,
3262
extra_compile_args=extra_compile_args,
63+
extra_link_args=extra_link_args,
3364
),
3465
Extension(
3566
"rlemasklib.oop_cython",
3667
sources=["src/rlemasklib/oop_cython.pyx"] + c_files,
37-
include_dirs=[np.get_include(), "src/rlemasklib/c"],
68+
include_dirs=include_dirs,
69+
library_dirs=library_dirs,
3870
extra_compile_args=extra_compile_args,
71+
extra_link_args=extra_link_args,
3972
),
4073
]
4174

0 commit comments

Comments
 (0)