Skip to content

Commit

Permalink
Update to oxipng 8 (#9)
Browse files Browse the repository at this point in the history
* Update to oxipng 8

Fix corresponding APIs

* Update types and tests for new options format

* Update README and CHANGELOG

* Clearer Interlacing None option name

NoOp -> Off to indicate that this disables interlacing on output PNG

* v8.0.0
  • Loading branch information
Nick Frasser authored Jan 4, 2023
1 parent 6109da0 commit 24524db
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 77 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 8.0.0

- Update to oxipng 8
- BREAKING: `interlace` option now expects `oxipng.Interlace` enum
- BREAKING: replace `alphas` option with `optimize_alpha` boolean
- Added: `check` option

## 7.0.0

- Upgrade to oxipng 7
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyoxipng"
version = "7.0.0"
version = "8.0.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -9,5 +9,5 @@ name = "oxipng"
crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.17.2", features = ["extension-module"] }
oxipng = { version = "7.0.*" }
pyo3 = { version = "0.17.3", features = ["extension-module"] }
oxipng = { version = "8.0.*" }
25 changes: 11 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ oxipng.optimize("/path/to/image.png", level=6, backup=True, interlace=1)
| `level` | Set the optimization level to an integer between 0 and 6 (inclusive) | `int` | `2` |
| `backup` | Whether the input file should be backed up before writing the output | `bool` | `False` |
| `fix_errors` | Attempt to fix errors when decoding the input file rather than throwing `PngError` | `bool` | `False` |
| `check` | Don't actually run any optimizations, just parse the PNG file | `bool` | `False` |
| `pretend` | Don't actually write any output file, just calculate the best results | `bool` | `False` |
| `force` | Write to output even if there was no improvement in compression | `bool` | `False` |
| `preserve_attrs` | Ensure the output file has the same permissions as the input file | `bool` | `False` |
| `filter` | Which filters to try on the file. Use Use enum values from `oxipng.RowFilter` | `set=[RowFilter.NoOp]` | `{RowFilter.NoOp}` |
| `interlace` | Whether to change the interlacing type of the file. `0` means disable interlacing. `1` means enable it. `None` means leave as is | `int \| None` | `None` |
| `alphas` | Alpha filtering strategies to use. Use enum values from `oxipng.AlphaOptim` | `set[AlphaOptim]` | `{AlphaOptim.NoOp}` |
| `interlace` | Whether to change the interlacing type of the file. `None` will not change current interlacing type | `Interlacing \| None` | `None` |
| `optimize_alpha` | Whether to allow transparent pixels to be altered to improve compression | `bool` | `False` |
| `bit_depth_reduction` | Whether to attempt bit depth reduction | `bool` | `True` |
| `color_type_reduction` | Whether to attempt color type reduction | `bool` | `True` |
| `palette_reduction` | Whether to attempt palette reduction | `bool` | `True` |
Expand All @@ -88,18 +89,6 @@ oxipng.optimize("/path/to/image.png", level=6, backup=True, interlace=1)
| `use_heuristics` | Whether to use heuristics to pick the best filter and compression. Intended for use with `level=1` | `bool` | `False` |
| `timeout` | Maximum amount of time to spend (in milliseconds) on optimizations. Further potential optimizations are skipped if the timeout is exceeded | `int \| None` | `None` |

### alphas

Initialize the `alphas` set with any of the following enum options:

- `oxipng.AlphaOptim.NoOp`
- `oxipng.AlphaOptim.Black`
- `oxipng.AlphaOptim.White`
- `oxipng.AlphaOptim.Up`
- `oxipng.AlphaOptim.Right`
- `oxipng.AlphaOptim.Down`
- `oxipng.AlphaOptim.Left`

### filter

Initialize the `filter` set with any of the following enum options:
Expand All @@ -113,6 +102,14 @@ Initialize the `filter` set with any of the following enum options:
- `oxipng.RowFilter.BigEnt`
- `oxipng.RowFilter.Brute`

### interlace

Set `interlace` to `None` to keep existing interlacing or to one of following
enum options:

- `oxipng.Interlacing.Off` (interlace disabled)
- `oxipng.Interlacing.Adam7` (interlace enabled)

### strip

Initialize the `strip` option with one of the following static methods in the
Expand Down
23 changes: 10 additions & 13 deletions oxipng.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,6 @@ StrOrBytesPath = Union[str, bytes, Path]

class PngError(Exception): ...

class AlphaOptim(Enum):
NoOp = ...
Black = ...
White = ...
Up = ...
Right = ...
Down = ...
Left = ...

class RowFilter(Enum):
NoOp = ...
Sub = ...
Expand All @@ -32,6 +23,10 @@ class RowFilter(Enum):
BigEnt = ...
Brute = ...

class Interlacing(Enum):
Off = ...
Adam7 = ...

class Headers:
@staticmethod
def none() -> "Headers": ...
Expand Down Expand Up @@ -70,12 +65,13 @@ def optimize(
level: int = 2,
backup: bool = False,
fix_errors: bool = False,
check: bool = False,
pretend: bool = False,
force: bool = False,
preserve_attrs: bool = False,
filter: Set[RowFilter] = {RowFilter.NoOp},
interlace: Optional[int] = None,
alphas: Set[AlphaOptim] = {AlphaOptim.NoOp},
interlace: Optional[Interlacing] = None,
optimize_alpha: bool = False,
bit_depth_reduction: bool = True,
color_type_reduction: bool = True,
palette_reduction: bool = True,
Expand All @@ -91,12 +87,13 @@ def optimize_from_memory(
level: int = 2,
backup: bool = False,
fix_errors: bool = False,
check: bool = False,
pretend: bool = False,
force: bool = False,
preserve_attrs: bool = False,
filter: Set[RowFilter] = {RowFilter.NoOp},
interlace: Optional[int] = None,
alphas: Set[AlphaOptim] = {AlphaOptim.NoOp},
interlace: Optional[Interlacing] = None,
optimize_alpha: bool = False,
bit_depth_reduction: bool = True,
color_type_reduction: bool = True,
palette_reduction: bool = True,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "maturin"
[project]
name = "pyoxipng"
requires-python = ">=3.7"
version = "7.0.0"
version = "8.0.0"
description = "Python wrapper for multithreaded .png image file optimizer oxipng"
readme = "README.md"
license = { file = "LICENSE" }
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ fn optimize_from_memory(data: &PyBytes, kwds: Option<&PyDict>) -> PyResult<Py<Py
#[pymodule]
fn oxipng(py: Python, m: &PyModule) -> PyResult<()> {
m.add("PngError", py.get_type::<PngError>())?;
m.add_class::<parse::AlphaOptim>()?;
m.add_class::<parse::RowFilter>()?;
m.add_class::<parse::Interlacing>()?;
m.add_class::<parse::Headers>()?;
m.add_class::<parse::Deflaters>()?;
m.add_function(wrap_pyfunction!(optimize, m)?)?;
Expand Down
74 changes: 34 additions & 40 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,6 @@ use op::IndexSet;

use crate::util::*;

// Alpha optimization
#[pyclass]
#[derive(Clone, Debug)]
pub enum AlphaOptim {
NoOp = op::AlphaOptim::NoOp as isize,
Black = op::AlphaOptim::Black as isize,
White = op::AlphaOptim::White as isize,
Up = op::AlphaOptim::Up as isize,
Right = op::AlphaOptim::Right as isize,
Down = op::AlphaOptim::Down as isize,
Left = op::AlphaOptim::Left as isize,
}

#[pymethods]
impl AlphaOptim {
fn __hash__(&self) -> u64 {
let mut hasher = DefaultHasher::new();
(self.clone() as u64).hash(&mut hasher);
hasher.finish()
}
}

impl From<AlphaOptim> for op::AlphaOptim {
fn from(val: AlphaOptim) -> Self {
match val {
AlphaOptim::NoOp => Self::NoOp,
AlphaOptim::Black => Self::Black,
AlphaOptim::White => Self::White,
AlphaOptim::Up => Self::Up,
AlphaOptim::Right => Self::Right,
AlphaOptim::Down => Self::Down,
AlphaOptim::Left => Self::Left,
}
}
}

// Filter
#[pyclass]
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -89,6 +53,32 @@ impl From<RowFilter> for op::RowFilter {
}
}

// Interlacing
#[pyclass]
#[derive(Clone, Debug)]
pub enum Interlacing {
Off = op::Interlacing::None as isize,
Adam7 = op::Interlacing::Adam7 as isize,
}

#[pymethods]
impl Interlacing {
fn __hash__(&self) -> u64 {
let mut hasher = DefaultHasher::new();
(self.clone() as u64).hash(&mut hasher);
hasher.finish()
}
}

impl From<Interlacing> for op::Interlacing {
fn from(val: Interlacing) -> Self {
match val {
Interlacing::Off => Self::None,
Interlacing::Adam7 => Self::Adam7,
}
}
}

#[pyclass]
#[derive(Debug, Clone)]
pub struct Headers(pub op::Headers);
Expand Down Expand Up @@ -204,18 +194,22 @@ fn parse_kw_opt(key: &str, value: &PyAny, opts: &mut op::Options) -> PyResult<()
"level" => {} // Handled elsewhere, ignore
"backup" => opts.backup = value.downcast::<PyBool>()?.is_true(),
"fix_errors" => opts.fix_errors = value.downcast::<PyBool>()?.is_true(),
"check" => opts.check = value.downcast::<PyBool>()?.is_true(),
"pretend" => opts.pretend = value.downcast::<PyBool>()?.is_true(),
"force" => opts.force = value.downcast::<PyBool>()?.is_true(),
"preserve_attrs" => opts.preserve_attrs = value.downcast::<PyBool>()?.is_true(),
"filter" => {
opts.filter =
py_iter_extract_map::<RowFilter, op::RowFilter, IndexSet<op::RowFilter>>(value)?
}
"interlace" => opts.interlace = py_option(value)?,
"alphas" => {
opts.alphas =
py_iter_extract_map::<AlphaOptim, op::AlphaOptim, IndexSet<op::AlphaOptim>>(value)?
"interlace" => {
opts.interlace = if let Some(i) = py_option::<Interlacing>(value)? {
Some(i.into())
} else {
None
}
}
"optimize_alpha" => opts.optimize_alpha = value.downcast::<PyBool>()?.is_true(),
"bit_depth_reduction" => opts.bit_depth_reduction = value.downcast::<PyBool>()?.is_true(),
"color_type_reduction" => opts.color_type_reduction = value.downcast::<PyBool>()?.is_true(),
"palette_reduction" => opts.palette_reduction = value.downcast::<PyBool>()?.is_true(),
Expand Down
4 changes: 2 additions & 2 deletions test/test_oxipng.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ def test_optimize_opts(infile, bakfile):
force=True,
preserve_attrs=True,
filter={oxipng.RowFilter.Sub, oxipng.RowFilter.Up, oxipng.RowFilter.Average},
interlace=1,
alphas={oxipng.AlphaOptim.White},
interlace=oxipng.Interlacing.Adam7,
optimize_alpha=True,
bit_depth_reduction=False,
palette_reduction=False,
grayscale_reduction=False,
Expand Down

0 comments on commit 24524db

Please sign in to comment.