All notable changes to this project will be documented in this file. This changelog was created during the development of v0.5, therefore all changes logged prior to v0.5 may not be accurate and are only based on previous Git commits.
Versions prior to v0.7 are not tagged/released on GitHub.
- Add
PngEncoderOptions::new
- Fix GIF encoding issues as produced in #38
- Fix text alignment rendering duplicately (#28)
- Fix
TextLayouts with varying fonts not registering properly (#29) - Fix paletted images panicking when attempting to encode as GIFs
- Fix encoding image sequences not respecting delay and disposal method
- Fix tests/doctests
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
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()
}- 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
- 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
Not(invert/negation) forRgbis much more efficient in release mode
- 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
Rectangle::newdeprecated in favor ofRectangle::at. Additionally, identical behavior can be found with<Rectangle as Default>::default.
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
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
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")
}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:
- 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.
- Add new
staticfeature. When enabled, this will statically link any native dependencies - Add non-zero width/height assertions to image constructors
- Fix GIF decoding bug for images with a global palette
- Fix conversion using
Pixel::from_arbitrary_palettewith dynamic pixels
ImageSequence::first_framenow returnsOption<&Frame>instead of&Frame.- Also introduces new
first_frame_mutandfirst_frame[_mut]_uncheckedmethods.
- Also introduces new
- 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
- Add WebP encoding and decoding support
- Add the
all-purecrate feature that enables all feature except forwebp- This is because WASM does not support WebP since the feature uses the native
libwebp. (as of v0.6-dev)
- This is because WASM does not support WebP since the feature uses the native
- Rework of pixel interface
- Remove
PixelDataenum in place of more efficientPixel::BIT_DEPTHandPixel::COLOR_TYPEconstants- Includes new
Pixel::color_typemethod for dynamic pixels PixelData::from_rawis nowPixel::from_raw_parts
- Includes new
- Implement
Hashfor pixel types Pixel::Subpixelassociated type now has boundsCopy + Into<u8>- Most places that take
&mut Imagecan now takeimpl DerefMut<Target = Image>instead (e.g. draw/text methods) Pixel::from_dynamiccan now do dynamic conversions between any pixel types
- Remove
- Implement all
From<Image<_>>forImage<T>as an alternative toImage::convert::<T> - Implement paletted images
Image::from_paletted_pixelscan create an image from raw paletted pixelsImage::palette[_mut][_unchecked]methods for accessing the image's paletteImage::map_palettefor mapping the image's paletteImage::flatten_palettefor converting a paletted image to a non-paletted image- New pixel trait
Paletted<'p>where'pis the lifetime of the palette (usually owned by the parentImage) - New pixel types:
PalettedRgbandPalettedRgba Pixel::Colorassociated type is eitherSelffor non-paletted pixels or the palette's pixel type for paletted pixelsPixel::from_arbitrary_palettefor converting any raw indexed pixel to the desired pixel typePixel::from_raw_parts_palettedisPixel::from_raw_partsthat accepts a palette
- Other QoL API improvements
Imageconstruct method naming changes (this is also reflected forImageSequence)Image::decode_from_bytesis nowImage::from_readerImage::decode_inferred_from_bytesis nowImage::from_reader_inferred- Add
Image::from_bytes[_inferred]for decoding directly from anyimpl AsRef<[u8]>- Useful for using with
include_bytes!macro - For
ImageSequencethis will only accept slices only (&[u8]instead ofimpl AsRef<[u8]>)
- Useful for using with
- Add a variety of colorops
Image::brighten[ed]will brighten the image by a given amountImage::darken[ed]will darken the image by a given amountImage::hue_rotate[d]will rotate the hue of the image by a given amount
- Add
Pixel::Subpixelassociated type, this is the type of the subpixel (e.g.u8forRgba)- Add
Pixel::map_subpixelsfor mapping the subpixels of a pixel
- Add
- Add
TrueColorpixel trait, implemented for allPixelsthat are convertable intoRgborRgba
- Separate various encoding dependencies and other features into cargo features
- Add text rendering support
- Various performance improvements
- Add GIF en/decoding support
- Add JPEG en/decoding support
- Add support for
ImageSequenceand APNGs - Switch encoders to use external crates
Initial release
