# fovea-derive
[](https://crates.io/crates/fovea-derive)
[](https://docs.rs/fovea-derive)
[](https://github.com/karhunen-loeve/fovea-derive/blob/main/LICENSE)
`fovea-derive` contains the procedural macros that turn pixel structs into fovea pixel types with explicit layout and semantics.
Most users should depend on `fovea`, not on this crate directly. The core crate re-exports the derives so custom pixel definitions can stay in normal fovea code.
```toml
[dependencies]
fovea = "0.1.1"
```
Depend on `fovea-derive` directly only if you are working on fovea internals or explicitly need the macro crate.
## Derives
| `PlainPixel` | The type has a stable byte layout suitable for byte-level access. |
| `HomogeneousPixel` | Every channel has the same channel type and can be viewed as a channel array. |
| `ZeroablePixel` | The type has an all-zero pixel value for allocation and initialization. |
| `LinearPixel` | The type supports channel-wise linear arithmetic with an explicit accumulator. |
| `WhiteChannel` | A homogeneous pixel can report its white/max channel value. |
The derives are intentionally strict. If the macro rejects a type, it is usually protecting a layout or semantic invariant that unsafe byte paths and transform bounds rely on.
## Custom pixel example
```rust,ignore
use fovea::{HomogeneousPixel, PlainPixel, ZeroablePixel};
use std::num::Saturating;
#[derive(Clone, Copy, PlainPixel, HomogeneousPixel, ZeroablePixel)]
#[repr(C)]
pub struct BayerRg8 {
pub value: Saturating<u8>,
}
```
Use `#[repr(C)]` for multi-field pixels and `#[repr(transparent)]` for one-field wrapper pixels. Avoid implicit layout. Pixel layout is part of the API contract.
## Linear pixels need an accumulator
Interpolation and blending often need more precision than the storage pixel. `LinearPixel` makes that accumulator explicit.
```rust,ignore
use fovea::{HomogeneousPixel, LinearPixel, PlainPixel, ZeroablePixel};
use std::num::Saturating;
#[derive(Clone, Copy, PlainPixel, HomogeneousPixel, ZeroablePixel, LinearPixel)]
#[repr(C)]
#[linear(accumulator = RgbF32)]
pub struct Rgb8 {
pub r: Saturating<u8>,
pub g: Saturating<u8>,
pub b: Saturating<u8>,
}
#[derive(Clone, Copy, PlainPixel, HomogeneousPixel, ZeroablePixel, LinearPixel)]
#[repr(C)]
#[linear(accumulator = Self)]
pub struct RgbF32 {
pub r: f32,
pub g: f32,
pub b: f32,
}
```
Do not derive `LinearPixel` just because arithmetic is possible. Derive it only when blending or interpolation is meaningful for the pixel semantics. Gamma-encoded sRGB pixel types intentionally do not implement `LinearSpace`.
## What this crate is not
`fovea-derive` does not define the pixel model. The model lives in `fovea::pixel`; this crate only automates correct implementations. Read the `fovea` crate docs first unless you are debugging macro behavior.
## Crate ecosystem
| `fovea` | Core crate and normal home of the derive re-exports. |
| `fovea-derive` | Procedural macro implementation crate. |
| `fovea-examples` | Repo-only examples, including custom-pixel patterns. |
## License
Licensed under the [MIT License](https://github.com/karhunen-loeve/fovea-derive/blob/main/LICENSE).