picx-image-optimizer 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.
- picx_image_optimizer-0.1.0/.github/workflows/ci.yml +29 -0
- picx_image_optimizer-0.1.0/.github/workflows/release.yml +53 -0
- picx_image_optimizer-0.1.0/.gitignore +5 -0
- picx_image_optimizer-0.1.0/CHANGELOG.md +8 -0
- picx_image_optimizer-0.1.0/LICENSE +21 -0
- picx_image_optimizer-0.1.0/PKG-INFO +189 -0
- picx_image_optimizer-0.1.0/README-CN.md +167 -0
- picx_image_optimizer-0.1.0/README.md +155 -0
- picx_image_optimizer-0.1.0/examples/basic_usage.py +20 -0
- picx_image_optimizer-0.1.0/pyproject.toml +69 -0
- picx_image_optimizer-0.1.0/src/picx/__init__.py +8 -0
- picx_image_optimizer-0.1.0/src/picx/__main__.py +4 -0
- picx_image_optimizer-0.1.0/src/picx/api.py +177 -0
- picx_image_optimizer-0.1.0/src/picx/backends/__init__.py +6 -0
- picx_image_optimizer-0.1.0/src/picx/backends/base.py +11 -0
- picx_image_optimizer-0.1.0/src/picx/backends/pillow.py +177 -0
- picx_image_optimizer-0.1.0/src/picx/backends/pyvips.py +110 -0
- picx_image_optimizer-0.1.0/src/picx/backends/resolver.py +73 -0
- picx_image_optimizer-0.1.0/src/picx/cli.py +187 -0
- picx_image_optimizer-0.1.0/src/picx/doctor.py +112 -0
- picx_image_optimizer-0.1.0/src/picx/errors.py +31 -0
- picx_image_optimizer-0.1.0/src/picx/formats.py +45 -0
- picx_image_optimizer-0.1.0/src/picx/help.py +31 -0
- picx_image_optimizer-0.1.0/src/picx/models.py +37 -0
- picx_image_optimizer-0.1.0/src/picx/presets.py +35 -0
- picx_image_optimizer-0.1.0/src/picx/report.py +62 -0
- picx_image_optimizer-0.1.0/src/picx/tile.py +310 -0
- picx_image_optimizer-0.1.0/tests/test_api.py +180 -0
- picx_image_optimizer-0.1.0/tests/test_cli.py +146 -0
- picx_image_optimizer-0.1.0/tests/test_help_doctor.py +80 -0
- picx_image_optimizer-0.1.0/tests/test_pyvips_backend.py +13 -0
- picx_image_optimizer-0.1.0/tests/test_report.py +28 -0
- picx_image_optimizer-0.1.0/tests/test_tile.py +94 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: ${{ matrix.python-version }}
|
|
18
|
+
- name: Install
|
|
19
|
+
run: python -m pip install -e ".[dev]"
|
|
20
|
+
- name: Tests
|
|
21
|
+
run: python -m pytest
|
|
22
|
+
- name: Compile
|
|
23
|
+
run: python -m compileall -q src tests examples
|
|
24
|
+
- name: Ruff
|
|
25
|
+
run: python -m ruff check .
|
|
26
|
+
- name: Black
|
|
27
|
+
run: python -m black --check .
|
|
28
|
+
- name: Mypy
|
|
29
|
+
run: python -m mypy src tests examples
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: Build distribution
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
persist-credentials: false
|
|
16
|
+
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.x"
|
|
20
|
+
|
|
21
|
+
- name: Install build tooling
|
|
22
|
+
run: python -m pip install build twine
|
|
23
|
+
|
|
24
|
+
- name: Build source and wheel distributions
|
|
25
|
+
run: python -m build
|
|
26
|
+
|
|
27
|
+
- name: Check distributions
|
|
28
|
+
run: python -m twine check dist/*
|
|
29
|
+
|
|
30
|
+
- name: Upload distributions
|
|
31
|
+
uses: actions/upload-artifact@v4
|
|
32
|
+
with:
|
|
33
|
+
name: python-package-distributions
|
|
34
|
+
path: dist/
|
|
35
|
+
|
|
36
|
+
publish:
|
|
37
|
+
name: Publish to PyPI
|
|
38
|
+
needs: build
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
environment:
|
|
41
|
+
name: pypi
|
|
42
|
+
url: https://pypi.org/project/picx-image-optimizer/
|
|
43
|
+
permissions:
|
|
44
|
+
id-token: write
|
|
45
|
+
steps:
|
|
46
|
+
- name: Download distributions
|
|
47
|
+
uses: actions/download-artifact@v4
|
|
48
|
+
with:
|
|
49
|
+
name: python-package-distributions
|
|
50
|
+
path: dist/
|
|
51
|
+
|
|
52
|
+
- name: Publish to PyPI
|
|
53
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ingeniousfrog
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: picx-image-optimizer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A tiny Python image optimization toolkit for batch compression and web assets.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ingeniousfrog/picx
|
|
6
|
+
Project-URL: Issues, https://github.com/ingeniousfrog/picx/issues
|
|
7
|
+
Project-URL: Repository, https://github.com/ingeniousfrog/picx
|
|
8
|
+
Author: ingeniousfrog
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: compression,image,optimization,tiff,tiles,webp
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: pillow>=10.0
|
|
24
|
+
Requires-Dist: pyvips>=2.2
|
|
25
|
+
Requires-Dist: rich>=13.0
|
|
26
|
+
Requires-Dist: typer>=0.9
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: black>=24.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: mypy<2,>=1.8; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# picx
|
|
36
|
+
|
|
37
|
+
picx is a small Python image optimization package for web assets, blogs, avatars,
|
|
38
|
+
and batch cleanup jobs. The package installs a CLI named `picx` and exposes a
|
|
39
|
+
compact Python API under `picx`.
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
- Compress single images or entire directories.
|
|
44
|
+
- Convert between `jpg`, `png`, `webp`, `avif`, and `tiff` outputs.
|
|
45
|
+
- Read `jpg`, `jpeg`, `png`, `webp`, `avif`, `tif`, and `tiff` inputs.
|
|
46
|
+
- Resize with `max_width` and `max_height`.
|
|
47
|
+
- Strip image metadata by default.
|
|
48
|
+
- Search for the highest quality under a target byte size.
|
|
49
|
+
- Render CLI compression reports with Rich.
|
|
50
|
+
- Use `web`, `blog`, `avatar`, and `lossless` presets.
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install -e ".[dev]"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`pip install picx-image-optimizer` installs the pyvips Python backend package. pyvips also
|
|
59
|
+
needs the native libvips system library for large-image processing. pip cannot
|
|
60
|
+
install this native system library for every platform, so install it once with
|
|
61
|
+
your OS or environment package manager:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
brew install vips
|
|
65
|
+
# or
|
|
66
|
+
conda install -c conda-forge libvips pyvips
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Install libvips in the same environment that runs `picx`. For example, if you
|
|
70
|
+
run `picx` inside `conda activate comfyui`, install libvips inside that conda
|
|
71
|
+
environment. Mixing Homebrew libvips with Anaconda/conda libraries can still
|
|
72
|
+
fail on macOS with dynamic-library or code-signature errors.
|
|
73
|
+
|
|
74
|
+
## CLI
|
|
75
|
+
|
|
76
|
+
Optimize one image:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
picx image ./photo.png --output ./dist/photo.webp --format webp --quality 82
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Optimize a directory recursively while preserving relative paths:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
picx dir ./images ./out --format webp --preset web
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Try a target size in bytes:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
picx image ./hero.jpg --output ./out/hero.webp --format webp --target-size 120000
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Handle trusted large images with Pillow:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
picx image ./texture.tif --output ./texture.webp --format webp --allow-large --max-pixels 400000000
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Use the pyvips backend for large images:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
picx image ./texture.tif --output ./texture.webp --format webp --backend pyvips
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
WebP has a per-side dimension limit of 16383 pixels. If either width or height
|
|
107
|
+
is larger, resize first or use tiling:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
picx image ./texture.tif --output ./texture.webp --format webp --backend pyvips --max-height 16000
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Create tiles and a manifest for very large images:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
picx tile ./texture.tif ./tiles --tile-size 1024 --format webp
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Python API
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from picx import optimize_dir, optimize_image, tile_image
|
|
123
|
+
|
|
124
|
+
single = optimize_image(
|
|
125
|
+
"photo.png",
|
|
126
|
+
output="dist/photo.webp",
|
|
127
|
+
format="webp",
|
|
128
|
+
quality=82,
|
|
129
|
+
max_width=1600,
|
|
130
|
+
strip_meta=True,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
batch = optimize_dir(
|
|
134
|
+
"images",
|
|
135
|
+
"out",
|
|
136
|
+
format="webp",
|
|
137
|
+
preset="blog",
|
|
138
|
+
recursive=True,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
tiles = tile_image("texture.tif", "tiles", tile_size=1024, format="webp")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`optimize_image()` and `optimize_dir()` return `OptimizeResult` objects with:
|
|
145
|
+
|
|
146
|
+
- `original_size`
|
|
147
|
+
- `output_size`
|
|
148
|
+
- `savings_ratio`
|
|
149
|
+
- `skipped`
|
|
150
|
+
- `error`
|
|
151
|
+
- `source_path`
|
|
152
|
+
- `output_path`
|
|
153
|
+
|
|
154
|
+
## Presets
|
|
155
|
+
|
|
156
|
+
| Preset | Output | Purpose |
|
|
157
|
+
| --- | --- | --- |
|
|
158
|
+
| `web` | webp, quality 82, max width 1920 | General website images |
|
|
159
|
+
| `blog` | webp, quality 78, max width 1600 | Blog and article images |
|
|
160
|
+
| `avatar` | webp, quality 85, max 256 x 256 | Profile images |
|
|
161
|
+
| `lossless` | png, quality 100 | Lossless-ish cleanup with metadata stripping |
|
|
162
|
+
|
|
163
|
+
## Development
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python3 -m pytest
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
picx uses Pillow by default and includes the pyvips Python backend package.
|
|
170
|
+
The pyvips backend also requires the native libvips system library, which pip
|
|
171
|
+
does not install automatically. Install libvips in the same environment that
|
|
172
|
+
runs `picx`.
|
|
173
|
+
|
|
174
|
+
## Large Images
|
|
175
|
+
|
|
176
|
+
By default, picx keeps Pillow's large-image safety posture. If an image exceeds
|
|
177
|
+
the configured pixel limit, picx reports a clear error with next steps instead
|
|
178
|
+
of showing a raw traceback. For trusted images, use `--allow-large` and optionally
|
|
179
|
+
set `--max-pixels`. For memory-efficient processing, install system libvips and
|
|
180
|
+
select `--backend pyvips` or keep the default `--backend auto`.
|
|
181
|
+
|
|
182
|
+
For single-file WebP output, keep both width and height at or below 16383 pixels.
|
|
183
|
+
Images larger than that should be resized with `--max-width` / `--max-height`, or
|
|
184
|
+
exported with `picx tile` instead.
|
|
185
|
+
|
|
186
|
+
`picx tile` writes image tiles plus `manifest.json`. The manifest is an index,
|
|
187
|
+
not a merged image: it records the original size, tile size, output format,
|
|
188
|
+
levels, and every tile's path and coordinates so another tool can display or
|
|
189
|
+
reconstruct the tile layout reliably.
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# picx
|
|
2
|
+
|
|
3
|
+
picx 是一个轻量的 Python 图片优化工具包,适合处理网页图片、博客配图、头像和批量压缩任务。它同时提供命令行工具 `picx` 和 Python API。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- 压缩单张图片或整个目录。
|
|
8
|
+
- 支持输出 `jpg`、`png`、`webp`、`avif`、`tiff`。
|
|
9
|
+
- 支持读取 `jpg`、`jpeg`、`png`、`webp`、`avif`、`tif`、`tiff`。
|
|
10
|
+
- 支持按 `max_width` / `max_height` 缩放。
|
|
11
|
+
- 默认清理图片元数据。
|
|
12
|
+
- 支持按目标体积搜索尽可能高的输出质量。
|
|
13
|
+
- 使用 Rich 输出压缩报告。
|
|
14
|
+
- 内置 `web`、`blog`、`avatar`、`lossless` 四个 preset。
|
|
15
|
+
- 支持 pyvips 后端和切片输出,用于处理超大图。
|
|
16
|
+
|
|
17
|
+
## 安装
|
|
18
|
+
|
|
19
|
+
开发安装:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install -e ".[dev]"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
正式使用时:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install picx-image-optimizer
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`pip install picx-image-optimizer` 会安装 pyvips 的 Python 包,但 pyvips 还需要系统原生库 libvips。pip 无法在所有平台上可靠安装这个系统库,所以需要用系统或环境包管理器额外安装一次:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
brew install vips
|
|
35
|
+
# 或
|
|
36
|
+
conda install -c conda-forge libvips pyvips
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
注意:libvips 要安装在运行 `picx` 的同一个环境里。比如你在 `conda activate comfyui` 后运行 `picx`,就要在这个 conda 环境里安装 libvips。macOS 上混用 Homebrew 的 libvips 和 Anaconda/conda 的动态库,仍然可能遇到动态库加载或代码签名错误。
|
|
40
|
+
|
|
41
|
+
## CLI 用法
|
|
42
|
+
|
|
43
|
+
压缩单张图片:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
picx image ./photo.png --output ./dist/photo.webp --format webp --quality 82
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
递归压缩目录,并保持相对目录结构:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
picx dir ./images ./out --format webp --preset web
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
按目标体积压缩:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
picx image ./hero.jpg --output ./out/hero.webp --format webp --target-size 120000
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
用 Pillow 处理可信的大图:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
picx image ./texture.tif --output ./texture.webp --format webp --allow-large --max-pixels 400000000
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
用 pyvips 后端处理大图:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
picx image ./texture.tif --output ./texture.webp --format webp --backend pyvips
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
WebP 单边尺寸上限通常是 16383 像素。如果宽或高超过这个限制,需要先缩放,或者改用切片:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
picx image ./texture.tif --output ./texture.webp --format webp --backend pyvips --max-height 16000
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
为超大图生成切片和 manifest:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
picx tile ./texture.tif ./tiles --tile-size 1024 --format webp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Python API
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from picx import optimize_dir, optimize_image, tile_image
|
|
89
|
+
|
|
90
|
+
single = optimize_image(
|
|
91
|
+
"photo.png",
|
|
92
|
+
output="dist/photo.webp",
|
|
93
|
+
format="webp",
|
|
94
|
+
quality=82,
|
|
95
|
+
max_width=1600,
|
|
96
|
+
strip_meta=True,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
batch = optimize_dir(
|
|
100
|
+
"images",
|
|
101
|
+
"out",
|
|
102
|
+
format="webp",
|
|
103
|
+
preset="blog",
|
|
104
|
+
recursive=True,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
tiles = tile_image("texture.tif", "tiles", tile_size=1024, format="webp")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`optimize_image()` 和 `optimize_dir()` 返回 `OptimizeResult`,包含:
|
|
111
|
+
|
|
112
|
+
- `original_size`
|
|
113
|
+
- `output_size`
|
|
114
|
+
- `savings_ratio`
|
|
115
|
+
- `skipped`
|
|
116
|
+
- `error`
|
|
117
|
+
- `source_path`
|
|
118
|
+
- `output_path`
|
|
119
|
+
|
|
120
|
+
## Preset
|
|
121
|
+
|
|
122
|
+
| Preset | 输出 | 用途 |
|
|
123
|
+
| --- | --- | --- |
|
|
124
|
+
| `web` | webp,quality 82,最大宽度 1920 | 通用网页图片 |
|
|
125
|
+
| `blog` | webp,quality 78,最大宽度 1600 | 博客和文章配图 |
|
|
126
|
+
| `avatar` | webp,quality 85,最大 256 x 256 | 头像 |
|
|
127
|
+
| `lossless` | png,quality 100 | 偏无损的清理和元数据移除 |
|
|
128
|
+
|
|
129
|
+
## 大图处理
|
|
130
|
+
|
|
131
|
+
默认情况下,picx 会保留 Pillow 的大图安全策略。如果图片超过像素限制,picx 会给出清晰错误和下一步建议,而不是直接抛出原始 traceback。
|
|
132
|
+
|
|
133
|
+
如果图片来源可信,可以使用:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
--allow-large --max-pixels 400000000
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
如果希望更省内存地处理超大 TIFF、PNG 等图片,优先使用:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
--backend pyvips
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
pyvips 的 Python 包会随 `picx` 安装,但原生 libvips 需要单独安装,并且必须安装在运行 `picx` 的同一个环境里。
|
|
146
|
+
|
|
147
|
+
## WebP 尺寸限制
|
|
148
|
+
|
|
149
|
+
单个 WebP 文件的宽和高都应不超过 16383 像素。超过这个尺寸时,即使 pyvips 能读入原图,编码成单个 WebP 也可能失败。
|
|
150
|
+
|
|
151
|
+
解决方式:
|
|
152
|
+
|
|
153
|
+
- 用 `--max-width` / `--max-height` 缩放到限制以内。
|
|
154
|
+
- 使用 `picx tile` 输出切片。
|
|
155
|
+
- 改用适合大图的其它格式。
|
|
156
|
+
|
|
157
|
+
## 切片和 manifest
|
|
158
|
+
|
|
159
|
+
`picx tile` 会输出一组 tile 图片和 `manifest.json`。
|
|
160
|
+
|
|
161
|
+
manifest 不是合并后的大图,而是切片索引。它记录原图尺寸、tile 大小、输出格式、层级,以及每张 tile 的路径和坐标。查看器或后续工具可以根据这些坐标可靠地展示或重建切片布局。
|
|
162
|
+
|
|
163
|
+
## 开发
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python3 -m pytest
|
|
167
|
+
```
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# picx
|
|
2
|
+
|
|
3
|
+
picx is a small Python image optimization package for web assets, blogs, avatars,
|
|
4
|
+
and batch cleanup jobs. The package installs a CLI named `picx` and exposes a
|
|
5
|
+
compact Python API under `picx`.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Compress single images or entire directories.
|
|
10
|
+
- Convert between `jpg`, `png`, `webp`, `avif`, and `tiff` outputs.
|
|
11
|
+
- Read `jpg`, `jpeg`, `png`, `webp`, `avif`, `tif`, and `tiff` inputs.
|
|
12
|
+
- Resize with `max_width` and `max_height`.
|
|
13
|
+
- Strip image metadata by default.
|
|
14
|
+
- Search for the highest quality under a target byte size.
|
|
15
|
+
- Render CLI compression reports with Rich.
|
|
16
|
+
- Use `web`, `blog`, `avatar`, and `lossless` presets.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install -e ".[dev]"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`pip install picx-image-optimizer` installs the pyvips Python backend package. pyvips also
|
|
25
|
+
needs the native libvips system library for large-image processing. pip cannot
|
|
26
|
+
install this native system library for every platform, so install it once with
|
|
27
|
+
your OS or environment package manager:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
brew install vips
|
|
31
|
+
# or
|
|
32
|
+
conda install -c conda-forge libvips pyvips
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Install libvips in the same environment that runs `picx`. For example, if you
|
|
36
|
+
run `picx` inside `conda activate comfyui`, install libvips inside that conda
|
|
37
|
+
environment. Mixing Homebrew libvips with Anaconda/conda libraries can still
|
|
38
|
+
fail on macOS with dynamic-library or code-signature errors.
|
|
39
|
+
|
|
40
|
+
## CLI
|
|
41
|
+
|
|
42
|
+
Optimize one image:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
picx image ./photo.png --output ./dist/photo.webp --format webp --quality 82
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Optimize a directory recursively while preserving relative paths:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
picx dir ./images ./out --format webp --preset web
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Try a target size in bytes:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
picx image ./hero.jpg --output ./out/hero.webp --format webp --target-size 120000
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Handle trusted large images with Pillow:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
picx image ./texture.tif --output ./texture.webp --format webp --allow-large --max-pixels 400000000
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Use the pyvips backend for large images:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
picx image ./texture.tif --output ./texture.webp --format webp --backend pyvips
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
WebP has a per-side dimension limit of 16383 pixels. If either width or height
|
|
73
|
+
is larger, resize first or use tiling:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
picx image ./texture.tif --output ./texture.webp --format webp --backend pyvips --max-height 16000
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Create tiles and a manifest for very large images:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
picx tile ./texture.tif ./tiles --tile-size 1024 --format webp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Python API
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from picx import optimize_dir, optimize_image, tile_image
|
|
89
|
+
|
|
90
|
+
single = optimize_image(
|
|
91
|
+
"photo.png",
|
|
92
|
+
output="dist/photo.webp",
|
|
93
|
+
format="webp",
|
|
94
|
+
quality=82,
|
|
95
|
+
max_width=1600,
|
|
96
|
+
strip_meta=True,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
batch = optimize_dir(
|
|
100
|
+
"images",
|
|
101
|
+
"out",
|
|
102
|
+
format="webp",
|
|
103
|
+
preset="blog",
|
|
104
|
+
recursive=True,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
tiles = tile_image("texture.tif", "tiles", tile_size=1024, format="webp")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`optimize_image()` and `optimize_dir()` return `OptimizeResult` objects with:
|
|
111
|
+
|
|
112
|
+
- `original_size`
|
|
113
|
+
- `output_size`
|
|
114
|
+
- `savings_ratio`
|
|
115
|
+
- `skipped`
|
|
116
|
+
- `error`
|
|
117
|
+
- `source_path`
|
|
118
|
+
- `output_path`
|
|
119
|
+
|
|
120
|
+
## Presets
|
|
121
|
+
|
|
122
|
+
| Preset | Output | Purpose |
|
|
123
|
+
| --- | --- | --- |
|
|
124
|
+
| `web` | webp, quality 82, max width 1920 | General website images |
|
|
125
|
+
| `blog` | webp, quality 78, max width 1600 | Blog and article images |
|
|
126
|
+
| `avatar` | webp, quality 85, max 256 x 256 | Profile images |
|
|
127
|
+
| `lossless` | png, quality 100 | Lossless-ish cleanup with metadata stripping |
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
python3 -m pytest
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
picx uses Pillow by default and includes the pyvips Python backend package.
|
|
136
|
+
The pyvips backend also requires the native libvips system library, which pip
|
|
137
|
+
does not install automatically. Install libvips in the same environment that
|
|
138
|
+
runs `picx`.
|
|
139
|
+
|
|
140
|
+
## Large Images
|
|
141
|
+
|
|
142
|
+
By default, picx keeps Pillow's large-image safety posture. If an image exceeds
|
|
143
|
+
the configured pixel limit, picx reports a clear error with next steps instead
|
|
144
|
+
of showing a raw traceback. For trusted images, use `--allow-large` and optionally
|
|
145
|
+
set `--max-pixels`. For memory-efficient processing, install system libvips and
|
|
146
|
+
select `--backend pyvips` or keep the default `--backend auto`.
|
|
147
|
+
|
|
148
|
+
For single-file WebP output, keep both width and height at or below 16383 pixels.
|
|
149
|
+
Images larger than that should be resized with `--max-width` / `--max-height`, or
|
|
150
|
+
exported with `picx tile` instead.
|
|
151
|
+
|
|
152
|
+
`picx tile` writes image tiles plus `manifest.json`. The manifest is an index,
|
|
153
|
+
not a merged image: it records the original size, tile size, output format,
|
|
154
|
+
levels, and every tile's path and coordinates so another tool can display or
|
|
155
|
+
reconstruct the tile layout reliably.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from picx import optimize_dir, optimize_image
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def main() -> None:
|
|
5
|
+
image_result = optimize_image(
|
|
6
|
+
"assets/photo.jpg",
|
|
7
|
+
output="out/photo.webp",
|
|
8
|
+
format="webp",
|
|
9
|
+
quality=82,
|
|
10
|
+
max_width=1600,
|
|
11
|
+
target_size=120_000,
|
|
12
|
+
)
|
|
13
|
+
print(image_result)
|
|
14
|
+
|
|
15
|
+
dir_results = optimize_dir("assets", "out", preset="web")
|
|
16
|
+
print(f"optimized {len(dir_results)} images")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
if __name__ == "__main__":
|
|
20
|
+
main()
|