diff --git a/src/color/mod.rs b/src/color/mod.rs index 929e6ac..213613e 100644 --- a/src/color/mod.rs +++ b/src/color/mod.rs @@ -67,10 +67,13 @@ impl Precision { /// A color format with a specific number of channels and precision. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ColorFormat { + /// The number and semantics of the channels. pub channels: Channels, + /// The precision/bit depth of the values in all channels. pub precision: Precision, } impl ColorFormat { + /// Creates a new `ColorFormat` with the given channels and precision. pub const fn new(channels: Channels, precision: Precision) -> Self { Self { channels, diff --git a/src/decode/mod.rs b/src/decode/mod.rs index f573004..d14f0bd 100644 --- a/src/decode/mod.rs +++ b/src/decode/mod.rs @@ -59,7 +59,7 @@ pub(crate) const fn get_decoders(format: Format) -> DecoderSet { Format::Y410 => Y410, Format::Y416 => Y416, - // sub-sampled formats + // subsampled formats Format::R1_UNORM => R1_UNORM, Format::R8G8_B8G8_UNORM => R8G8_B8G8_UNORM, Format::G8R8_G8B8_UNORM => G8R8_G8B8_UNORM, @@ -223,6 +223,13 @@ pub fn decode_rect( } } +/// Options for decoding images. +/// +/// ## See also +/// +/// - [`decode`] +/// - [`decode_rect`] +/// - [`Decoder::options`](crate::Decoder::options) #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct DecodeOptions { diff --git a/src/decode/read_write.rs b/src/decode/read_write.rs index 81a2477..7ed6f13 100644 --- a/src/decode/read_write.rs +++ b/src/decode/read_write.rs @@ -1124,7 +1124,7 @@ pub(crate) fn process_bi_planar_helper< pub(crate) struct BiPlaneInfo { pub plane1_element_size: u8, pub plane2_element_size: u8, - /// The sub-sampling of plane2. + /// The subsampling of plane2. pub sub_sampling: (u8, u8), } pub(crate) fn for_each_bi_planar( diff --git a/src/decoder.rs b/src/decoder.rs index 6c4a323..d3ebc62 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -19,6 +19,9 @@ pub struct Decoder { layout: DataLayout, iter: SurfaceIterator, + /// The options used for decoding. + /// + /// Default: [`DecodeOptions::default()`] pub options: DecodeOptions, } impl Decoder { diff --git a/src/detect.rs b/src/detect.rs index 4c83152..82a17f9 100644 --- a/src/detect.rs +++ b/src/detect.rs @@ -69,7 +69,7 @@ pub(crate) const fn dxgi_format_to_supported(dxgi_format: DxgiFormat) -> Option< DxgiFormat::Y410 => Some(Format::Y410), DxgiFormat::Y416 => Some(Format::Y416), - // sub-sampled formats + // subsampled formats DxgiFormat::R8G8_B8G8_UNORM => Some(Format::R8G8_B8G8_UNORM), DxgiFormat::G8R8_G8B8_UNORM => Some(Format::G8R8_G8B8_UNORM), DxgiFormat::YUY2 => Some(Format::YUY2), diff --git a/src/encode/mod.rs b/src/encode/mod.rs index 0805dc1..3d2d7eb 100644 --- a/src/encode/mod.rs +++ b/src/encode/mod.rs @@ -61,7 +61,7 @@ pub(crate) const fn get_encoders(format: Format) -> Option { Format::Y410 => Y410, Format::Y416 => Y416, - // sub-sampled formats + // subsampled formats Format::R1_UNORM => R1_UNORM, Format::R8G8_B8G8_UNORM => R8G8_B8G8_UNORM, Format::G8R8_G8B8_UNORM => G8R8_G8B8_UNORM, @@ -222,6 +222,12 @@ fn encode_parallel( progress.checked_report(1.0) } +/// Options for encoding images. +/// +/// ## See also +/// +/// - [`encode`] +/// - [`Encoder::encoding`](crate::Encoder::encoding) #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pub struct EncodeOptions { @@ -240,6 +246,9 @@ pub struct EncodeOptions { pub dithering: Dithering, /// The error metric for block compression formats. /// + /// This is currently only supported for BC1-3. All other formats will + /// ignore this option and assume [`ErrorMetric::Uniform`]. + /// /// Default: [`ErrorMetric::Uniform`] pub error_metric: ErrorMetric, /// The compression quality. @@ -276,6 +285,8 @@ impl Default for EncodeOptions { } } +/// Specifies whether dithering is enabled/supported for color and/or alpha +/// channels. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum Dithering { /// Dithering is disabled for all channels. @@ -289,6 +300,7 @@ pub enum Dithering { Alpha = 0b10, } impl Dithering { + /// Creates a new `Dithering` given the channels it is enabled for. pub const fn new(color: bool, alpha: bool) -> Self { match (color, alpha) { (true, true) => Dithering::ColorAndAlpha, @@ -298,9 +310,11 @@ impl Dithering { } } + /// Whether dithering is enabled for color channels. pub const fn color(self) -> bool { matches!(self, Dithering::ColorAndAlpha | Dithering::Color) } + /// Whether dithering is enabled for the alpha channel. pub const fn alpha(self) -> bool { matches!(self, Dithering::ColorAndAlpha | Dithering::Alpha) } @@ -318,10 +332,20 @@ impl Dithering { } } +/// The error metric encoders use to optimize compressed formats. +/// +/// Not all formats support all error metrics. See +/// [`EncodeOptions::error_metric`] for more details. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum ErrorMetric { + /// The error of all channels is weighted equally. #[default] Uniform, + /// Color is assumed to be sRGB, and the error is calculated in a + /// perceptually uniform color space. + /// + /// [Oklab](https://en.wikipedia.org/wiki/Oklab_color_space) is currently + /// used as the perceptually uniform color space. Perceptual, } diff --git a/src/encoder.rs b/src/encoder.rs index ce37649..24a7d85 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -21,13 +21,13 @@ pub struct Encoder { /// The encoding options used to encode surfaces. /// - /// Defaults: `EncodeOptions::default()` + /// Default: `EncodeOptions::default()` pub encoding: EncodeOptions, /// Options regarding automatic mipmap generation. /// /// Set `self.mipmaps.generate = true` to enable automatic mipmap generation. /// - /// Defaults: `MipmapOptions::default()` + /// Default: `MipmapOptions::default()` pub mipmaps: MipmapOptions, // internal cache for resizing @@ -283,16 +283,30 @@ impl Encoder { } } +/// The filter to use when resizing images for mipmap generation. +/// +/// ## See also +/// +/// - [`MipmapOptions::resize_filter`] #[derive(Debug, Clone, Copy, Default)] pub enum ResizeFilter { + /// Nearest neighbor interpolation (=point filtering). Nearest, + /// Box (also called area or binning). + /// + /// This is the default filter, because it produces mipmaps that are + /// generally free of artifacts and sharp (without being over sharpened). #[default] Box, + /// Triangle filtering (=linear interpolation). Triangle, + /// Mitchell interpolation. Mitchell, + /// Lanczos interpolation with a radius of 3. Lanczos3, } +/// Options for automatic mipmap generation in [`Encoder`]. #[derive(Debug, Clone, Copy)] pub struct MipmapOptions { /// Whether to generate mipmaps for the texture. @@ -301,23 +315,25 @@ pub struct MipmapOptions { /// generate all mipmaps until the next level 0 object or EOF. /// /// Note: Generating mipmaps for volume depth slices is not supported. This - /// will **NOT** result in an error and instead the encoder will silently - /// ignore the option. + /// will **NOT** result in an error. Instead, the encoder will silently + /// ignore the option and assume mipmap generation is disabled. /// /// Default: `false` pub generate: bool, - /// Whether the alpha channel (if any) is straight alpha. + /// Whether the alpha channel (if any) is straight alpha transparency. /// /// This is important when generating mipmaps. Resizing RGBA with straight /// alpha requires that the alpha channel is premultiplied into the color - /// channels before resizing and then unpremultiplied after resizing. This + /// channels before resizing and then un-premultiplied after resizing. This /// is necessary to avoid color bleeding. /// - /// If the alpha channel is premultiplied alpha or custom (e.g. like in - /// channel-packed textures), this option should be set to `false`. + /// If the alpha channel is premultiplied alpha transparency or custom + /// (e.g. like in channel-packed textures), this option should be set to + /// `false`. /// /// If this option is set to `false`, all channels will be resized - /// independently of each other. + /// independently of each other. If set to `true`, the alpha channel will + /// be interpreted as straight alpha transparency and handled accordingly. /// /// Default: `true` pub resize_straight_alpha: bool, diff --git a/src/error.rs b/src/error.rs index a049a4d..533d288 100644 --- a/src/error.rs +++ b/src/error.rs @@ -272,6 +272,11 @@ pub enum EncodingError { /// Returned by [`Encoder`](crate::Encoder) and [`encode()`](crate::encode()) when the format /// does not support encoding. UnsupportedFormat(Format), + /// Returned when the format requires the image size to be a multiple of + /// certain dimensions, but the provided image does not satisfy this. + /// + /// The two `NonZeroU32` values specify the required width and height + /// multiples respectively. InvalidSize(NonZeroU32, NonZeroU32), /// Returned by [`Encoder`](crate::Encoder) when the user tries to write a surface diff --git a/src/format.rs b/src/format.rs index c0918b2..c47dfc0 100644 --- a/src/format.rs +++ b/src/format.rs @@ -49,7 +49,7 @@ pub enum Format { Y410, Y416, - // sub-sampled formats + // subsampled formats R1_UNORM, R8G8_B8G8_UNORM, G8R8_G8B8_UNORM, @@ -147,13 +147,13 @@ impl Format { } /// Returns the format of a surface from a DXGI format. /// - /// `None` if the DXGI format is not supported for decoding. + /// `None` if the DXGI format is not supported for decoding/encoding. pub const fn from_dxgi(dxgi: DxgiFormat) -> Option { detect::dxgi_format_to_supported(dxgi) } /// Returns the format of a surface from a FourCC code. /// - /// `None` if the FourCC code is not supported for decoding. + /// `None` if the FourCC code is not supported for decoding/encoding. pub const fn from_four_cc(four_cc: FourCC) -> Option { detect::four_cc_to_supported(four_cc) } @@ -240,7 +240,7 @@ impl TryFrom for DxgiFormat { Format::Y410 => DxgiFormat::Y410, Format::Y416 => DxgiFormat::Y416, - // sub-sampled + // subsampled Format::R1_UNORM => DxgiFormat::R1_UNORM, Format::R8G8_B8G8_UNORM => DxgiFormat::R8G8_B8G8_UNORM, Format::G8R8_G8B8_UNORM => DxgiFormat::G8R8_G8B8_UNORM, diff --git a/src/header.rs b/src/header.rs index 18664c9..13c7733 100644 --- a/src/header.rs +++ b/src/header.rs @@ -8,7 +8,7 @@ //! //! [`RawHeader`] is a low-level representation of an unparsed DDS header. It is //! bit-for-bit what is on disk. You rarely need to interact with this type, but -//! it can useful for manually detecting and parsing non-standard DDS files. +//! it can be useful for manually detecting and parsing non-standard DDS files. //! //! # Creating a header //! @@ -420,7 +420,7 @@ pub struct ParseOptions { /// DDS files typically start with the magic bytes `"DDS "`. By default, the /// decoder will check for these bytes and error if they are not present. /// - /// If this is set to `true`, the decoder assume that the magic bytes are + /// If this is set to `true`, the decoder assumes that the magic bytes are /// not present and immediately start reading the header. This can be used /// to read DDS files without magic bytes. /// @@ -1871,7 +1871,7 @@ impl TryFrom for DxgiFormat { type Error = u32; fn try_from(value: u32) -> Result { - // NOTE: This implementation is NOT generated by the marco for + // NOTE: This implementation is NOT generated by the macro for // performance and code size reasons. On virtually any optimization // level, the below code translates to around 6 instructions, while a // generated match arm (0 | 1 | 2 | ... | 115 | 130 | 131 | 132 => ...) diff --git a/src/iter.rs b/src/iter.rs index 0212277..92ccf15 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -1,5 +1,11 @@ use crate::{DataLayout, DataRegion, Size, SurfaceDescriptor, Texture, Volume}; +/// Information about the surface to be read or written. +/// +/// ## See also +/// +/// - [`Decoder::surface_info`](crate::Decoder::surface_info) +/// - [`Encoder::surface_info`](crate::Encoder::surface_info) #[derive(Debug, Clone, Copy)] pub struct SurfaceInfo<'a> { size: Size, @@ -27,7 +33,7 @@ impl SurfaceInfo<'_> { self.len } - /// Whether this surface is has a mipmapping level greater than 0. + /// Whether this surface has a mipmap level greater than 0. /// /// For textures and texture arrays, this means that the texture is not /// a level 0 texture. For volumes, this means that the surface is not a diff --git a/src/layout.rs b/src/layout.rs index 710ffdf..cd52024 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -9,16 +9,18 @@ use crate::{ LayoutError, PixelInfo, Size, }; +/// An object or collection of objects in the data section of a DDS file. pub trait DataRegion { /// The number of bytes this object occupies in the data section of a DDS file. /// - /// It is guaranteed that `self.offset() + self.len() <= u64::MAX`. + /// It is guaranteed that `self.data_offset() + self.data_len() <= u64::MAX`. + /// See [`DataRegion::data_end()`]. fn data_len(&self) -> u64; /// The byte offset of this object in the data section of a DDS file. fn data_offset(&self) -> u64; /// The byte offset of the byte after this object in the data section of a DDS file. /// - /// This is equivalent to `self.offset() + self.len()`. + /// This is equivalent to `self.data_offset() + self.data_len()`. fn data_end(&self) -> u64 { self.data_offset() + self.data_len() } @@ -396,6 +398,7 @@ impl DataRegion for Volume { } } +/// Describes what kind of elements the texture array contains. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum TextureArrayKind { /// An array of textures. @@ -589,7 +592,7 @@ pub enum DataLayout { /// } /// ``` Volume(Volume), - /// A simply array of 2D textures. + /// A simple array of 2D textures. /// /// All textures within the array have the same size, mipmap count, and /// pixel format. diff --git a/src/lib.rs b/src/lib.rs index 5e5c2bd..867d981 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,6 +152,11 @@ //! to get periodic updates on the encoding progress. See the [`Progress`] type //! for more details. //! +//! #### Cancellation +//! +//! The encoder supports cancelling the encoding operation using a +//! [`CancellationToken`] and [`Progress::with_cancellation()`]. +//! //! ### Low-level API //! //! Besides the `Encoder` and `Decoder` types, the library also exposes a low-level diff --git a/src/pixel.rs b/src/pixel.rs index 7ff636e..324924e 100644 --- a/src/pixel.rs +++ b/src/pixel.rs @@ -9,7 +9,7 @@ use crate::{util::div_ceil, Format, FormatError, Size}; /// - simple uncompressed (but quantized) formats like `R8G8B8A8_UNORM` and /// `B5G6R5_UNORM`, /// - block-compressed formats like `BC1_UNORM` (DXT1), -/// - chroma sub-sampled formats like `NV12` which store the luma and chroma in +/// - chroma subsampled formats like `NV12` which store the luma and chroma in /// different planes, /// - and more. /// @@ -18,9 +18,10 @@ use crate::{util::div_ceil, Format, FormatError, Size}; /// /// ## Unsupported pixel formats /// -/// Note that [`PixelInfo`] can describe pixel formats are **not** supported for -/// decoding. This is by design to allow users to get the data layout for DDS -/// files this library doesn't fully support. +/// [`PixelInfo`] **can** describe pixel formats **not** supported for +/// de-/encoding. This is by design to enable the creation of +/// [`DataLayout`](crate::DataLayout)s for DDS files this library doesn't fully +/// support. #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum PixelInfo { /// Each pixel has a fixed number of bytes, regardless of the dimensions of @@ -28,20 +29,25 @@ pub enum PixelInfo { /// /// This is only the case for uncompressed image formats. E.g. /// `R8G8B8A8_UNORM`. - Fixed { bytes_per_pixel: u8 }, + Fixed { + /// The number of bytes per pixel. + /// + /// This is typically between 1 and 16. + bytes_per_pixel: u8, + }, /// Pixels are grouped into blocks of constant byte size. /// - /// This is used for block-compressed and channel-packed sub-sampled pixel + /// This is used for block-compressed and channel-packed subsampled pixel /// formats. E.g. `BC1_UNORM` (`DXT1`) has 8 bytes per 4x4 block, and /// `R8G8B8G8_UNORM` has 4 bytes per pair (2x1 block). Block(BlockPixelInfo), - /// Pixels are stored as sub-sampled YUV (or YCbCr) samples in separate + /// Pixels are stored as subsampled YUV (or YCbCr) samples in separate /// planes. /// - /// Separate planes means that the Y and U/V components for one pixel are + /// Separate planes mean that the Y and U/V components for one pixel are /// stored in separate arrays. One example of this is the /// [`NV12` format](https://learn.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#nv12). - /// This an 8-bit YUV 4:2:0 (meaning that U and V are sub-sampled to half + /// This an 8-bit YUV 4:2:0 (meaning that U and V are subsampled to half /// width and height) with the following memory layout: /// /// ```text @@ -72,22 +78,33 @@ pub struct BlockPixelInfo { } impl BlockPixelInfo { const fn new(bytes_per_block: u8, block_size: (u8, u8)) -> Self { + debug_assert!(block_size.0 > 0 && block_size.1 > 0); + Self { bytes_per_block, size: pack_2_u4(block_size), } } + /// Returns the number of bytes per block. + /// + /// Note: Partial blocks (e.g. at the edges of a surface) still occupy the + /// full number of bytes. pub const fn bytes_per_block(&self) -> u8 { self.bytes_per_block } /// Returns the `(width, height)` of a block. + /// + /// Both components are guaranteed to be non-zero. pub const fn size(&self) -> (u8, u8) { unpack_2_u4(self.size) } /// Returns the number of pixels in a block. + /// + /// This is guaranteed to be non-zero. pub const fn pixels(&self) -> u8 { let (x, y) = self.size(); + debug_assert!(x > 0 && y > 0); x * y } } @@ -103,35 +120,69 @@ impl BiPlanarPixelInfo { plane2_bytes_per_sample: u8, plane2_sub_sampling: (u8, u8), ) -> Self { + debug_assert!(plane2_sub_sampling.0 > 0 && plane2_sub_sampling.1 > 0); + Self { bytes: pack_2_u4((plane1_bytes_per_pixel, plane2_bytes_per_sample)), plane2_sub_sampling: pack_2_u4(plane2_sub_sampling), } } + /// The number of bytes per pixel in plane 1 (typically the luma plane). pub const fn plane1_bytes_per_pixel(&self) -> u8 { unpack_2_u4(self.bytes).0 } + /// The number of bytes per (subsampled) sample in plane 2 (typically the + /// chroma plane). + /// + /// The chroma plane typically contains the U and V (or Cb and Cr) channels. + /// U and V combined are considered one sample. E.g. if U and V are 1 byte + /// each, plane 2 is considered to be 2 bytes per sample. pub const fn plane2_bytes_per_sample(&self) -> u8 { unpack_2_u4(self.bytes).1 } + /// The subsampling factor of plane 2. + /// + /// Subsampling factors are in the order X,Y (horizontal,vertical) and are + /// guaranteed to be non-zero. pub const fn plane2_sub_sampling(&self) -> (u8, u8) { unpack_2_u4(self.plane2_sub_sampling) } } impl PixelInfo { + /// Creates a new [`PixelInfo::Fixed`]. pub const fn fixed(bytes_per_pixel: u8) -> Self { Self::Fixed { bytes_per_pixel } } + /// Creates a new [`PixelInfo::Block`]. + /// + /// ## Panics + /// + /// Panics if `block_size` components are 0 or >= 16. pub const fn block(bytes_per_block: u8, block_size: (u8, u8)) -> Self { + assert!(block_size.0 > 0 && block_size.1 > 0); + assert!(block_size.0 < 16 && block_size.1 < 16); + Self::Block(BlockPixelInfo::new(bytes_per_block, block_size)) } + /// Creates a new [`PixelInfo::BiPlanar`]. + /// + /// ## Panics + /// + /// Panics if: + /// + /// 1. `bytes_per_pixel` or `bytes_per_sample` are >= 16. + /// 2. `sub_sampling` components are 0 or >= 16. pub const fn bi_planar( bytes_per_pixel: u8, bytes_per_sample: u8, sub_sampling: (u8, u8), ) -> Self { + assert!(bytes_per_pixel < 16 && bytes_per_sample < 16); + assert!(sub_sampling.0 > 0 && sub_sampling.1 > 0); + assert!(sub_sampling.0 < 16 && sub_sampling.1 < 16); + Self::BiPlanar(BiPlanarPixelInfo::new( bytes_per_pixel, bytes_per_sample, @@ -139,6 +190,7 @@ impl PixelInfo { )) } + /// Detects the pixel format from a DDS header. pub fn from_header(header: &Header) -> Result { match header { Header::Dx9(dx9) => match &dx9.pixel_format { @@ -246,7 +298,7 @@ impl From for PixelInfo { // 3 bytes per pixel F::R8G8B8_UNORM | F::B8G8R8_UNORM => Self::fixed(3), - // sub-sampled formats + // subsampled formats // 4 bytes per one 2x1 block F::UYVY => Self::block(4, (2, 1)), @@ -277,7 +329,7 @@ impl TryFrom for PixelInfo { match value { // Fixed - // 1 bytes per pixel + // 1 byte per pixel F::R8_TYPELESS | F::R8_UNORM | F::R8_UINT | F::R8_SNORM | F::R8_SINT | F::A8_UNORM => { Ok(Self::fixed(1)) } @@ -361,7 +413,7 @@ impl TryFrom for PixelInfo { | F::R32G32B32A32_UINT | F::R32G32B32A32_SINT => Ok(Self::fixed(16)), - // Sub-sampled 2x1 + // Subsampled 2x1 F::R8G8_B8G8_UNORM | F::G8R8_G8B8_UNORM => Ok(Self::block(4, (2, 1))), // YUV 4:2:2 formats // https://learn.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#yuy2 diff --git a/src/progress.rs b/src/progress.rs index e5288ed..94986be 100644 --- a/src/progress.rs +++ b/src/progress.rs @@ -58,7 +58,7 @@ impl Default for ProgressRange { /// [`encode()`](crate::encode()). /// /// This structure is just a wrapper around a function that handles progress -/// reports. A progress report is a single `f32` value between 0 to 1 +/// reports. A progress report is a single `f32` value between 0 and 1 /// representing the percentage of the task that has been completed. /// /// Encoders will generally try to make 10 to 50 progress reports per second. @@ -69,7 +69,7 @@ impl Default for ProgressRange { /// has been reported, the next report may be 40% again, 42%, or similar, but /// never 39% or lower. In particular, there may be multiple reports for 100%. /// -/// ## Multi-threaded progress reporting +/// ## Multithreaded progress reporting /// /// Encoding may happen in parallel across multiple threads. As such, progress /// reports may come from multiple threads at the same time. @@ -101,7 +101,7 @@ pub struct Progress<'a> { impl<'a> Progress<'a> { /// Creates a new progress reporter. /// - /// This reporter supports multi-threaded progress reporting. See the + /// This reporter supports multithreaded progress reporting. See the /// documentation of [`Progress`] for more details. pub fn new(reporter: &'a mut F) -> Self { Self { @@ -112,7 +112,7 @@ impl<'a> Progress<'a> { } /// Creates a new progress reporter. /// - /// This reporter does **not** support multi-threaded progress reporting. + /// This reporter does **not** support multithreaded progress reporting. /// See the documentation of [`Progress`] for more details. pub fn new_single_threaded(reporter: &'a mut F) -> Self { Self { @@ -160,6 +160,7 @@ impl<'a> Progress<'a> { /// Returns whether the operation has been cancelled. /// /// If no [`CancellationToken`] was set, this will always return `false`. + /// If a token was set, this will return [`CancellationToken::is_cancelled`]. pub fn is_cancelled(&self) -> bool { if let Some(cancel) = &self.cancel { cancel.is_cancelled() @@ -219,6 +220,11 @@ impl<'a> Progress<'a> { /// same cancellation state. Cancelling one token will cancel all clones and /// vice versa. This behavior can be used to cancel multiple operations at /// once. +/// +/// ## See also +/// +/// - [`Progress::with_cancellation()`] +/// - [`Progress::is_cancelled()`] pub struct CancellationToken { cancelled: Arc, } diff --git a/src/split.rs b/src/split.rs index cb6ebb1..6cd4b26 100644 --- a/src/split.rs +++ b/src/split.rs @@ -6,15 +6,14 @@ use crate::{util, Dithering, EncodeOptions, Format, ImageView, Offset, Size}; /// /// ## Purpose /// -/// The main use case of this type is to allow end users to implement custom -/// concurrent/parallel encoding schemes. The parallel encoding implemented by +/// The primary purpose of this type is to enable the creation of custom +/// concurrent or parallel encoding schemes. The parallel encoding implemented by /// [`encode`](crate::encode()) may not fit every use case, so this type can be -/// used to split a single [`ImageView`] into multiple fragments that can be -/// encoded independently. +/// used to encode fragments of an image independently of each other. /// -/// Note that split views depend on the [`Format`] and [`EncodeOptions`] that -/// are used to create them. The encoding fragments with different formats -/// or options may yield unexpected results. +/// Note: Split views are specific to the [`Format`] and [`EncodeOptions`] used +/// to create them. Encoding fragments with different formats or options may +/// yield unexpected results. pub struct SplitView<'a> { image: ImageView<'a>, len: u32, @@ -54,6 +53,8 @@ impl<'a> SplitView<'a> { self.len } + /// Returns the fragment at the given index, or `None` if the index is out + /// of bounds. pub fn get(&self, index: u32) -> Option> { if index >= self.len { return None;