|
| 1 | +//! # DDS |
| 2 | +//! |
| 3 | +//! A Rust library for decoding and encoding DDS (DirectDraw Surface) files. |
| 4 | +//! |
| 5 | +//! ## The DDS format |
| 6 | +//! |
| 7 | +//! DDS is a container format for storing compressed and uncompressed textures, |
| 8 | +//! cube maps, volumes, buffers, and arrays of the before. It is used by |
| 9 | +//! DirectX, OpenGL, Vulkan, and other graphics APIs. |
| 10 | +//! |
| 11 | +//! A DDS files has 2 parts: a header and a data section. The header describes |
| 12 | +//! the type of data in the file (e.g. a BC1-compressed 100x200px texture) and |
| 13 | +//! determines the layout of the data section. The data section then contains |
| 14 | +//! the binary pixel data. |
| 15 | +//! |
| 16 | +//! ## Features |
| 17 | +//! |
| 18 | +//! - `rayon` (default): Parallel encoding using the `rayon` crate. |
| 19 | +//! |
| 20 | +//! This feature will enable parallel encoding of DDS files. Both the |
| 21 | +//! high-level [`Encoder`] and low-level [`encode()`] functions will use this |
| 22 | +//! feature to speed up processing. |
| 23 | +//! |
| 24 | +//! All features marked with "(default)" are enabled by default. |
| 25 | +//! |
| 26 | +//! ## Usage |
| 27 | +//! |
| 28 | +//! ### Decoding |
| 29 | +//! |
| 30 | +//! The [`Decoder`] type is the high-level interface for decoding DDS files. |
| 31 | +//! |
| 32 | +//! The most common case, a single image, can be decoded as follows: |
| 33 | +//! |
| 34 | +//! ```no_run |
| 35 | +//! # use dds::*; |
| 36 | +//! # use std::fs::File; |
| 37 | +//! let file = File::open("path/to/file.dds").unwrap(); |
| 38 | +//! let mut decoder = Decoder::new(file).unwrap(); |
| 39 | +//! // make sure the file is a single image |
| 40 | +//! assert!(decoder.layout().texture().is_some()); |
| 41 | +//! // prepare a buffer to decode into |
| 42 | +//! let mut data = vec![0u8; decoder.main_size().pixels() as usize * 4]; |
| 43 | +//! // create an image view from the buffer |
| 44 | +//! let view = ImageViewMut::new(&mut data, decoder.main_size(), ColorFormat::RGBA_U8).unwrap(); |
| 45 | +//! // decode the image into the buffer |
| 46 | +//! decoder.read_surface(view).unwrap(); |
| 47 | +//! ``` |
| 48 | +//! |
| 49 | +//! Cube maps can be detected using `decoder.layout().is_cube_map()` and decoded |
| 50 | +//! with [`Decoder::read_cube_map`]. |
| 51 | +//! |
| 52 | +//! Volumes have to be read one depth slice at a time using [`Decoder::read_surface`]. |
| 53 | +//! |
| 54 | +//! It is also possible to decode a rectangle of a surface using |
| 55 | +//! [`Decoder::read_surface_rect`]. |
| 56 | +//! |
| 57 | +//! ### Encoding |
| 58 | +//! |
| 59 | +//! Since the data of a DDS file is determined by the header, the first step to |
| 60 | +//! encoding a DDS file is to create a header. See the documentation of |
| 61 | +//! the [`crate::header`] module for more details. |
| 62 | +//! |
| 63 | +//! ```no_run |
| 64 | +//! # use dds::{*, header::*}; |
| 65 | +//! # use std::fs::File; |
| 66 | +//! fn save_rgba_image( |
| 67 | +//! file: &mut File, |
| 68 | +//! image_data: &[u8], |
| 69 | +//! width: u32, |
| 70 | +//! height: u32, |
| 71 | +//! ) -> Result<(), EncodingError> { |
| 72 | +//! let format = Format::BC1_UNORM; |
| 73 | +//! let header = Header::new_image(width, height, format); |
| 74 | +//! |
| 75 | +//! let mut encoder = Encoder::new(file, format, &header)?; |
| 76 | +//! encoder.options.quality = CompressionQuality::Fast; |
| 77 | +//! |
| 78 | +//! let view = ImageView::new(image_data, Size::new(width, height), ColorFormat::RGBA_U8) |
| 79 | +//! .expect("invalid image data"); |
| 80 | +//! encoder.write_surface(view)?; |
| 81 | +//! encoder.finish()?; |
| 82 | +//! Ok(()) |
| 83 | +//! } |
| 84 | +//! ``` |
| 85 | +//! |
| 86 | +//! Note the use of [`Encoder::finish()`]. This method will verify that the |
| 87 | +//! file contains all necessary data. |
| 88 | +//! |
| 89 | +//! To create DDS files with mipmaps, use [`Encoder::write_surface_with`]: |
| 90 | +//! |
| 91 | +//! ```no_run |
| 92 | +//! # use dds::{*, header::*}; |
| 93 | +//! # use std::fs::File; |
| 94 | +//! fn save_rgba_image_with_mipmaps( |
| 95 | +//! file: &mut File, |
| 96 | +//! image_data: &[u8], |
| 97 | +//! width: u32, |
| 98 | +//! height: u32, |
| 99 | +//! ) -> Result<(), EncodingError> { |
| 100 | +//! let format = Format::BC1_UNORM; |
| 101 | +//! let header = Header::new_image(width, height, format).with_mipmaps(); |
| 102 | +//! |
| 103 | +//! let mut encoder = Encoder::new(file, format, &header)?; |
| 104 | +//! encoder.options.quality = CompressionQuality::Fast; |
| 105 | +//! |
| 106 | +//! let view = ImageView::new(image_data, Size::new(width, height), ColorFormat::RGBA_U8) |
| 107 | +//! .expect("invalid image data"); |
| 108 | +//! let write_options = WriteOptions { |
| 109 | +//! generate_mipmaps: true, |
| 110 | +//! ..Default::default() |
| 111 | +//! }; |
| 112 | +//! encoder.write_surface_with(view, None, &write_options)?; |
| 113 | +//! encoder.finish()?; |
| 114 | +//! Ok(()) |
| 115 | +//! } |
| 116 | +//! ``` |
| 117 | +//! |
| 118 | +//! Cube maps can be created by encoding their 6 faces in the order: |
| 119 | +//! +X -X +Y -Y +Z -Z. |
| 120 | +//! |
| 121 | +//! Volumes have to be encoded one depth slice at a time using [`Encoder::write_surface`]. |
| 122 | +//! |
| 123 | +//! ### Progress reporting |
| 124 | +//! |
| 125 | +//! The decoder is generally so fast that progress reporting is not needed. |
| 126 | +//! |
| 127 | +//! The encoder, however, can take a long time to encode large images. Use the |
| 128 | +//! `progress` parameter of the [`Encoder::write_surface_with`] method to get |
| 129 | +//! periodic updates on the encoding progress. See the [`Progress`] type for |
| 130 | +//! more details. |
| 131 | +//! |
| 132 | +//! ### Low-level API |
| 133 | +//! |
| 134 | +//! Besides the `Encoder` and `Decoder` types, the library also exposes a low-level |
| 135 | +//! API for encoding and decoding DDS surfaces. It should generally not be |
| 136 | +//! necessary to use this API. |
| 137 | +//! |
| 138 | +//! The [`encode()`] and [`decode()`] functions are used to encode and decode a |
| 139 | +//! single DDS surface. The [`SplitSurface`] type can be used to split a surface |
| 140 | +//! into multiple fragments for parallel encoding. |
| 141 | +
|
1 | 142 | #![forbid(unsafe_code)] |
2 | 143 |
|
3 | 144 | mod cast; |
|
0 commit comments