mirror of
https://github.com/lifegpc/libtlg-rs.git
synced 2026-06-06 13:59:11 +08:00
features(libtlg-rs): Add tlg6 decode support
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -156,10 +156,17 @@ version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libtlg-rs"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"overf",
|
||||
]
|
||||
|
||||
@@ -246,7 +253,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tlg"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libtlg-rs",
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
[package]
|
||||
name = "libtlg-rs"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
description = "Rust version of libtlg"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/lifegpc/libtlg-rs"
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1"
|
||||
overf = "0.1"
|
||||
|
||||
@@ -141,8 +141,174 @@ fn load_tlg5<T: Read + Seek>(src: &mut T) -> Result<Tlg> {
|
||||
})
|
||||
}
|
||||
|
||||
fn load_tlg6<T: Read + Seek>(_src: &mut T) -> Result<Tlg> {
|
||||
Err(TlgError::Str("TLG6 is not supported yet".to_string()))
|
||||
fn load_tlg6<T: Read + Seek>(src: &mut T) -> Result<Tlg> {
|
||||
let mut buf = [0u8; 4];
|
||||
src.read_exact(&mut buf)?;
|
||||
let colors = buf[0];
|
||||
let color_type = match colors {
|
||||
3 => TlgColorType::Bgr24,
|
||||
4 => TlgColorType::Bgra32,
|
||||
1 => TlgColorType::Grayscale8,
|
||||
_ => return Err(TlgError::UnsupportedColorType(colors)),
|
||||
};
|
||||
if buf[1] != 0 {
|
||||
return Err(TlgError::Str("Data flags must be 0".to_string()));
|
||||
}
|
||||
if buf[2] != 0 {
|
||||
return Err(TlgError::Str("Color types must be 0".to_string()));
|
||||
}
|
||||
if buf[3] != 0 {
|
||||
return Err(TlgError::Str(
|
||||
"External golomb bit length table is not yet supported.".to_string(),
|
||||
));
|
||||
}
|
||||
let width = src.read_u32()?;
|
||||
let height = src.read_u32()?;
|
||||
let max_bit_length = src.read_u32()?;
|
||||
let x_block_count = (width - 1) / (TLG6_W_BLOCK_SIZE as u32) + 1;
|
||||
let y_block_count = (height - 1) / (TLG6_H_BLOCK_SIZE as u32) + 1;
|
||||
let main_count = width / (TLG6_W_BLOCK_SIZE as u32);
|
||||
let fraction = width - main_count * TLG6_W_BLOCK_SIZE as u32;
|
||||
let mut bit_pool = vec![0u8; max_bit_length as usize / 8 + 5];
|
||||
let mut pixelbuf = vec![0u32; width as usize * TLG6_H_BLOCK_SIZE + 1];
|
||||
let mut filter_types = vec![0u8; x_block_count as usize * y_block_count as usize];
|
||||
let mut lzss_text = [0u8; 4096];
|
||||
let zero = if colors == 3 { 0xff_00_00_00u32 } else { 0 };
|
||||
let zeroline = vec![zero; width as usize];
|
||||
{
|
||||
let mut p = 0;
|
||||
let mut i = 0;
|
||||
while i < 0x20u8 {
|
||||
let mut j = 0;
|
||||
while j < 0x10u8 {
|
||||
lzss_text[p] = i;
|
||||
p += 1;
|
||||
lzss_text[p] = i;
|
||||
p += 1;
|
||||
lzss_text[p] = i;
|
||||
p += 1;
|
||||
lzss_text[p] = i;
|
||||
p += 1;
|
||||
lzss_text[p] = j;
|
||||
p += 1;
|
||||
lzss_text[p] = j;
|
||||
p += 1;
|
||||
lzss_text[p] = j;
|
||||
p += 1;
|
||||
lzss_text[p] = j;
|
||||
p += 1;
|
||||
j += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
{
|
||||
let inbuf_size = src.read_u32()? as usize;
|
||||
let mut inbuf = vec![0u8; inbuf_size];
|
||||
src.read_exact(&mut inbuf)?;
|
||||
tlg5_decompress_slide(&mut filter_types, &inbuf, inbuf_size, &mut lzss_text, 0);
|
||||
}
|
||||
let mut prevline = zeroline;
|
||||
let mut outbuf = vec![0u32; width as usize * height as usize];
|
||||
for y in (0..height).step_by(TLG6_H_BLOCK_SIZE) {
|
||||
let y_lim = (y + TLG6_H_BLOCK_SIZE as u32).min(height);
|
||||
let pixel_count = (y_lim - y) as usize * width as usize;
|
||||
for c in 0..colors {
|
||||
let mut bit_length = src.read_u32()?;
|
||||
let method = (bit_length >> 30) & 3;
|
||||
bit_length &= 0x3fff_ffff;
|
||||
let byte_length = (bit_length + 7) / 8;
|
||||
if byte_length as usize >= bit_pool.len() {
|
||||
return Err(TlgError::Str(
|
||||
"Bit pool is too small for the given bit length".to_string(),
|
||||
));
|
||||
}
|
||||
src.read_exact(&mut bit_pool[..byte_length as usize])?;
|
||||
match method {
|
||||
0 => {
|
||||
tlg6_decode_golomb_values(
|
||||
&mut pixelbuf,
|
||||
pixel_count,
|
||||
&bit_pool,
|
||||
c == 0 && colors != 1,
|
||||
c,
|
||||
)?;
|
||||
}
|
||||
_ => return Err(TlgError::UnsupportedCompressedMethod(method as u8)),
|
||||
}
|
||||
}
|
||||
let ft = &filter_types[(y as usize / TLG6_H_BLOCK_SIZE) * x_block_count as usize..];
|
||||
let skip_bytes = (y_lim - y) as usize * TLG6_W_BLOCK_SIZE;
|
||||
for yy in y..y_lim {
|
||||
let curline =
|
||||
&mut outbuf[(yy as usize * width as usize)..(yy as usize + 1) * width as usize];
|
||||
let dir = (yy & 1) ^ 1 != 0;
|
||||
let oddskip = ((y_lim - yy - 1) as isize) - (yy - y) as isize;
|
||||
if main_count != 0 {
|
||||
let start = TLG6_W_BLOCK_SIZE.min(width as usize) * (yy - y) as usize;
|
||||
tlg6_decode_line(
|
||||
&prevline,
|
||||
curline,
|
||||
width,
|
||||
0,
|
||||
main_count as usize,
|
||||
ft,
|
||||
skip_bytes,
|
||||
&pixelbuf,
|
||||
start,
|
||||
zero,
|
||||
oddskip,
|
||||
dir,
|
||||
)?;
|
||||
}
|
||||
if main_count != x_block_count {
|
||||
let ww = TLG6_W_BLOCK_SIZE.min(fraction as usize);
|
||||
let start = ww * (yy - y) as usize;
|
||||
tlg6_decode_line(
|
||||
&prevline,
|
||||
curline,
|
||||
width,
|
||||
main_count as usize,
|
||||
x_block_count as usize,
|
||||
ft,
|
||||
skip_bytes,
|
||||
&pixelbuf,
|
||||
start,
|
||||
zero,
|
||||
oddskip,
|
||||
dir,
|
||||
)?;
|
||||
}
|
||||
prevline = curline.to_vec();
|
||||
}
|
||||
}
|
||||
let mut data = Vec::with_capacity(outbuf.len() * colors as usize);
|
||||
for p in outbuf {
|
||||
let t = p.to_le_bytes();
|
||||
let b = t[0];
|
||||
let g = t[1];
|
||||
let r = t[2];
|
||||
let a = t[3];
|
||||
match color_type {
|
||||
TlgColorType::Bgr24 => {
|
||||
data.extend_from_slice(&[b, g, r]);
|
||||
}
|
||||
TlgColorType::Bgra32 => {
|
||||
data.extend_from_slice(&[b, g, r, a]);
|
||||
}
|
||||
TlgColorType::Grayscale8 => {
|
||||
data.extend_from_slice(&[b]);
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(Tlg {
|
||||
tags: Default::default(),
|
||||
version: 6,
|
||||
width,
|
||||
height,
|
||||
color: color_type,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
fn internal_load_tlg<T: Read + Seek>(src: &mut T) -> Result<Tlg> {
|
||||
|
||||
@@ -1,5 +1,59 @@
|
||||
use crate::*;
|
||||
use overf::wrapping;
|
||||
|
||||
const TLG6_GOLOMB_N_COUNT: usize = 4;
|
||||
const TLG6_LEADING_ZERO_TABLE_BITS: usize = 12;
|
||||
const TLG6_LEADING_ZERO_TABLE_SIZE: usize = 1 << TLG6_LEADING_ZERO_TABLE_BITS;
|
||||
const TLG6_GOLOMB_COMPRESSED: [[u16; 9]; TLG6_GOLOMB_N_COUNT] = [
|
||||
[3, 7, 15, 27, 63, 108, 223, 448, 130],
|
||||
[3, 5, 13, 24, 51, 95, 192, 384, 257],
|
||||
[2, 5, 12, 21, 39, 86, 155, 320, 384],
|
||||
[2, 3, 9, 18, 33, 61, 129, 258, 511],
|
||||
];
|
||||
const TLG6_GLOBMB_TABLE_SIZE: usize = TLG6_GOLOMB_N_COUNT * 2 * 128;
|
||||
pub const TLG6_W_BLOCK_SIZE: usize = 8;
|
||||
pub const TLG6_H_BLOCK_SIZE: usize = 8;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref TLG6_LEADING_ZERO_TABLE: [u8; TLG6_LEADING_ZERO_TABLE_SIZE] =
|
||||
tlg6_init_leading_zero_table();
|
||||
static ref TLG6_GOLOMB_BIT_LENGTH_TABLE: [[i8; TLG6_GOLOMB_N_COUNT]; TLG6_GLOBMB_TABLE_SIZE] =
|
||||
tlg6_init_golomb_table();
|
||||
}
|
||||
|
||||
fn tlg6_init_leading_zero_table() -> [u8; TLG6_LEADING_ZERO_TABLE_SIZE] {
|
||||
let mut table = [0; TLG6_LEADING_ZERO_TABLE_SIZE];
|
||||
for i in 0..TLG6_LEADING_ZERO_TABLE_SIZE {
|
||||
let mut cnt = 0;
|
||||
let mut j = 1;
|
||||
while j != TLG6_LEADING_ZERO_TABLE_SIZE && i & j == 0 {
|
||||
j <<= 1;
|
||||
cnt += 1;
|
||||
}
|
||||
cnt += 1;
|
||||
if j == TLG6_LEADING_ZERO_TABLE_SIZE {
|
||||
cnt = 0;
|
||||
}
|
||||
table[i] = cnt as u8;
|
||||
}
|
||||
table
|
||||
}
|
||||
|
||||
fn tlg6_init_golomb_table() -> [[i8; TLG6_GOLOMB_N_COUNT]; TLG6_GLOBMB_TABLE_SIZE] {
|
||||
let mut table = [[0; TLG6_GOLOMB_N_COUNT]; TLG6_GLOBMB_TABLE_SIZE];
|
||||
for n in 0..TLG6_GOLOMB_N_COUNT {
|
||||
let mut a = 0;
|
||||
for i in 0..9 {
|
||||
for _ in 0..TLG6_GOLOMB_COMPRESSED[n][i] {
|
||||
table[a][n] = i as i8;
|
||||
a += 1;
|
||||
}
|
||||
}
|
||||
debug_assert!(a == TLG6_GLOBMB_TABLE_SIZE);
|
||||
}
|
||||
table
|
||||
}
|
||||
|
||||
pub fn tlg5_compose_colors3(outp: &mut [u8], upper: &[u8], buf: &[&[u8]], width: u32) {
|
||||
let mut outpos = 0usize;
|
||||
let mut upper_pos = 0usize;
|
||||
@@ -120,3 +174,425 @@ pub fn tlg5_decompress_slide(
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
pub fn tlg6_fetch_32bits(data: &[u8], loc: usize) -> Result<u32> {
|
||||
if data.len() < loc + 4 {
|
||||
return Err(TlgError::IndexOutOfRange);
|
||||
}
|
||||
Ok(u32::from_le_bytes([
|
||||
data[loc],
|
||||
data[loc + 1],
|
||||
data[loc + 2],
|
||||
data[loc + 3],
|
||||
]))
|
||||
}
|
||||
|
||||
pub fn tlg6_decode_golomb_values(
|
||||
pixelbuf: &mut [u32],
|
||||
pixel_count: usize,
|
||||
bit_pool: &[u8],
|
||||
is_first: bool,
|
||||
c: u8,
|
||||
) -> Result<()> {
|
||||
let mut n = TLG6_GOLOMB_N_COUNT - 1;
|
||||
let mut a = 0;
|
||||
let mut bit_pos = 1;
|
||||
let mut zero = if bit_pool[0] & 1 != 0 { 0u8 } else { 1 };
|
||||
let mut index = 0;
|
||||
let mut bit_pool_index = 0;
|
||||
while index < pixel_count {
|
||||
let mut count;
|
||||
{
|
||||
let mut t = tlg6_fetch_32bits(bit_pool, bit_pool_index)? >> bit_pos;
|
||||
let mut b = TLG6_LEADING_ZERO_TABLE[(t as usize) & (TLG6_LEADING_ZERO_TABLE_SIZE - 1)];
|
||||
let mut bit_count = b as i32;
|
||||
while b == 0 {
|
||||
bit_count += TLG6_LEADING_ZERO_TABLE_BITS as i32;
|
||||
bit_pos += TLG6_LEADING_ZERO_TABLE_BITS as i32;
|
||||
bit_pool_index += bit_pos as usize >> 3;
|
||||
bit_pos &= 7;
|
||||
t = tlg6_fetch_32bits(bit_pool, bit_pool_index)? >> bit_pos;
|
||||
b = TLG6_LEADING_ZERO_TABLE[(t as usize) & (TLG6_LEADING_ZERO_TABLE_SIZE - 1)];
|
||||
bit_count += b as i32;
|
||||
}
|
||||
bit_pos += b as i32;
|
||||
bit_pool_index += bit_pos as usize >> 3;
|
||||
bit_pos &= 7;
|
||||
bit_count -= 1;
|
||||
count = 1 << bit_count;
|
||||
count += (tlg6_fetch_32bits(bit_pool, bit_pool_index)? >> bit_pos) & (count - 1);
|
||||
bit_pos += bit_count;
|
||||
bit_pool_index += bit_pos as usize >> 3;
|
||||
bit_pos &= 7;
|
||||
}
|
||||
if zero != 0 {
|
||||
loop {
|
||||
if is_first {
|
||||
pixelbuf[index] = 0;
|
||||
} else {
|
||||
let mut tmp = pixelbuf[index].to_le_bytes();
|
||||
tmp[c as usize] = 0;
|
||||
pixelbuf[index] = u32::from_le_bytes(tmp);
|
||||
}
|
||||
index += 1;
|
||||
count -= 1;
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
zero ^= 1;
|
||||
} else {
|
||||
loop {
|
||||
let k = TLG6_GOLOMB_BIT_LENGTH_TABLE[a][n];
|
||||
let mut t = tlg6_fetch_32bits(bit_pool, bit_pool_index)? >> bit_pos;
|
||||
let mut bit_count;
|
||||
let mut b;
|
||||
let mut v;
|
||||
let sign;
|
||||
if t != 0 {
|
||||
b = TLG6_LEADING_ZERO_TABLE[(t as usize) & (TLG6_LEADING_ZERO_TABLE_SIZE - 1)];
|
||||
bit_count = b as i32;
|
||||
while b == 0 {
|
||||
bit_count += TLG6_LEADING_ZERO_TABLE_BITS as i32;
|
||||
bit_pos += TLG6_LEADING_ZERO_TABLE_BITS as i32;
|
||||
bit_pool_index += bit_pos as usize >> 3;
|
||||
bit_pos &= 7;
|
||||
t = tlg6_fetch_32bits(bit_pool, bit_pool_index)? >> bit_pos;
|
||||
b = TLG6_LEADING_ZERO_TABLE
|
||||
[(t as usize) & (TLG6_LEADING_ZERO_TABLE_SIZE - 1)];
|
||||
bit_count += b as i32;
|
||||
}
|
||||
bit_count -= 1;
|
||||
} else {
|
||||
bit_pool_index += 5;
|
||||
bit_count = if bit_pool_index == 0 {
|
||||
return Err(TlgError::IndexOutOfRange);
|
||||
} else {
|
||||
bit_pool[bit_pool_index - 1] as i32
|
||||
};
|
||||
bit_pos = 0;
|
||||
t = tlg6_fetch_32bits(bit_pool, bit_pool_index)?;
|
||||
b = 0;
|
||||
}
|
||||
v = (bit_count << k) + ((t as i32 >> b) & ((1 << k) - 1));
|
||||
sign = (v & 1) - 1;
|
||||
v >>= 1;
|
||||
a += v as usize;
|
||||
if is_first {
|
||||
pixelbuf[index] = (wrapping!((v ^ sign) + sign + 1) as u32) & 0xFF;
|
||||
} else {
|
||||
let mut tmp = pixelbuf[index].to_le_bytes();
|
||||
tmp[c as usize] = wrapping!((v ^ sign) + sign + 1) as u8;
|
||||
pixelbuf[index] = u32::from_le_bytes(tmp);
|
||||
}
|
||||
index += 1;
|
||||
bit_pos += b as i32 + k as i32;
|
||||
bit_pool_index += bit_pos as usize >> 3;
|
||||
bit_pos &= 7;
|
||||
if n == 0 {
|
||||
n = TLG6_GOLOMB_N_COUNT - 1;
|
||||
a >>= 1;
|
||||
} else {
|
||||
n -= 1;
|
||||
}
|
||||
count -= 1;
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
zero ^= 1;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn make_gt_mask(a: u32, b: u32) -> u32 {
|
||||
let tmp2 = !b;
|
||||
let tmp = wrapping! {((a & tmp2) + (((a ^ tmp2) >> 1) & 0x7f7f7f7f) ) & 0x80808080};
|
||||
wrapping! { ((tmp >> 7) + 0x7f7f7f7f) ^ 0x7f7f7f7f }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn packed_bytes_add(a: u32, b: u32) -> u32 {
|
||||
let tmp = wrapping! {(((a & b) << 1) + ((a ^ b) & 0xfefefefe) ) & 0x01010100};
|
||||
wrapping!(a + b - tmp)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn med2(a: u32, b: u32, c: u32) -> u32 {
|
||||
let aa_gt_bb = make_gt_mask(a, b);
|
||||
let a_xor_b_and_aa_gt_bb = (a ^ b) & aa_gt_bb;
|
||||
let aa = a_xor_b_and_aa_gt_bb ^ a;
|
||||
let bb = a_xor_b_and_aa_gt_bb ^ b;
|
||||
let n = make_gt_mask(c, bb);
|
||||
let nn = make_gt_mask(aa, c);
|
||||
let m = !(n | nn);
|
||||
wrapping! {
|
||||
(n & aa) | (nn & bb) | ((bb & m) - (c & m) + (aa & m))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn med(a: u32, b: u32, c: u32, v: u32) -> u32 {
|
||||
packed_bytes_add(med2(a, b, c), v)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn avg_packed(x: u32, y: u32) -> u32 {
|
||||
wrapping!(((x) & (y)) + ((((x) ^ (y)) & 0xfefefefe) >> 1)) + (((x) ^ (y)) & 0x01010101)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn avg(a: u32, b: u32, v: u32) -> u32 {
|
||||
packed_bytes_add(avg_packed(a, b), v)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cal_v(b: u8, g: u8, r: u8, a: u8) -> u32 {
|
||||
(0xff0000 & ((r as u32) << 16))
|
||||
+ (0xff00 & ((g as u32) << 8))
|
||||
+ (0xff & (b as u32))
|
||||
+ ((a as u32) << 24)
|
||||
}
|
||||
|
||||
pub fn tlg6_decode_line(
|
||||
prevline: &[u32],
|
||||
curline: &mut [u32],
|
||||
width: u32,
|
||||
start_block: usize,
|
||||
block_limit: usize,
|
||||
filter_types: &[u8],
|
||||
skipblockbytes: usize,
|
||||
inp: &[u32],
|
||||
mut inp_pos: usize,
|
||||
initialp: u32,
|
||||
oddskip: isize,
|
||||
dir: bool,
|
||||
) -> Result<()> {
|
||||
let mut p;
|
||||
let mut up;
|
||||
let step: i32;
|
||||
let mut prevline_pos = 0;
|
||||
let mut curline_pos = 0;
|
||||
if start_block != 0 {
|
||||
prevline_pos += start_block * TLG6_W_BLOCK_SIZE;
|
||||
curline_pos += start_block * TLG6_W_BLOCK_SIZE;
|
||||
p = curline[curline_pos - 1];
|
||||
up = prevline[prevline_pos - 1];
|
||||
} else {
|
||||
p = initialp;
|
||||
up = initialp;
|
||||
}
|
||||
inp_pos += skipblockbytes * start_block;
|
||||
step = if dir { 1 } else { -1 };
|
||||
for i in start_block..block_limit {
|
||||
let mut w = (width as usize - i * TLG6_W_BLOCK_SIZE).min(TLG6_W_BLOCK_SIZE);
|
||||
let ww = w;
|
||||
if step == -1 {
|
||||
inp_pos += ww - 1;
|
||||
}
|
||||
if i & 1 != 0 {
|
||||
inp_pos = (inp_pos as isize + oddskip as isize * ww as isize) as usize;
|
||||
}
|
||||
loop {
|
||||
let inpt = inp[inp_pos];
|
||||
let ia = ((inpt >> 24) & 0xFF) as u8;
|
||||
let ir = ((inpt >> 16) & 0xFF) as u8;
|
||||
let ig = ((inpt >> 8) & 0xFF) as u8;
|
||||
let ib = (inpt & 0xFF) as u8;
|
||||
let u = prevline[prevline_pos];
|
||||
p = match filter_types[i] {
|
||||
0 => med(p, u, up, cal_v(ib, ig, ir, ia)),
|
||||
1 => avg(p, u, cal_v(ib, ig, ir, ia)),
|
||||
2 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(wrapping!(ib + ig), ig, wrapping!(ir + ig), ia),
|
||||
),
|
||||
3 => avg(p, u, cal_v(wrapping!(ib + ig), ig, wrapping!(ir + ig), ia)),
|
||||
4 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(ib, wrapping!(ig + ib), wrapping!(ir + ib + ig), ia),
|
||||
),
|
||||
5 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(ib, wrapping!(ig + ib), wrapping!(ir + ib + ig), ia),
|
||||
),
|
||||
6 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(wrapping!(ib + ir + ig), wrapping!(ig + ir), ir, ia),
|
||||
),
|
||||
7 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(wrapping!(ib + ir + ig), wrapping!(ig + ir), ir, ia),
|
||||
),
|
||||
8 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(
|
||||
wrapping!(ib + ir),
|
||||
wrapping!(ig + ib + ir),
|
||||
wrapping!(ir + ib + ir + ig),
|
||||
ia,
|
||||
),
|
||||
),
|
||||
9 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(
|
||||
wrapping!(ib + ir),
|
||||
wrapping!(ig + ib + ir),
|
||||
wrapping!(ir + ib + ir + ig),
|
||||
ia,
|
||||
),
|
||||
),
|
||||
10 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(wrapping!(ib + ir), wrapping!(ig + ib + ir), ir, ia),
|
||||
),
|
||||
11 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(wrapping!(ib + ir), wrapping!(ig + ib + ir), ir, ia),
|
||||
),
|
||||
12 => med(p, u, up, cal_v(wrapping!(ib + ig), ig, ir, ia)),
|
||||
13 => avg(p, u, cal_v(wrapping!(ib + ig), ig, ir, ia)),
|
||||
14 => med(p, u, up, cal_v(ib, wrapping!(ig + ib), ir, ia)),
|
||||
15 => avg(p, u, cal_v(ib, wrapping!(ig + ib), ir, ia)),
|
||||
16 => med(p, u, up, cal_v(ib, ig, wrapping!(ir + ig), ia)),
|
||||
17 => avg(p, u, cal_v(ib, ig, wrapping!(ir + ig), ia)),
|
||||
18 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(
|
||||
wrapping!(ib + ig + ir + ib),
|
||||
wrapping!(ig + ir + ib),
|
||||
wrapping!(ir + ib),
|
||||
ia,
|
||||
),
|
||||
),
|
||||
19 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(
|
||||
wrapping!(ib + ig + ir + ib),
|
||||
wrapping!(ig + ir + ib),
|
||||
wrapping!(ir + ib),
|
||||
ia,
|
||||
),
|
||||
),
|
||||
20 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(wrapping!(ib + ir), wrapping!(ig + ir), ir, ia),
|
||||
),
|
||||
21 => avg(p, u, cal_v(wrapping!(ib + ir), wrapping!(ig + ir), ir, ia)),
|
||||
22 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(ib, wrapping!(ig + ib), wrapping!(ir + ib), ia),
|
||||
),
|
||||
23 => avg(p, u, cal_v(ib, wrapping!(ig + ib), wrapping!(ir + ib), ia)),
|
||||
24 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(ib, wrapping!(ig + ir + ib), wrapping!(ir + ib), ia),
|
||||
),
|
||||
25 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(ib, wrapping!(ig + ir + ib), wrapping!(ir + ib), ia),
|
||||
),
|
||||
26 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(
|
||||
wrapping!(ib + ig),
|
||||
wrapping!(ig + ir + ib + ig),
|
||||
wrapping!(ir + ib + ig),
|
||||
ia,
|
||||
),
|
||||
),
|
||||
27 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(
|
||||
wrapping!(ib + ig),
|
||||
wrapping!(ig + ir + ib + ig),
|
||||
wrapping!(ir + ib + ig),
|
||||
ia,
|
||||
),
|
||||
),
|
||||
28 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(
|
||||
wrapping!(ib + ig + ir),
|
||||
wrapping!(ig + ir),
|
||||
wrapping!(ir + ib + ig + ir),
|
||||
ia,
|
||||
),
|
||||
),
|
||||
29 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(
|
||||
wrapping!(ib + ig + ir),
|
||||
wrapping!(ig + ir),
|
||||
wrapping!(ir + ib + ig + ir),
|
||||
ia,
|
||||
),
|
||||
),
|
||||
30 => med(
|
||||
p,
|
||||
u,
|
||||
up,
|
||||
cal_v(ib, wrapping!(ig + (ib << 1)), wrapping!(ir + (ib << 1)), ia),
|
||||
),
|
||||
31 => avg(
|
||||
p,
|
||||
u,
|
||||
cal_v(ib, wrapping!(ig + (ib << 1)), wrapping!(ir + (ib << 1)), ia),
|
||||
),
|
||||
v => {
|
||||
return Err(TlgError::Str(format!("Unsupported filter type: {}", v)));
|
||||
}
|
||||
};
|
||||
up = u;
|
||||
curline[curline_pos] = p;
|
||||
curline_pos += 1;
|
||||
prevline_pos += 1;
|
||||
inp_pos = (inp_pos as isize + step as isize) as usize;
|
||||
w -= 1;
|
||||
if w == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if step == 1 {
|
||||
inp_pos += skipblockbytes - ww;
|
||||
} else {
|
||||
inp_pos += skipblockbytes + 1;
|
||||
}
|
||||
if i & 1 != 0 {
|
||||
inp_pos = (inp_pos as isize - oddskip as isize * ww as isize) as usize;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ pub enum TlgError {
|
||||
InvalidFormat,
|
||||
/// Unsupported color type
|
||||
UnsupportedColorType(u8),
|
||||
/// Index out of range error
|
||||
IndexOutOfRange,
|
||||
/// Unsupported compressed method
|
||||
UnsupportedCompressedMethod(u8),
|
||||
/// String type error
|
||||
Str(String),
|
||||
}
|
||||
@@ -47,6 +51,10 @@ impl std::fmt::Display for TlgError {
|
||||
TlgError::Io(e) => write!(f, "IO Error: {}", e),
|
||||
TlgError::InvalidFormat => write!(f, "Invalid TLG format"),
|
||||
TlgError::UnsupportedColorType(c) => write!(f, "Unsupported color type: {}", c),
|
||||
TlgError::IndexOutOfRange => write!(f, "Index out of range"),
|
||||
TlgError::UnsupportedCompressedMethod(m) => {
|
||||
write!(f, "Unsupported compressed method: {}", m)
|
||||
}
|
||||
TlgError::Str(s) => write!(f, "{}", s),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tlg"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
description = "Tools to process TLG image file."
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
|
||||
Reference in New Issue
Block a user