Releases: jay3332/ril
Releases · jay3332/ril
v0.10.2
v0.10.1
v0.10
v0.10 (2023-10-12)
Major encoder/decoder interface changes
v0.10 introduces a major overhaul to the Encoder/Decoder interfaces.
- Added support for lazy encoding of image sequences.
- The
Encodertrait has been overhauled- New associated type
<_ as Encoder>::Configfor configuring specific encoders - Encoding logic between static images and image sequences are now unified: main encoding logic will occur in
Encoder::add_frame - Shortcut associated methods
Encoder::encode_staticandEncoder::encode_sequencehave been added - Encoders now take metadata, which can be an
&Image,&Frame, orEncoderMetadata- You can derive an
EncoderMetadatafrom anImageorFramewith theFrom/Intotrait
(i.e.EncoderMetadata::from(&image))
- You can derive an
- See below to see how you can lazily encode a stream of frames into a GIF
- New associated type
- The
- Removed
DynamicFrameIterator- Replaced with
Box<dyn FrameIterator<_>> - The new
SingleFrameIteratorstruct allows for iterating over a single static image
- Replaced with
ImageFormatstruct is now moved into a private standaloneformatmodule.- This is breaking if you were importing
ril::image::ImageFormat(useril::ImageFormatinstead)
- This is breaking if you were importing
Example: Lazily encoding a GIF
use std::fs::File;
use std::time::Duration;
use ril::encodings::gif::GifEncoder; // import the encoder for your desired format
use ril::prelude::*;
fn main() -> ril::Result<()> {
let mut dest = File::create("output.gif")?;
// Create a new 256x256 RGB image with a black background
let black_image = Image::new(256, 256, Rgb::black());
// Create a new 256x256 RGB image with a white background
let white_image = Image::new(256, 256, Rgb::white());
// Prepare the encoder, using one of our images as metadata
// note: the image ONLY serves as metadata (e.g. dimensions, bit depth, etc.),
// it is not encoded into the GIF itself when calling `Encoder::new`
// note: you will see what `into_handle` does later
let mut encoder = GifEncoder::new(&mut dest, &image)?;
// Lazily encode 10 frames into the GIF
for i in 0..10 {
// Create a new frame with a delay of 1 second
let frame = if i % 2 == 0 { black_image.clone() } else { white_image.clone() };
let frame = Frame::from_image(frame).with_delay(Duration::from_secs(1));
// Add the frame to the encoder
encoder.add_frame(&frame)?;
}
// Finish the encoding process
encoder.finish()
}Other breaking changes
- Image generic type
Pdoes not have a default anymore- In other words:
struct Image<P: Pixel = Dynamic>is nowstruct Image<P: Pixel> - This means when you create a new image, you will need to specify the pixel type:
Image::<Rgb>::new(256, 256, Rgb::black())Image::<Dynamic>::open("image.png")?
- You can add a type alias
type DynamicImage = Image<Dynamic>;if you want to keep the old behavior
- In other words:
LinearGradientInterpolationrenamed toGradientInterpolationLinearGradientBlendModerenamed toGradientBlendMode- Removes
Pixel::invertedin favor ofstd::ops::Not- Instead of
pixel.inverted(), you can now do!pixelimage.inverted()is removed and replaced with!image
- This is not the same as the old
Pixel::invertedas it will also invert alpha - Adds various implementations for
Image<Rgba>:Image::<Rgba>::split_rgb_and_alphasplits the image into(Image<Rgb>, Image<L>)Image::<Rgba>::from_rgb_and_alphacreates an RGBA image from(Image<Rgb>, Image<L>)Image::<Rgba>::map_rgb_pixelsmaps only the R@claGB pixels of the image- Allows for
image.map_rgb_pixels(|p| !p)for the previous behavior
- Allows for
Image::<Rgba>::map_alpha_pixelsmaps only the alpha pixels of the image
- Instead of
Fill/IntoFillstructs are now moved into a standalonefillmodule.- Differentiate text anchor and text alignment
TextLayout::{centered, with_horizontal_anchor, with_vertical_anchor}will now change the text anchor but
not the alignment the text- Adds
TextAlignenum for text alignment (left, center, right) - Adds
TextLayout::with_alignto specify text alignment - This is a breaking change behavior-wise
- For example, if you have
.centered()in your code, you will need to change it to
.with_align(TextAlign::Center).centered()to produce the same results.
- For example, if you have
Error::IOErrorrenamed toError::IoError
Other changes
- Implement
std::error::ErrorforError - Add radial gradients via
RadialGradient- This adds
GradientPositionandRadialGradientCoverenums
- This adds
- Add conic gradients via
ConicGradient - Add
Rectangle::atmethod, which creates a rectangle at specified coordinates. - Add
Rectangle::squareto create a rectangle with equal side lengths - Document
Fill/IntoFillstructs - Add
ImageFillfill struct for image-clipped fills.IntoFillis implemented for&Image.
- Add
ResizeAlgorithm::Tilewhich repeats copies of the image to fill the target dimensions
Performance improvements
Not(invert/negation) forRgbis much more efficient in release mode
Bug fixes
- Fix
Linepanicking with reversed vertices- This error was most commonly encountered with rendering
Polygonwith borders or antialiasing
- This error was most commonly encountered with rendering
- Fix compile-time errors when enabling
jpegfeature without enabling thegiffeature - Fix memory leaks when encoding/decoding WebP images
Deprecated methods
Rectangle::newdeprecated in favor ofRectangle::at. Additionally, identical behavior can be found with
<Rectangle as Default>::default.
v0.9
v0.9 (2022-12-13)
Breaking changes
Pixel::force_into_rgb[a]method is now replaced withPixel::as_rgb[a], which also takes self by reference instead
of by value.- All provided
Drawobjects (but not theDrawtrait itself) are now generic overF: IntoFillinstead ofP: Pixel- The trait
IntoFillis explained below - There should be no change in usage because for any
P: Pixel,Pis implemented forIntoFill - If you are extracting the fill color from a
Drawobject, you will need to access the.color()method on
theSolidColorstruct. It is aconst fn. - The
Drawtrait is still generic overP: Pixel, no changes there
- The trait
Other changes
ColorType::is_dynamicis now aconst fn- Add
ColorType::has_alphafor whether the color type has an alpha channel - Add new
Filltrait, used to represent a fill color (or gradient, see below) for aDrawobject. This replaces the
simplePixeltrait previously used for this purpose.- Add new
IntoFilltrait, which provides a way to convert anything to aFillobject- Associated type
<_ as IntoFill>::Pixelis the pixel type of the fill. - Associated type
<_ as IntoFill>::Fillis the actual fill type. IntoFillis implemented for allP: Pixeland turns intodraw::SolidColor<P>IntoFillis implemented forLinearGradient(see below) and turns intogradient::LinearGradientFill<P>
- Associated type
- Add new
- Add support for gradients
- Enabled with the
gradientfeature, which is enabled by default - New
LinearGradientstruct, which represents a linear gradientLinearGradientBlendModeandLinearGradientInterpolationenums are re-exports from thecolorgradcrate,
which is used to configure the gradient's blending mode and interpolation.
- Enabled with the
- Add
Polygon::regularmethod, which creates a regular polygon with the given amount of sides, center, and radius- This uses the
Polygon::regular_rotatedmethod, which is the same method, but you are able to specify the rotation
of the polygon in radians.
- This uses the
Linear gradient example
use ril::prelude::*;
fn main() -> ril::Result<()> {
// Create a new 256x256 RGB image with a black background
let mut image = Image::new(256, 256, Rgb::black());
// Create the `LinearGradient` object
let gradient = LinearGradient::new()
// The gradient will be rotated 45 degrees
.with_angle_degrees(45.0)
// The first stop is at 0.0, and is red
.with_color(Rgb::new(255, 0, 0))
// The second stop is at 0.5, and is white
.with_color(Rgb::new(255, 255, 255))
// We can also specify color stop positions manually:
// .with_color_at(0.5, Rgb::new(255, 255, 255))
// ...
// The third stop is at 1.0, and is green
.with_color(Rgb::new(0, 255, 0));
// Fill a hexagon with the gradient and draw it to the image
image.draw(&Polygon::regular(6, image.center(), 64).with_fill(gradient));
// Save the image to a PNG file
image.save_inferred("gradient_output.png")
}Output
Full Changelog: v0.8...v0.9
v0.8
v0.8 (2022-11-30)
Breaking changes
Pastedraw struct now stores images and masks by reference instead of by value. This is to prevent
unnecessary cloning of large images and/or masks.- Paste now has two generic lifetime arguments:
Paste<'img, 'mask, _>. - This also means that
Image::paste,Image::paste_with_mask, andImage::withmethods now take images and masks
by reference instead of by value too.
- Paste now has two generic lifetime arguments:
Other changes
- Add support for drawing lines and polygons using
LineandPolygondraw entities- Drawing a line or polygon with rounded vertices and a non-centered border position results in undesired output as
of now.
- Drawing a line or polygon with rounded vertices and a non-centered border position results in undesired output as
- Add new
staticfeature. When enabled, this will statically link any native dependencies - Add non-zero width/height assertions to image constructors
Bug fixes
- Fix GIF decoding bug for images with a global palette
- Fix conversion using
Pixel::from_arbitrary_palettewith dynamic pixels
Full Changelog: v0.7...v0.8
v0.7
v0.7 (2022-11-22)
Breaking changes
ImageSequence::first_framenow returnsOption<&Frame>instead of&Frame.- Also introduces new
first_frame_mutandfirst_frame[_mut]_uncheckedmethods.
- Also introduces new
Other changes
- Add crate-level support for image quantization
- The new
quantizefeature enables thecolor_quantdependency for more complex quantization algorithms
This is enabled by default, mainly becausecolor_quantappears to not pull any additional dependencies Quantizerstruct can handle direct quantization of raw pixel dataImage::quantizeis a higher-level method that can quantize an image into a paletted image- Implement
From<Image<Rgb[a]>>forImage<PalettedRgb[a]>which utlizes quantization
- The new
- Fix decoding bug for JPEG images with L pixels