Metadata-Version: 2.4
Name: vapoursynth-cranexpr
Version: 0.11.0
Summary: VapourSynth expr plugin built on top of Cranelift.
License-Expression: Apache-2.0
Requires-Python: >=3.12
Requires-Dist: vapoursynth>=75
Description-Content-Type: text/markdown

# cranexpr

cranexpr is like [`std.Expr`](https://www.vapoursynth.com/doc/functions/video/expr.html)
but built on top of [Cranelift](https://cranelift.dev/). It's a [VapourSynth](https://www.vapoursynth.com/)
plugin that allows one to evaluate an expression per pixel.

## Examples

Median of 3 clips:

```python
core.cranexpr.Expr([x, y, z], "x y min x y max z min max")
```

Flip a clip horizontally:

```python
core.cranexpr.Expr([x], "width X - 1 - Y x[]")
```

3x3 box blur:

```python
core.cranexpr.Expr([x], "x[-1,-1] x[0,-1] x[1,-1] x[-1,0] x x[1,0] x[-1,1] x[0,1] x[1,1] + + + + + + + + 9 /")
```

## Features

- Arithmetic: `+`, `-`, `*`, `/`, `%`, `pow`, `exp`, `log`, `sqrt`.
- Trigonometry: `sin`, `cos`, `tan`, `atan2`.
- Comparison: `>`, `<`, `=`, `>=`, `<=`.
- Logical: `and`, `or`, `xor`, `not`.
- Bitwise: `bitand`, `bitor`, `bitxor`, `bitnot`.
- Clamping: `min`, `max`, `clip` (alias: `clamp`).
- Rounding: `floor`, `round`, `trunc`.
- Ternary (if/else): `?`.
- `sgn`: Returns the sign of a value (-1 if negative, 1 if positive, 0 if zero).
- Constants:
  - `width`: Width of the plane.
  - `height`: Height of the plane.
  - `N`: Current frame number.
  - `pi`: π.
- Stack manipulation:
  - `dropN`, `drop`: drops the top N values from the stack. `drop` is equivalent
    to `drop1`.
  - `dupN`, `dup`: allows a value N steps up in the stack to be duplicated. The
    top value of the stack has index 0 meaning that `dup` is equivalent to
    `dup0`.
  - `swapN`, `swap`: allows a value N steps up in the stack to be swapped. The
    top value of the stack has index 0 meaning that `swap` is equivalent to
    `swap1`. This is because `swapN` always swaps with the topmost value at
    index 0.
- Variables:
  - `var!`: Pops the top value from the stack and stores it in a variable named
    `var`.
  - `var@`: Pushes the value of the variable `var` onto the stack.
- Frame property access: `clip.PropertyName`.
  - Accesses a numeric frame property from the given clip.
  - If the property is missing, its value will be `NaN`.
  - If the property is not a numeric frame property, its value will be the first
    byte.
- Relative pixel access: `clip[relX, relY]:[mode]`.
  - Accesses a pixel relative to the current coordinate (`X`, `Y`). `relX` and
    `relY` must be integer constants.
  - If no suffix is provided, the edge behavior is determined by the filter's
    `boundary` parameter.
    - `:c`: Forces clamped boundary.
    - `:m`: Forces mirrored boundary.
- Absolute pixel access: `absX absY clip[]:[mode]`.
  - Accesses a pixel at an absolute coordinate. It pops `absY` then `absX` from
    the stack. These coordinates can be computed by expressions.
  - If the coordinates are not integers, they will be rounded half to even.
  - **Example:** `X 2 / Y x[]` reads the pixel at half the current X
    coordinate from the first clip, using the default clamp mode.
  - **Boundary Suffixes:**
    - `:c`: Forces clamped boundary.
    - `:m`: Forces mirrored boundary.
- Supports any number of input clips. `srcN` may be used to access the `N`-th
  input clip. Shorthand aliases `x`, `y`, `z`, `a`, `b`, `c`, etc. map to
  `src0`, `src1`, `src2`, `src3`, `src4`, `src5`, etc., up to `w` being `src25`.
  Beyond that, use `srcN`.

## Install

```
pip install vapoursynth-cranexpr
```

## API

```python
cranexpr.Expr(
  clips: vs.VideoNode | Sequence[vs.VideoNode],
  expr: str | list[str],
  format: int | None = None,
  boundary: Literal[0, 1] = 0,
) -> vs.VideoNode
```

- `clips` — Input video nodes.
- `expr` — Reverse Polish Notation (RPN) expression(s) for each plane. The
  expression given for the previous plane is used if the list contains fewer
  expressions than the input clip has planes. This means that a single
  expression will be applied to all planes by default.
- `format` — By default the output format is the same as the first input clip's
  format. This can be overridden by setting this parameter.
- `boundary` — Boundary mode. `0` for clamping, `1` for mirroring.

```python
cranexpr.PropExpr(
  clips: vs.VideoNode | Sequence[vs.VideoNode],
  **kwargs: str,
) -> vs.VideoNode
```

- `clips` — Input video nodes. The first clip's format is used for the output.
- `**kwargs` — Each keyword argument maps a frame property name to a RPN
  expression. The expression is evaluated once per frame and the result is
  written back as a frame property on the output.

`PropExpr` evaluates expressions that produce scalar values and stores them as
frame properties on the output frame. All expressions are evaluated before any
properties are written.

If the computed value is an exact integer, then it is stored as an integer frame
property. Otherwise it is stored as a float.

`PropExpr` supports all operators supported by `Expr` except those that access
pixel values (`x`/`y`/`srcN` as pixel values, relative pixel access like
`x[-1,0]`, absolute pixel access like `x[]`, and the per-pixel coordinate
variables `X` and `Y`).

```python
cranexpr.Select(
  clip_src: vs.VideoNode | Sequence[vs.VideoNode],
  prop_src: vs.VideoNode | Sequence[vs.VideoNode],
  expr: str | list[str],
) -> vs.VideoNode
```

- `clip_src` — Candidate clips. All must have the same format and dimensions.
- `prop_src` — Clips whose frame properties the expression may read.
- `expr` — Reverse Polish Notation (RPN) expression(s) for each plane. The
  expression given for the previous plane is used if the list contains fewer
  expressions than the input clip has planes. This means that a single
  expression will be applied to all planes by default.

`Select` evaluates a RPN expression once per frame (per plane) and uses the
result as an index to pick a clip from `clip_src` to satisfy the current frame
request. It is designed to replace many uses of `std.FrameEval` where you want
to compute a metric from frame properties and then choose one of several clips
to use.

For each output frame and each plane, the filter evaluates the plane's
expression, rounds the result to the nearest integer, clamps it to the range
`[0, len(clip_src) - 1]`, then takes that plane from `clip_src[index]`'s frame
`n`.

`Select` supports all operators supported by `Expr` except those that access
pixel values (`x`/`y`/`srcN` as pixel values, relative pixel access like
`x[-1,0]`, absolute pixel access like `x[]`, and the per-pixel coordinate
variables `X` and `Y`).

Unlike `Expr`, where a non-existent frame property evaluates to `NaN`, `Select`
uses `0.0` instead.
