Skip to main content

lepton_jpeg/
lib.rs

1/*---------------------------------------------------------------------------------------------
2 *  Copyright (c) Microsoft Corporation. All rights reserved.
3 *  Licensed under the Apache License, Version 2.0. See LICENSE.txt in the project root for license information.
4 *  This software incorporates material from third parties. See NOTICE.txt for details.
5 *--------------------------------------------------------------------------------------------*/
6
7//! A lossless JPEG compressor with precise bit-for-bit recovery, supporting both baseline and progressive JPEGs.
8//! Achieves compression savings of around 22%, making it suitable for cold cloud storage use cases.
9//!
10//! This crate is a Rust port of Dropbox’s original [lepton](https://github.com/dropbox/lepton) JPEG compression tool.
11//! It retains the performance characteristics of the C++ version while benefiting from Rust’s memory safety guarantees.
12//! All JPEG content—including metadata and even malformed segments—is preserved accurately.
13//!
14//! The original C++ codebase has been deprecated by Dropbox. This Rust implementation incorporates
15//! an exhaustive security review of the original, making it a safer and more maintainable alternative.
16
17// Don't allow any unsafe code by default. Since this code has to potentially deal with
18// badly/maliciously formatted images, we want this extra level of safety.
19#![forbid(unsafe_code)]
20#![forbid(trivial_casts)]
21#![forbid(trivial_numeric_casts)]
22#![forbid(non_ascii_idents)]
23#![forbid(unused_extern_crates)]
24#![forbid(unused_import_braces)]
25#![forbid(redundant_lifetimes)]
26#![forbid(single_use_lifetimes)]
27#![forbid(unused_extern_crates)]
28#![forbid(unused_lifetimes)]
29#![forbid(unused_macro_rules)]
30#![forbid(macro_use_extern_crate)]
31#![forbid(missing_unsafe_on_extern)]
32#![deny(missing_docs)]
33
34mod consts;
35mod helpers;
36mod jpeg;
37mod metrics;
38mod structs;
39
40mod enabled_features;
41mod lepton_error;
42
43pub use enabled_features::EnabledFeatures;
44pub use helpers::catch_unwind_result;
45pub use lepton_error::{ExitCode, LeptonError};
46pub use metrics::{CpuTimeMeasure, Metrics};
47pub use structs::lepton_file_writer::get_git_version;
48
49use crate::lepton_error::{AddContext, Result};
50pub use crate::structs::simple_threadpool::{
51    DEFAULT_THREAD_POOL, LeptonThreadPool, LeptonThreadPriority, SimpleThreadPool,
52    SingleThreadPool, ThreadPoolHolder,
53};
54
55#[cfg(feature = "micro_benchmark")]
56/// Module that exposes internal functions for micro benchmarking
57pub mod micro_benchmark;
58
59/// Trait for types that can provide the current position in a stream. This
60/// is intentionally a subset of the Seek trait, as it only requires remembering
61/// the current position without allowing seeking to arbitrary positions.
62///
63/// This is useful for callers for which it would be complex to provide seek capabilities, but can
64/// count the number of bytes read or written so far.
65///
66/// We provide a blanket implementation for any type that implements `std::io::Seek`.
67pub trait StreamPosition {
68    /// Returns the current position in the stream.
69    fn position(&mut self) -> u64;
70}
71
72impl<T: std::io::Seek> StreamPosition for T {
73    fn position(&mut self) -> u64 {
74        self.stream_position().unwrap()
75    }
76}
77
78pub use structs::lepton_file_reader::decode_lepton;
79
80pub use structs::lepton_file_writer::{encode_lepton, encode_lepton_verify};
81
82static PACKAGE_VERSION: &str = env!("CARGO_PKG_VERSION");
83
84pub use structs::lepton_file_reader::LeptonFileReader;
85
86/// Returns the version string of the library, which includes the package version and the git version.
87/// This is useful for debugging and logging purposes to know the exact version of the library is being used
88pub fn get_version_string() -> String {
89    format!("{}-{}", PACKAGE_VERSION, get_git_version())
90}
91
92/// used by utility to dump out the contents of a jpeg file or lepton file for debugging purposes
93#[allow(dead_code)]
94pub fn dump_jpeg(input_data: &[u8], all: bool, enabled_features: &EnabledFeatures) -> Result<()> {
95    use std::io::Cursor;
96    use structs::lepton_file_reader::decode_lepton_file_image;
97    use structs::lepton_file_writer::read_jpeg;
98
99    let mut lh;
100    let block_image;
101
102    if input_data[0] == 0xff && input_data[1] == 0xd8 {
103        let mut reader = Cursor::new(input_data);
104
105        (lh, block_image) = read_jpeg(&mut reader, enabled_features, |jh, _ri| {
106            println!("parsed header:");
107            let s = format!("{jh:?}");
108            println!("{0}", s.replace("},", "},\r\n").replace("],", "],\r\n"));
109        })?;
110    } else {
111        let mut reader = Cursor::new(input_data);
112
113        (lh, block_image) =
114            decode_lepton_file_image(&mut reader, enabled_features, &DEFAULT_THREAD_POOL)
115                .context()?;
116
117        loop {
118            println!("parsed header:");
119            let s = format!("{0:?}", lh.jpeg_header);
120            println!("{0}", s.replace("},", "},\r\n").replace("],", "],\r\n"));
121
122            if !lh
123                .advance_next_header_segment(&enabled_features)
124                .context()?
125            {
126                break;
127            }
128        }
129    }
130
131    let s = format!("{lh:?}");
132    println!("{0}", s.replace("},", "},\r\n").replace("],", "],\r\n"));
133
134    if all {
135        for i in 0..block_image.len() {
136            println!("Component {0}", i);
137            let image = &block_image[i];
138            for dpos in 0..image.get_block_width() * image.get_original_height() {
139                print!("dpos={0} ", dpos);
140                let block = image.get_block(dpos);
141
142                print!("{0}", block.get_transposed_from_zigzag(0));
143                for i in 1..64 {
144                    print!(",{0}", block.get_transposed_from_zigzag(i));
145                }
146                println!();
147            }
148        }
149    }
150
151    return Ok(());
152}