#[rustfmt::skip]
pub const ZIGZAG: [usize; 64] = [
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63,
];
#[derive(Clone)]
pub struct HuffSpec {
pub class: u8,
pub id: u8,
pub counts: [u8; 16],
pub values: Vec<u8>,
}
impl HuffSpec {
pub fn single(class: u8, id: u8, value: u8, len: usize) -> HuffSpec {
assert!((1..=16).contains(&len));
let mut counts = [0u8; 16];
counts[len - 1] = 1;
HuffSpec {
class,
id,
counts,
values: vec![value],
}
}
}
#[derive(Clone, Copy)]
pub struct CompSpec {
pub id: u8,
pub h: u8,
pub v: u8,
pub quant_id: u8,
pub dc_id: u8,
pub ac_id: u8,
}
pub struct FlatJpeg {
pub width: u16,
pub height: u16,
pub sof_marker: u8,
pub precision: u8,
pub components: Vec<CompSpec>,
pub quant_ids: Vec<u8>,
pub huff: Vec<HuffSpec>,
pub dri: u16,
pub flat_code_len: usize,
pub sos_selectors: Option<Vec<u8>>,
}
impl FlatJpeg {
pub fn grayscale(width: u16, height: u16) -> FlatJpeg {
FlatJpeg {
width,
height,
sof_marker: 0xC0,
precision: 8,
components: vec![CompSpec {
id: 1,
h: 1,
v: 1,
quant_id: 0,
dc_id: 0,
ac_id: 0,
}],
quant_ids: vec![0],
huff: vec![
HuffSpec::single(0, 0, 0x00, 2),
HuffSpec::single(1, 0, 0x00, 2),
],
dri: 0,
flat_code_len: 2,
sos_selectors: None,
}
}
pub fn color444(width: u16, height: u16) -> FlatJpeg {
FlatJpeg {
width,
height,
sof_marker: 0xC0,
precision: 8,
components: vec![
CompSpec {
id: 1,
h: 1,
v: 1,
quant_id: 0,
dc_id: 0,
ac_id: 0,
},
CompSpec {
id: 2,
h: 1,
v: 1,
quant_id: 1,
dc_id: 1,
ac_id: 1,
},
CompSpec {
id: 3,
h: 1,
v: 1,
quant_id: 1,
dc_id: 1,
ac_id: 1,
},
],
quant_ids: vec![0, 1],
huff: vec![
HuffSpec::single(0, 0, 0x00, 2),
HuffSpec::single(1, 0, 0x00, 2),
HuffSpec::single(0, 1, 0x00, 2),
HuffSpec::single(1, 1, 0x00, 2),
],
dri: 0,
flat_code_len: 2,
sos_selectors: None,
}
}
pub fn with_flat_code_len(mut self, len: usize) -> FlatJpeg {
self.flat_code_len = len;
for h in &mut self.huff {
*h = HuffSpec::single(h.class, h.id, 0x00, len);
}
self
}
fn mcu_grid(&self) -> (usize, usize) {
let max_h = self.components.iter().map(|c| c.h).max().unwrap_or(1) as usize;
let max_v = self.components.iter().map(|c| c.v).max().unwrap_or(1) as usize;
let mx = (self.width as usize).div_ceil(8 * max_h);
let my = (self.height as usize).div_ceil(8 * max_v);
(mx, my)
}
fn blocks_per_mcu(&self) -> usize {
self.components
.iter()
.map(|c| c.h as usize * c.v as usize)
.sum()
}
fn entropy(&self) -> Vec<u8> {
let (mx, my) = self.mcu_grid();
let blocks = self.blocks_per_mcu();
let mut bw = BitWriter::new();
let mut rst = 0u8;
for mcu in 0..mx * my {
if self.dri > 0 && mcu > 0 && mcu % self.dri as usize == 0 {
bw.align_and_restart(rst);
rst = (rst + 1) & 7;
}
for _ in 0..blocks {
bw.zeros(self.flat_code_len); bw.zeros(self.flat_code_len); }
}
bw.finish()
}
pub fn build(&self) -> Vec<u8> {
let mut out = Vec::new();
out.extend_from_slice(&[0xFF, 0xD8]);
for &qid in &self.quant_ids {
let mut seg = vec![qid & 0x0F];
seg.extend(std::iter::repeat_n(1u8, 64));
push_segment(&mut out, 0xDB, &seg);
}
let mut sof = vec![self.precision];
sof.extend_from_slice(&self.height.to_be_bytes());
sof.extend_from_slice(&self.width.to_be_bytes());
sof.push(self.components.len() as u8);
for c in &self.components {
sof.push(c.id);
sof.push((c.h << 4) | (c.v & 0x0F));
sof.push(c.quant_id & 0x0F);
}
push_segment(&mut out, self.sof_marker, &sof);
for h in &self.huff {
let mut seg = vec![(h.class << 4) | (h.id & 0x0F)];
seg.extend_from_slice(&h.counts);
seg.extend_from_slice(&h.values);
push_segment(&mut out, 0xC4, &seg);
}
if self.dri > 0 {
push_segment(&mut out, 0xDD, &self.dri.to_be_bytes());
}
let selectors = self
.sos_selectors
.clone()
.unwrap_or_else(|| self.components.iter().map(|c| c.id).collect());
let mut sos = vec![self.components.len() as u8];
for (c, &sel) in self.components.iter().zip(&selectors) {
sos.push(sel);
sos.push((c.dc_id << 4) | (c.ac_id & 0x0F));
}
sos.extend_from_slice(&[0x00, 0x3F, 0x00]); push_segment(&mut out, 0xDA, &sos);
out.extend_from_slice(&self.entropy());
out.extend_from_slice(&[0xFF, 0xD9]);
out
}
}
struct BitWriter {
out: Vec<u8>,
cur: u32,
n: u32,
}
impl BitWriter {
fn new() -> BitWriter {
BitWriter {
out: Vec::new(),
cur: 0,
n: 0,
}
}
fn zeros(&mut self, count: usize) {
for _ in 0..count {
self.push_bit(0);
}
}
fn push_bit(&mut self, bit: u32) {
self.cur = (self.cur << 1) | (bit & 1);
self.n += 1;
if self.n == 8 {
self.emit_byte((self.cur & 0xFF) as u8);
self.cur = 0;
self.n = 0;
}
}
fn emit_byte(&mut self, b: u8) {
self.out.push(b);
if b == 0xFF {
self.out.push(0x00); }
}
fn align_and_restart(&mut self, n: u8) {
self.pad_ones();
self.out.push(0xFF);
self.out.push(0xD0 + (n & 7));
}
fn pad_ones(&mut self) {
if self.n > 0 {
while self.n != 0 {
self.push_bit(1);
}
}
}
fn finish(mut self) -> Vec<u8> {
self.pad_ones();
self.out
}
}
fn push_segment(out: &mut Vec<u8>, marker: u8, body: &[u8]) {
out.push(0xFF);
out.push(marker);
let len = (body.len() + 2) as u16;
out.extend_from_slice(&len.to_be_bytes());
out.extend_from_slice(body);
}