diff --git a/.gitignore b/.gitignore index d373bb5..5e9f178 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ Cargo.lock # Ignore images *.png *.dpf +*.sqp *.raw *.rgba *.jpg diff --git a/src/compression/dct.rs b/src/compression/dct.rs index 260e004..1072539 100644 --- a/src/compression/dct.rs +++ b/src/compression/dct.rs @@ -98,7 +98,7 @@ pub fn idct(input: &[f32], width: usize, height: usize) -> Vec { /// JPEG 8x8 Base Quantization Matrix for a quality level of 50. /// -/// Instead of using this, utilize the [`quantization_matrix`] function to +/// Instead of using this, use the [`quantization_matrix`] function to /// get a quantization matrix corresponding to the image quality value. const BASE_QUANTIZATION_MATRIX: [u16; 64] = [ 16, 11, 10, 16, 24, 40, 51, 61, @@ -221,7 +221,7 @@ pub fn dct_decompress(input: &[i16], parameters: DctParameters) -> Vec { let row_offset = row_num * parameters.width; - let offset = if start_x + 8 >= parameters.width { + let offset = if start_x + 8 > parameters.width { parameters.width % 8 } else { 8 diff --git a/src/lib.rs b/src/lib.rs index 59c3fca..afd64f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,52 @@ -//! SQP (SQuishy Picture Format) is an image format. It can be used to store -//! image data in lossless or lossy compressed form. +//! SQP (**SQ**uishy **P**icture Format) is an image format. It can be used to store +//! image data in lossless or lossy compressed form. It is designed to be +//! relatively simple compared to other more standard formats. +//! +//! This image format is mainly for experimentation and learning about +//! compression. While it can be used, there are no guarantees about stability, +//! breaking changes, or features. +//! +//! If you're looking for an image format to use, you might want to consider +//! using a more standard one such as those supported by the +//! [image crate](https://docs.rs/image/latest/image/). +//! +//! # Example +//! ## Creating and writing an SQP +//! ```no_run +//! use sqp::{SquishyPicture, ColorFormat}; +//! +//! let width = 2; +//! let height = 2; +//! let bitmap = vec![ +//! 255, 255, 255, 255, 0, 255, 0, 128, +//! 255, 255, 255, 255, 0, 255, 0, 128 +//! ]; +//! +//! // Create a 2×2 image in memory. Nothing is compressed or encoded +//! // at this point. +//! let sqp_image = SquishyPicture::from_raw_lossless( +//! width, +//! height, +//! ColorFormat::Rgba8, +//! bitmap +//! ); +//! +//! // Write it out to a file. This performs compression and encoding. +//! sqp_image.save("my_image.sqp").expect("Could not save the image"); +//! ``` +//! +//! ## Reading an SQP from a file. +//! ```no_run +//! use std::fs::File; +//! use sqp::SquishyPicture; +//! +//! // Load it directly with the `open` function... +//! let image = sqp::open("my_image.sqp").expect("Could not open file"); +//! +//! // ...or from something implementing Read. +//! let input_file = File::open("my_image.sqp").expect("Could not open image file"); +//! let image2 = SquishyPicture::decode(&input_file); +//! ``` mod compression { pub mod dct; @@ -10,3 +57,18 @@ mod operations; pub mod picture; pub mod header; + +// ----------------------- // +// INLINED USEFUL FEATURES // +// ----------------------- // +#[doc(inline)] +pub use picture::SquishyPicture; + +#[doc(inline)] +pub use header::ColorFormat; + +#[doc(inline)] +pub use header::CompressionType; + +#[doc(inline)] +pub use picture::open; diff --git a/src/picture.rs b/src/picture.rs index 197e22c..4f952d9 100644 --- a/src/picture.rs +++ b/src/picture.rs @@ -1,4 +1,6 @@ -use std::{fs::File, io::{self, BufWriter, Read, Write}}; +//! Functions and other utilities surrounding the [`SquishyPicture`] type. + +use std::{fs::File, io::{self, BufWriter, Read, Write}, path::Path}; use byteorder::{ReadBytesExt, WriteBytesExt}; use integer_encoding::VarInt; @@ -11,11 +13,6 @@ use crate::{ operations::{diff_line, line_diff}, }; -pub struct DangoPicture { - pub header: Header, - pub bitmap: Vec, -} - #[derive(Error, Debug)] pub enum Error { #[error("incorrect identifier, got {0:02X?}")] @@ -28,7 +25,13 @@ pub enum Error { CompressionError(#[from] CompressionError), } -impl DangoPicture { +/// The basic Squishy Picture type for manipulation in-memory. +pub struct SquishyPicture { + pub header: Header, + pub bitmap: Vec, +} + +impl SquishyPicture { /// Create a DPF from raw bytes in a particular [`ColorFormat`]. /// /// The quality parameter does nothing if the compression type is not @@ -36,7 +39,7 @@ impl DangoPicture { /// /// # Example /// ```ignore - /// let dpf_lossy = DangoPicture::from_raw( + /// let dpf_lossy = SquishyPicture::from_raw( /// input.width(), /// input.height(), /// ColorFormat::Rgba32, @@ -72,13 +75,13 @@ impl DangoPicture { color_format, }; - DangoPicture { + Self { header, bitmap, } } - /// Convenience method over [`DangoPicture::from_raw`] which creates a + /// Convenience method over [`SquishyPicture::from_raw`] which creates a /// lossy image with a given quality. pub fn from_raw_lossy( width: u32, @@ -97,7 +100,8 @@ impl DangoPicture { ) } - + /// Convenience method over [`SquishyPicture::from_raw`] which creates a + /// lossless image. pub fn from_raw_lossless( width: u32, height: u32, @@ -114,8 +118,9 @@ impl DangoPicture { ) } - /// Encode the image into anything that implements [Write]. Returns the - /// number of bytes written. + /// Encode the image into anything that implements [`Write`]. + /// + /// Returns the number of bytes written. pub fn encode(&self, mut output: O) -> Result { let mut count = 0; @@ -146,6 +151,9 @@ impl DangoPicture { }, }; + let mut inspection_file = File::create("raw_data").unwrap(); + inspection_file.write_all(&modified_data).unwrap(); + // Compress the final image data using the basic LZW scheme let (compressed_data, compression_info) = compress(modified_data)?; @@ -168,8 +176,8 @@ impl DangoPicture { Ok(()) } - /// Decode the image from anything that implements [Read] - pub fn decode(mut input: I) -> Result { + /// Decode the image from anything that implements [`Read`] + pub fn decode(mut input: I) -> Result { let header = Header::read_from(&mut input)?; let compression_info = CompressionInfo::read_from(&mut input); @@ -194,7 +202,7 @@ impl DangoPicture { }, }; - Ok(DangoPicture { header, bitmap }) + Ok(Self { header, bitmap }) } } @@ -209,3 +217,9 @@ fn decode_varint_stream(stream: &[u8]) -> Vec { output } + +pub fn open>(path: P) -> Result { + let input = File::open(path)?; + + Ok(SquishyPicture::decode(input)?) +}