otf_pixels_ops/lib.rs
1//! Operation kernels for `otf-pixels`.
2//!
3//! Each op implements [`Op`] and is chained onto an
4//! [`Image`] to build graph structure. Ops do no work when chained — they
5//! declare their output shape and their demand, and run only when a terminal
6//! pulls pixels through them.
7//!
8//! [`Op`]: otf_pixels_core::Op
9//! [`Image`]: otf_pixels_core::Image
10//!
11//! # Scope
12//!
13//! The full v1 op set from SPEC §Core ops is here: [`Resize`], [`Crop`],
14//! [`Rotate`], [`Flip`], [`Flop`], [`Modulate`], [`Convolve`], [`Composite`],
15//! [`ExtractChannel`] and [`Flatten`], with sharp's [`Extend`] and the
16//! per-pixel adjustments in `adjust`. [`Trim`] is the exception: its output
17//! shape depends on pixel values, so it searches computed pixels rather
18//! than being an op.
19//!
20//! # Two kinds of op
21//!
22//! **Layout** ops — crop, flip, flop, rotate — move whole pixels without
23//! inspecting them. They copy opaque byte runs, so one implementation is
24//! correct for every pixel format including ones added later, and they do not
25//! use `dispatch_sample!`: there is no arithmetic to specialize.
26//!
27//! **Arithmetic** ops — resize, modulate, convolve, composite, flatten — read
28//! sample values, so they dispatch once per tile on the sample type and run a
29//! monomorphized inner loop (ADR-0002). Per ADR-0011 those loops are written
30//! to autovectorize rather than to call intrinsics, and 8-bit paths use `i32`
31//! fixed point so that vectorization cannot change the result.
32//!
33//! # Tiling is not observable
34//!
35//! Every op here produces the same pixels whether it runs in one tile or in
36//! many. That is not automatic — a resize whose weight tables were built per
37//! tile would resample at the tile's scale — so each op with a non-trivial
38//! demand mapping asserts it directly.
39//!
40//! # Writing an op
41//!
42//! An op declares four things (ARCHITECTURE §Layer 3):
43//!
44//! - `output_descriptor` — its output shape, computed at graph-build time.
45//! - `input_regions` — the inverse mapping demand propagation walks backwards.
46//! - `access_pattern` — `Sequential` or `Spatial`, driving tile negotiation
47//! (ADR-0003).
48//! - `compute` — the kernel itself.
49//!
50//! The first three are what make an op work correctly under M2's scheduler
51//! rather than only under M1's whole-image evaluator, so they must be right
52//! even while the evaluator only ever asks for whole images.
53
54mod adjust;
55mod composite;
56mod convert;
57mod convolve;
58mod extend;
59mod filter;
60mod geometry;
61mod icc;
62mod pointwise;
63mod resample;
64mod resize;
65mod rotate;
66mod trim;
67
68pub use adjust::{EnsureAlpha, Gamma, Greyscale, Linear, Negate, Recomb, Threshold, Tint};
69pub use composite::{Blend, Composite, Placement};
70pub use convert::ConvertFormat;
71pub use convolve::{Convolve, Kernel};
72pub use extend::{Extend, ExtendWith};
73pub use filter::{Filter, Run, Weights};
74pub use geometry::{Crop, Flip, Flop};
75pub use icc::{Conversion, ToSrgb, Unconvertible};
76pub use pointwise::{ExtractChannel, Flatten, Modulate};
77pub use resize::{Fit, Position, Resize, ResizeOptions};
78pub use rotate::{Quarter, Rotate};
79pub use trim::Trim;