refactor: remove vec alloc in format function, extending out vec instead
This commit is contained in:
parent
8e79a7954a
commit
5b2d912cf8
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -744,6 +744,7 @@ dependencies = [
|
|||||||
name = "qoi2"
|
name = "qoi2"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"imageproc",
|
"imageproc",
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
|
|||||||
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.86"
|
||||||
bytemuck = "1.16.1"
|
bytemuck = "1.16.1"
|
||||||
imageproc = "0.25.0"
|
imageproc = "0.25.0"
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
use std::mem::discriminant;
|
use std::mem::discriminant;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use crate::common::*;
|
use crate::common::*;
|
||||||
|
|
||||||
|
// @TODO replace Options with custom Errors
|
||||||
|
|
||||||
impl Ops {
|
impl Ops {
|
||||||
// @TODO don't alloc here, get a mut reference and extend here
|
fn write_encoded (self, buf: &mut Vec<u8>) {
|
||||||
fn format (self) -> Vec<u8> {
|
|
||||||
// cast_diff
|
// cast_diff
|
||||||
let cd = |diff: i8| cast_with_bias(diff, 2);
|
let cd = |diff: i8| cast_with_bias(diff, 2);
|
||||||
// cast_luma_green
|
// cast_luma_green
|
||||||
@ -14,13 +15,13 @@ impl Ops {
|
|||||||
let clrb = |diff: i8| cast_with_bias(diff, 8);
|
let clrb = |diff: i8| cast_with_bias(diff, 8);
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Ops::Nop => vec![],
|
Ops::Nop => (),
|
||||||
Ops::Rgb([r, g, b]) => vec![254, r, g, b],
|
Ops::Rgb([r, g, b]) => buf.extend_from_slice(&[254, r, g, b]),
|
||||||
Ops::Rgba([r, g, b, a]) => vec![255, r, g, b, a],
|
Ops::Rgba([r, g, b, a]) => buf.extend_from_slice(&[255, r, g, b, a]),
|
||||||
Ops::Index(idx) => vec![idx as u8],
|
Ops::Index(idx) => buf.push(idx as u8),
|
||||||
Ops::Run(len) => vec![(3 << 6) | (len - 1)],
|
Ops::Run(len) => buf.push((3 << 6) | (len - 1)),
|
||||||
Ops::Diff([dr, dg, db]) => vec![(1 << 6) | ((cd(dr) << 4) | (cd(dg) << 2) | cd(db)) ],
|
Ops::Diff([dr, dg, db]) => buf.push((1 << 6) | ((cd(dr) << 4) | (cd(dg) << 2) | cd(db))),
|
||||||
Ops::Luma([dr, dg, db]) => vec![(2 << 6) | clg(dg), (clrb(dr) << 4) | clrb(db)],
|
Ops::Luma([dr, dg, db]) => buf.extend_from_slice(&[(2 << 6) | clg(dg), (clrb(dr) << 4) | clrb(db)]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,8 +58,9 @@ fn encode_body (header: Header, data: &[u8]) -> Option<Vec<u8>> {
|
|||||||
Ops::Run(run) if run < 62 => cur = Ops::Run(run + 1),
|
Ops::Run(run) if run < 62 => cur = Ops::Run(run + 1),
|
||||||
// if run is full, commit it to out vec, and start a new one
|
// if run is full, commit it to out vec, and start a new one
|
||||||
Ops::Run(run) if run >= 62 => {
|
Ops::Run(run) if run >= 62 => {
|
||||||
|
cur = Ops::Run(62); // clamp for safety;
|
||||||
|
cur.write_encoded(&mut out);
|
||||||
cur = Ops::Run(1);
|
cur = Ops::Run(1);
|
||||||
out.extend_from_slice(&Ops::Run(62).format());
|
|
||||||
},
|
},
|
||||||
// otherwise (default case, when encountering a match for the first time) start a run
|
// otherwise (default case, when encountering a match for the first time) start a run
|
||||||
_ => cur = Ops::Run(1),
|
_ => cur = Ops::Run(1),
|
||||||
@ -66,19 +68,19 @@ fn encode_body (header: Header, data: &[u8]) -> Option<Vec<u8>> {
|
|||||||
} else {
|
} else {
|
||||||
// if current Op is Run (meaning we need to and it since there's no match)
|
// if current Op is Run (meaning we need to and it since there's no match)
|
||||||
if discriminant(&cur) == discriminant(&Ops::Run(0)) {
|
if discriminant(&cur) == discriminant(&Ops::Run(0)) {
|
||||||
out.extend_from_slice(&cur.format());
|
cur.write_encoded(&mut out);
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash = hash(rgba);
|
let hash = hash(rgba);
|
||||||
// INDEX -> DIFF -> LUMA -> RGB(A)
|
// INDEX -> DIFF -> LUMA -> RGB(A)
|
||||||
if known[hash] == rgba {
|
if known[hash] == rgba {
|
||||||
cur = Ops::Index(hash);
|
cur = Ops::Index(hash);
|
||||||
} else if let Some(ops) = diff_ops([r, g, b, a], [last[0], last[1], last[2], last[3]]) {
|
} else if let Some(ops) = diff_ops([r, g, b, a], last) {
|
||||||
cur = ops;
|
cur = ops;
|
||||||
} else {
|
} else {
|
||||||
cur = header.channels.ops_color(&rgba[..header.channels.num()])?;
|
cur = header.channels.ops_color(&rgba[..header.channels.num()])?;
|
||||||
}
|
}
|
||||||
out.extend_from_slice(&cur.format());
|
cur.write_encoded(&mut out);
|
||||||
last = rgba;
|
last = rgba;
|
||||||
known[hash] = rgba;
|
known[hash] = rgba;
|
||||||
}
|
}
|
||||||
@ -86,7 +88,7 @@ fn encode_body (header: Header, data: &[u8]) -> Option<Vec<u8>> {
|
|||||||
|
|
||||||
// if an image buffer ends with a run, flush it as well
|
// if an image buffer ends with a run, flush it as well
|
||||||
if discriminant(&cur) == discriminant(&Ops::Run(0)) {
|
if discriminant(&cur) == discriminant(&Ops::Run(0)) {
|
||||||
out.extend_from_slice(&cur.format());
|
cur.write_encoded(&mut out);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(out)
|
Some(out)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user