17 releases
0.8.90-alpha.2 | Aug 7, 2024 |
---|---|
0.8.90-alpha.1 | Jul 16, 2024 |
0.8.50 | Aug 31, 2024 |
0.8.40 | Jun 28, 2024 |
0.4.0 |
|
#1 in Images
1,005,218 downloads per month
Used in 1,202 crates
(178 directly)
140KB
2.5K
SLoC
Pixel types for Rust
Operating on pixels as weakly-typed vectors of u8
is error-prone and inconvenient. It's better to use vectors of pixel structs.
However, Rust is so strongly typed that your Rgb
pixel struct is not compatible with my Rgb
pixel struct. So let's all use mine :P
v0.8.90 is a transitional/preview release
The RGB crate is getting a major update, which will eventually be stablized as v1.0.0.
For testing, use:
[dependencies]
rgb = "0.8.90"
# this is required, because v0.8.90 is not on crates.io
[patch.crates-io]
rgb.git = "https://github.com/kornelski/rust-rgb"
We welcome your feedback about the crate!
- Are the names of the traits and their methods good?
- Are there any standard library traits you'd like implemented on the pixel types?
- Is the split between
Pixel
,HetPixel
,HasAlpha
sensible? (pixels support a different type for the alpha channel, and there'sRgbw
without alpha).
Please open issues in the repo with the feedback or message @kornel@mastodon.social.
Installation
If you want to run a stable, compatible version, run cargo add rgb@0.8.47
.
If you want to try unstable experimental version, run cargo add rgb@0.8.90-alpha.1
or add this to your Cargo.toml
:
[dependencies]
rgb = "0.8.90-alpha.1" # unstable experimental version
# rgb = "0.8.47" # older, stable
Usage
use rgb::{Rgb, Rgba, Argb, Bgr, Bgra, Abgr, Grb, Gray_v09 as Gray, GrayA};
let rgb = Rgb {r: 0, g: 0, b: 0};
let rbga = Rgba {r: 0, g: 0, b: 0, a: 0};
let argb = Argb {a: 0, r: 0, g: 0, b: 0};
let bgr = Bgr {b: 0, g: 0, r: 0};
let bgra = Bgra {b: 0, g: 0, r: 0, a: 0};
let abgr = Abgr {r: 0, g: 0, b: 0, a: 0};
let grb = Grb {g: 0, b: 0, r: 0};
let gray = Gray {v: 0};
let gray_a = GrayA {v: 0, a: 0};
If you have a pixel type you would like to use that is not currently implemented, please open an issue to request your pixel type.
The pixel types with an alpha component such as Rgba
have two
generic type parameters:
struct Rgba<T, A = T> {
r: T,
g: T,
b: T,
a: A,
}
This makes them more flexible for more use-cases, for example if you
needed more precision for you color components than your alpha
component you could create an Rgba<f32, u8>
. However, in most
use-cases the alpha component type will be the same as the color
component type.
A pixel with separate types for the color and alpha
components is called a heterogeneous pixel (HetPixel
), whereas a pixel with a
single type for both color and alpha components is called a
homogeneous pixel (Pixel
).
Pixel Traits
All functionality for the pixel types is implemented via traits. This
means that none of the pixel types, like Rgb<u8>
, have any inherent
methods. This makes it easy to choose which methods you'd like to be
in scope at any given time unlike inherent methods which are always
within scope.
This crate offers the following traits:
HetPixel
The most foundational pixel trait implemented by every pixel type.
use rgb::{Rgba, HetPixel};
let mut rgba: Rgba<u8> = Rgba::try_from_colors_alpha([0, 0, 0], 0).unwrap();
*rgba.color_array_mut()[2] = u8::MAX;
assert_eq!(rgba.color_array(), [0, 0, 255]);
*rgba.alpha_opt_mut().unwrap() = 50;
assert_eq!(rgba.alpha_opt(), Some(50));
let rgba = rgba.map_colors(u16::from);
let rgba = rgba.map_colors_same(|c| c * 2);
let rgba = rgba.map_alpha(f32::from);
let rgba = rgba.map_alpha_same(|a| a * 2.0);
assert_eq!(rgba, Rgba::<u16, f32> {r: 0, g: 0, b: 510, a: 100.0});
Pixel
A stricter form of HetPixel
where the two component types, color and
alpha, are the same.
use rgb::{Rgba, Pixel};
let mut rgba: Rgba<u8> = Rgba::try_from_components([0, 0, 0, 0]).unwrap();
*rgba.each_mut()[2] = u8::MAX;
assert_eq!(rgba.to_array(), [0, 0, 255, 0]);
let rgba = rgba.map(u16::from);
let rgba = rgba.map_same(|c| c * 2);
assert_eq!(rgba, Rgba::<u16> {r: 0, g: 0, b: 510, a: 0});
GainAlpha
A way to add alpha to a pixel type in various ways.
use rgb::{Rgb, Rgba, GainAlpha};
let expected: Rgba<u8> = Rgba {r: 0, g: 0, b: 0, a: 255};
assert_eq!(Rgb {r: 0, g: 0, b: 0}.with_default_alpha(255), expected);
assert_eq!(Rgb {r: 0, g: 0, b: 0}.with_alpha(255), expected);
assert_eq!(Rgba {r: 0, g: 0, b: 0, a: 0}.with_alpha(255), expected);
HasAlpha
A trait only implemented on pixels that have an alpha component.
Due to a naming conflict with several now-deprecated inherent
functions with the same name (such as Rgb::alpha()
) the
HasAlpha::alpha()
method requires fully qualified syntax for
disambiguation. The deprecated functions are due to be removed in a
future release which will solve this issue.
use rgb::{Rgba, HasAlpha};
let mut rgba: Rgba<u8> = Rgba {r: 0, g: 0, b: 0, a: 255};
*rgba.alpha_mut() -= 50;
assert_eq!(HasAlpha::alpha(&rgba), 205);
Bytemuck
If you have a &[u8]
or Vec<u8>
type and you want a &[Rgb<u8>]
or
Vec<Rgb<u8>>
type then you can safely achieve these type-casts via
the bytemuck
crate (see cast_slice()
and cast_vec()
).
You will need to enable the bytemuck
crate feature in order to use
functions from the bytemuck
library on the pixel types in this
crate.
Crate Features
default
: The default feature which does nothing.num-traits
: Enables variousnum_traits
traits impls for the pixel types such asCheckedAdd
.defmt-03
= Enables theFormat
trait impls fromdefmt
v0.3
for the pixel typesserde
= EnablesSerializable
andDeserializable
trait impls fromserde
for the pixel typesbytemuck
= EnablesPod
andZeroable
trait impls frombytemuck
for the pixel types
Legacy Features
The following crate features are only exposed for compatibility with
the v0.8
release so as to be non-breaking, however, once migrated to
v0.9
you should no longer be using any of these features. They are
going to be removed in the next major release after v0.9
.
argb = []
grb = []
checked_fns = []
as-bytes = ["bytemuck"]
Color-Space Agnostic
This crate is purposefully agnostic about the color-spaces of the
pixel types. For example, Gray<u8>
could be either linear lightness or
gamma-corrected luma, etc.
Correct color management is a complex problem, and this crate aims to be the lowest common denominator, so it's intentionally agnostic about it.
However, this library supports any subpixel type for RGB<T>
, and
RGBA<RGBType, AlphaType>
, so you can use them with a newtype, e.g.:
# use rgb::Rgb;
struct LinearLight(u16);
type LinearRGB = Rgb<LinearLight>;
Roadmap to 1.0
The plan is to provide easy migration to v1.0. There will be a transitional v0.9 version released that will be mostly backwards-compatible with 0.8, and forwards-compatible with 1.0.
Planned changes:
- Types will be renamed to follow Rust's naming convention:
RGBA
→Rgba
. The names with an8
or16
suffix (RGBA8
) will continue to work. - The
Gray
andGrayAlpha
types will change from tuple structs with.0
to structs with named fields.v
(value) and.a
(alpha). Through aDeref
trick both field names will work, but.0
is going to be deprecated. bytemuck::Pod
(conversions from/to raw bytes) will require color and alpha components to be the same type (i.e. it will work withRgba<u8>
, but notRgba<Newtype, DifferentType>
). Currently it's unsound if the alpha has a different size than color components.- Many inherent methods will be moved to a new
Pixel
trait.
Migrating away from deprecated items
Many items in this crate have become deprecated in preparation for a future release which removes them. Here is a checklist of things you may need to do.
- Update to the latest version of 0.8, and fix all deprecation warnings.
- rename
.alpha()
to.with_alpha()
- rename
- Change field access on
GrayAlpha
from.0
and.1
to.v
and.a
where possible. - Use the
bytemuck
crate for conversions from/to bytes. - Use the
num-traits
crate for.checked_add()
, don't enablechecked_fns
feature. - Don't enable
gbr
andargb
features. All pixel types are enabled by default. AsRef<[T]>
implementations have changed toAsRef<[T; N]>
. In most cases.as_ref()
/.as_mut()
calls should coerce to a slice anyway.- Instead of
pixel.as_slice()
usepixel.as_ref()
. - Stop using the
rgb::Gray
/rgb::GrayAlpha
types and switch torgb::Gray_v09 as Gray
/rgb::GrayA
instead respectively.
Dependencies
~0–290KB