colopresso 12.2.0__cp310-abi3-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.
- colopresso/__init__.py +56 -0
- colopresso/_colopresso.pyd +0 -0
- colopresso/_colopresso_ext.c +612 -0
- colopresso/core.py +266 -0
- colopresso/py.typed +65 -0
- colopresso-12.2.0.dist-info/METADATA +669 -0
- colopresso-12.2.0.dist-info/RECORD +8 -0
- colopresso-12.2.0.dist-info/WHEEL +5 -0
colopresso/core.py
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
#
|
|
3
|
+
# This file is part of colopresso
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2025-2026 COLOPL, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Author: Go Kudo <g-kudo@colopl.co.jp>
|
|
8
|
+
# Developed with AI (LLM) code assistance. See `NOTICE` for details.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Core Python bindings for colopresso (stable ABI wrapper)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass, field, asdict
|
|
17
|
+
from enum import IntEnum
|
|
18
|
+
from typing import List, Optional, Tuple
|
|
19
|
+
|
|
20
|
+
from . import _colopresso
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PngxLossyType(IntEnum):
|
|
24
|
+
"""PNGX lossy compression type"""
|
|
25
|
+
PALETTE256 = _colopresso.PNGX_LOSSY_TYPE_PALETTE256
|
|
26
|
+
LIMITED_RGBA4444 = _colopresso.PNGX_LOSSY_TYPE_LIMITED_RGBA4444
|
|
27
|
+
REDUCED_RGBA32 = _colopresso.PNGX_LOSSY_TYPE_REDUCED_RGBA32
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ColopressoError(Exception):
|
|
31
|
+
"""Exception raised for colopresso errors"""
|
|
32
|
+
|
|
33
|
+
ERROR_CODES = {
|
|
34
|
+
0: "OK",
|
|
35
|
+
1: "File not found",
|
|
36
|
+
2: "Invalid PNG",
|
|
37
|
+
3: "Invalid format",
|
|
38
|
+
4: "Out of memory",
|
|
39
|
+
5: "Encode failed",
|
|
40
|
+
6: "Decode failed",
|
|
41
|
+
7: "IO error",
|
|
42
|
+
8: "Invalid parameter",
|
|
43
|
+
9: "Output not smaller",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
def __init__(self, code: int, message: Optional[str] = None):
|
|
47
|
+
self.code = code
|
|
48
|
+
self.message = message or self.ERROR_CODES.get(code, f"Unknown error ({code})")
|
|
49
|
+
super().__init__(self.message)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class Config:
|
|
54
|
+
"""Configuration for colopresso encoders"""
|
|
55
|
+
|
|
56
|
+
# WebP
|
|
57
|
+
webp_quality: float = 80.0
|
|
58
|
+
webp_lossless: bool = False
|
|
59
|
+
webp_method: int = 6
|
|
60
|
+
webp_target_size: int = 0
|
|
61
|
+
webp_target_psnr: float = 0.0
|
|
62
|
+
webp_segments: int = 4
|
|
63
|
+
webp_sns_strength: int = 50
|
|
64
|
+
webp_filter_strength: int = 60
|
|
65
|
+
webp_filter_sharpness: int = 0
|
|
66
|
+
webp_filter_type: int = 1
|
|
67
|
+
webp_autofilter: bool = True
|
|
68
|
+
webp_alpha_compression: bool = True
|
|
69
|
+
webp_alpha_filtering: int = 1
|
|
70
|
+
webp_alpha_quality: int = 100
|
|
71
|
+
webp_pass: int = 1
|
|
72
|
+
webp_preprocessing: int = 0
|
|
73
|
+
webp_partitions: int = 0
|
|
74
|
+
webp_partition_limit: int = 0
|
|
75
|
+
webp_emulate_jpeg_size: bool = False
|
|
76
|
+
webp_thread_level: int = 0
|
|
77
|
+
webp_low_memory: bool = False
|
|
78
|
+
webp_near_lossless: int = 100
|
|
79
|
+
webp_exact: bool = False
|
|
80
|
+
webp_use_delta_palette: bool = False
|
|
81
|
+
webp_use_sharp_yuv: bool = False
|
|
82
|
+
|
|
83
|
+
# AVIF
|
|
84
|
+
avif_quality: float = 50.0
|
|
85
|
+
avif_alpha_quality: int = 100
|
|
86
|
+
avif_lossless: bool = False
|
|
87
|
+
avif_speed: int = 6
|
|
88
|
+
avif_threads: int = 1
|
|
89
|
+
|
|
90
|
+
# PNGX (PNG)
|
|
91
|
+
pngx_level: int = 5
|
|
92
|
+
pngx_strip_safe: bool = True
|
|
93
|
+
pngx_optimize_alpha: bool = True
|
|
94
|
+
pngx_lossy_enable: bool = True
|
|
95
|
+
pngx_lossy_type: int = 0 # PngxLossyType.PALETTE256
|
|
96
|
+
pngx_lossy_max_colors: int = 256
|
|
97
|
+
pngx_lossy_reduced_colors: int = -1
|
|
98
|
+
pngx_lossy_reduced_bits_rgb: int = 4
|
|
99
|
+
pngx_lossy_reduced_alpha_bits: int = 4
|
|
100
|
+
pngx_lossy_quality_min: int = 80
|
|
101
|
+
pngx_lossy_quality_max: int = 95
|
|
102
|
+
pngx_lossy_speed: int = 3
|
|
103
|
+
pngx_lossy_dither_level: float = 0.6
|
|
104
|
+
pngx_saliency_map_enable: bool = True
|
|
105
|
+
pngx_chroma_anchor_enable: bool = True
|
|
106
|
+
pngx_adaptive_dither_enable: bool = True
|
|
107
|
+
pngx_gradient_boost_enable: bool = True
|
|
108
|
+
pngx_chroma_weight_enable: bool = True
|
|
109
|
+
pngx_postprocess_smooth_enable: bool = True
|
|
110
|
+
pngx_postprocess_smooth_importance_cutoff: float = 0.6
|
|
111
|
+
pngx_palette256_gradient_profile_enable: bool = True
|
|
112
|
+
pngx_palette256_gradient_dither_floor: float = 0.78
|
|
113
|
+
pngx_palette256_alpha_bleed_enable: bool = False
|
|
114
|
+
pngx_palette256_alpha_bleed_max_distance: int = 64
|
|
115
|
+
pngx_palette256_alpha_bleed_opaque_threshold: int = 248
|
|
116
|
+
pngx_palette256_alpha_bleed_soft_limit: int = 160
|
|
117
|
+
pngx_palette256_profile_opaque_ratio_threshold: float = 0.90
|
|
118
|
+
pngx_palette256_profile_gradient_mean_max: float = 0.16
|
|
119
|
+
pngx_palette256_profile_saturation_mean_max: float = 0.42
|
|
120
|
+
pngx_palette256_tune_opaque_ratio_threshold: float = 0.90
|
|
121
|
+
pngx_palette256_tune_gradient_mean_max: float = 0.14
|
|
122
|
+
pngx_palette256_tune_saturation_mean_max: float = 0.35
|
|
123
|
+
pngx_palette256_tune_speed_max: int = 1
|
|
124
|
+
pngx_palette256_tune_quality_min_floor: int = 90
|
|
125
|
+
pngx_palette256_tune_quality_max_target: int = 100
|
|
126
|
+
pngx_threads: int = 1
|
|
127
|
+
pngx_protected_colors: Optional[List[Tuple[int, int, int, int]]] = None
|
|
128
|
+
|
|
129
|
+
def _to_dict(self) -> dict:
|
|
130
|
+
"""Convert to dictionary for C extension"""
|
|
131
|
+
d = asdict(self)
|
|
132
|
+
if isinstance(d.get("pngx_lossy_type"), PngxLossyType):
|
|
133
|
+
d["pngx_lossy_type"] = int(d["pngx_lossy_type"])
|
|
134
|
+
return d
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _wrap_error(func):
|
|
138
|
+
"""Wrap C extension errors into ColopressoError"""
|
|
139
|
+
def wrapper(*args, **kwargs):
|
|
140
|
+
try:
|
|
141
|
+
return func(*args, **kwargs)
|
|
142
|
+
except _colopresso.ColopressoError as e:
|
|
143
|
+
code = e.args[0] if e.args else -1
|
|
144
|
+
message = e.args[1] if len(e.args) > 1 else None
|
|
145
|
+
raise ColopressoError(code, message) from None
|
|
146
|
+
return wrapper
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@_wrap_error
|
|
150
|
+
def encode_webp(png_data: bytes, config: Optional[Config] = None) -> bytes:
|
|
151
|
+
"""
|
|
152
|
+
Encode PNG data to WebP format.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
png_data: Raw PNG file data
|
|
156
|
+
config: Optional configuration (uses defaults if not provided)
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
WebP encoded data
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
ColopressoError: If encoding fails
|
|
163
|
+
"""
|
|
164
|
+
config_dict = config._to_dict() if config else None
|
|
165
|
+
return _colopresso.encode_webp(png_data, config_dict)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@_wrap_error
|
|
169
|
+
def encode_avif(png_data: bytes, config: Optional[Config] = None) -> bytes:
|
|
170
|
+
"""
|
|
171
|
+
Encode PNG data to AVIF format.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
png_data: Raw PNG file data
|
|
175
|
+
config: Optional configuration (uses defaults if not provided)
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
AVIF encoded data
|
|
179
|
+
|
|
180
|
+
Raises:
|
|
181
|
+
ColopressoError: If encoding fails
|
|
182
|
+
"""
|
|
183
|
+
config_dict = config._to_dict() if config else None
|
|
184
|
+
return _colopresso.encode_avif(png_data, config_dict)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@_wrap_error
|
|
188
|
+
def encode_pngx(png_data: bytes, config: Optional[Config] = None) -> bytes:
|
|
189
|
+
"""
|
|
190
|
+
Optimize PNG data using PNGX encoder.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
png_data: Raw PNG file data
|
|
194
|
+
config: Optional configuration (uses defaults if not provided)
|
|
195
|
+
For PALETTE256 mode, you can specify protected colors using
|
|
196
|
+
config.pngx_protected_colors as a list of (r, g, b, a) tuples.
|
|
197
|
+
These colors will always be included in the palette.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Optimized PNG data
|
|
201
|
+
|
|
202
|
+
Raises:
|
|
203
|
+
ColopressoError: If encoding fails
|
|
204
|
+
"""
|
|
205
|
+
config_dict = config._to_dict() if config else None
|
|
206
|
+
return _colopresso.encode_pngx(png_data, config_dict)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def get_version() -> int:
|
|
210
|
+
"""Get colopresso version number"""
|
|
211
|
+
return _colopresso.get_version()
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def get_libwebp_version() -> int:
|
|
215
|
+
"""Get libwebp version number"""
|
|
216
|
+
return _colopresso.get_libwebp_version()
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def get_libpng_version() -> int:
|
|
220
|
+
"""Get libpng version number"""
|
|
221
|
+
return _colopresso.get_libpng_version()
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def get_libavif_version() -> int:
|
|
225
|
+
"""Get libavif version number"""
|
|
226
|
+
return _colopresso.get_libavif_version()
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def get_pngx_oxipng_version() -> int:
|
|
230
|
+
"""Get oxipng version number"""
|
|
231
|
+
return _colopresso.get_pngx_oxipng_version()
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def get_pngx_libimagequant_version() -> int:
|
|
235
|
+
"""Get libimagequant version number"""
|
|
236
|
+
return _colopresso.get_pngx_libimagequant_version()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def get_buildtime() -> int:
|
|
240
|
+
"""Get build timestamp"""
|
|
241
|
+
return _colopresso.get_buildtime()
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def get_compiler_version_string() -> str:
|
|
245
|
+
"""Get compiler version string"""
|
|
246
|
+
return _colopresso.get_compiler_version_string()
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def get_rust_version_string() -> str:
|
|
250
|
+
"""Get Rust version string"""
|
|
251
|
+
return _colopresso.get_rust_version_string()
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def is_threads_enabled() -> bool:
|
|
255
|
+
"""Check if threading is enabled"""
|
|
256
|
+
return _colopresso.is_threads_enabled()
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def get_default_thread_count() -> int:
|
|
260
|
+
"""Get default thread count"""
|
|
261
|
+
return _colopresso.get_default_thread_count()
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def get_max_thread_count() -> int:
|
|
265
|
+
"""Get maximum thread count"""
|
|
266
|
+
return _colopresso.get_max_thread_count()
|
colopresso/py.typed
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
#
|
|
3
|
+
# This file is part of colopresso
|
|
4
|
+
#
|
|
5
|
+
# Copyright (C) 2025-2026 COLOPL, Inc.
|
|
6
|
+
#
|
|
7
|
+
# Author: Go Kudo <g-kudo@colopl.co.jp>
|
|
8
|
+
# Developed with AI (LLM) code assistance. See `NOTICE` for details.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Type stubs for colopresso
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from dataclasses import dataclass
|
|
15
|
+
from enum import IntEnum
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
class PngxLossyType(IntEnum):
|
|
19
|
+
PALETTE256: int
|
|
20
|
+
LIMITED_RGBA4444: int
|
|
21
|
+
REDUCED_RGBA32: int
|
|
22
|
+
|
|
23
|
+
class ColopressoError(Exception):
|
|
24
|
+
code: int
|
|
25
|
+
message: str
|
|
26
|
+
def __init__(self, code: int, message: Optional[str] = None) -> None: ...
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class Config:
|
|
30
|
+
webp_quality: float
|
|
31
|
+
webp_lossless: bool
|
|
32
|
+
webp_method: int
|
|
33
|
+
avif_quality: float
|
|
34
|
+
avif_alpha_quality: int
|
|
35
|
+
avif_lossless: bool
|
|
36
|
+
avif_speed: int
|
|
37
|
+
avif_threads: int
|
|
38
|
+
pngx_level: int
|
|
39
|
+
pngx_strip_safe: bool
|
|
40
|
+
pngx_optimize_alpha: bool
|
|
41
|
+
pngx_lossy_enable: bool
|
|
42
|
+
pngx_lossy_type: PngxLossyType
|
|
43
|
+
pngx_lossy_max_colors: int
|
|
44
|
+
pngx_lossy_quality_min: int
|
|
45
|
+
pngx_lossy_quality_max: int
|
|
46
|
+
pngx_lossy_speed: int
|
|
47
|
+
pngx_lossy_dither_level: float
|
|
48
|
+
pngx_threads: int
|
|
49
|
+
|
|
50
|
+
def encode_webp(png_data: bytes, config: Optional[Config] = None) -> bytes: ...
|
|
51
|
+
def encode_avif(png_data: bytes, config: Optional[Config] = None) -> bytes: ...
|
|
52
|
+
def encode_pngx(png_data: bytes, config: Optional[Config] = None) -> bytes: ...
|
|
53
|
+
|
|
54
|
+
def get_version() -> int: ...
|
|
55
|
+
def get_libwebp_version() -> int: ...
|
|
56
|
+
def get_libpng_version() -> int: ...
|
|
57
|
+
def get_libavif_version() -> int: ...
|
|
58
|
+
def get_pngx_oxipng_version() -> int: ...
|
|
59
|
+
def get_pngx_libimagequant_version() -> int: ...
|
|
60
|
+
def get_buildtime() -> int: ...
|
|
61
|
+
def get_compiler_version_string() -> str: ...
|
|
62
|
+
def get_rust_version_string() -> str: ...
|
|
63
|
+
def is_threads_enabled() -> bool: ...
|
|
64
|
+
def get_default_thread_count() -> int: ...
|
|
65
|
+
def get_max_thread_count() -> int: ...
|