mirror of
https://github.com/bend-n/fimg.git
synced 2024-12-22 02:28:19 -06:00
detection of color count
This commit is contained in:
parent
3bc1dd6c07
commit
ae82460a8f
|
@ -26,6 +26,7 @@ minifb = { version = "0.25.0", default-features = false, features = [
|
|||
wgpu = { version = "0.19.1", default-features = false, optional = true }
|
||||
atools = "0.1.0"
|
||||
qwant = { version = "1.0.0", optional = true }
|
||||
libc = "0.2.153"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { version = "0.53.0", features = [
|
||||
|
@ -67,7 +68,7 @@ text = ["fontdue"]
|
|||
blur = ["slur"]
|
||||
term = ["qwant", "save", "scale", "windows"]
|
||||
real-show = ["minifb", "text"]
|
||||
default = ["save", "scale"]
|
||||
default = ["save", "scale", "term"]
|
||||
wgpu-convert = ["dep:wgpu"]
|
||||
|
||||
[profile.release]
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
const_option,
|
||||
array_chunks,
|
||||
let_chains,
|
||||
try_blocks,
|
||||
test
|
||||
)]
|
||||
#![warn(
|
||||
|
|
116
src/term.rs
116
src/term.rs
|
@ -114,55 +114,8 @@ where
|
|||
#[cfg(unix)]
|
||||
// https://github.com/benjajaja/ratatui-image/blob/master/src/picker.rs#L226
|
||||
fn guess_harder(&self, to: &mut impl Write) -> Option<Result> {
|
||||
extern crate libc;
|
||||
use std::{io::Read, mem::MaybeUninit};
|
||||
|
||||
fn r(result: i32) -> Option<()> {
|
||||
(result != -1).then_some(())
|
||||
}
|
||||
|
||||
let mut termios = MaybeUninit::<libc::termios>::uninit();
|
||||
// SAFETY: get termios of stdin
|
||||
r(unsafe { libc::tcgetattr(0, termios.as_mut_ptr()) })?;
|
||||
// SAFETY: gotten
|
||||
let termios = unsafe { termios.assume_init() };
|
||||
|
||||
// SAFETY: turn off echo and canonical (requires enter before stdin reads) modes
|
||||
unsafe {
|
||||
libc::tcsetattr(
|
||||
0,
|
||||
libc::TCSADRAIN,
|
||||
&libc::termios {
|
||||
c_lflag: termios.c_lflag & !libc::ICANON & !libc::ECHO,
|
||||
..termios
|
||||
},
|
||||
)
|
||||
};
|
||||
let buf = {
|
||||
// contains a kitty gfx and sixel query, the `\x1b[c` is for sixels
|
||||
println!(r"_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\[c");
|
||||
let mut stdin = std::io::stdin();
|
||||
let mut buf = String::new();
|
||||
|
||||
let mut b = [0; 16];
|
||||
'l: loop {
|
||||
let n = stdin.read(&mut b).ok()?;
|
||||
if n == 0 {
|
||||
continue;
|
||||
}
|
||||
for b in b {
|
||||
buf.push(b as char);
|
||||
if b == b'c' {
|
||||
break 'l;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf
|
||||
};
|
||||
|
||||
// SAFETY: reset attrs to what they were before we became nosy
|
||||
unsafe { libc::tcsetattr(0, libc::TCSADRAIN, &termios) };
|
||||
|
||||
// contains a kitty gfx and sixel query, the `\x1b[c` is for sixels
|
||||
let buf = query(r"_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\[c")?;
|
||||
if buf.contains("_Gi=31;OK") {
|
||||
Some(Kitty(self.as_ref()).write(to))
|
||||
} else if buf.contains(";4;")
|
||||
|
@ -176,3 +129,68 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
// https://github.com/benjajaja/ratatui-image/blob/master/src/picker.rs#L226
|
||||
fn query(device_query_code: &'static str) -> Option<String> {
|
||||
extern crate libc;
|
||||
use std::mem::MaybeUninit;
|
||||
fn r(result: i32) -> Option<()> {
|
||||
(result != -1).then_some(())
|
||||
}
|
||||
|
||||
let mut termios = MaybeUninit::<libc::termios>::uninit();
|
||||
// SAFETY: get termios of stdin
|
||||
r(unsafe { libc::tcgetattr(0, termios.as_mut_ptr()) })?;
|
||||
// SAFETY: gotten
|
||||
let termios = unsafe { termios.assume_init() };
|
||||
|
||||
// SAFETY: turn off echo and canonical (requires enter before stdin reads) modes
|
||||
unsafe {
|
||||
libc::tcsetattr(
|
||||
0,
|
||||
libc::TCSADRAIN,
|
||||
&libc::termios {
|
||||
c_lflag: termios.c_lflag & !libc::ICANON & !libc::ECHO,
|
||||
..termios
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
let buf = try {
|
||||
// SAFETY: linux time out'd reading
|
||||
unsafe {
|
||||
println!("{device_query_code}");
|
||||
let mut buf = Vec::new();
|
||||
let mut tmp = [0; 1 << 5];
|
||||
loop {
|
||||
let mut x = std::mem::zeroed::<libc::fd_set>();
|
||||
libc::FD_SET(0, &mut x);
|
||||
match libc::select(
|
||||
1,
|
||||
&mut x,
|
||||
0 as _,
|
||||
0 as _,
|
||||
&mut libc::timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 5e5 as _,
|
||||
},
|
||||
) {
|
||||
0 => break,
|
||||
-1 => return None,
|
||||
_ => {}
|
||||
}
|
||||
match libc::read(libc::STDIN_FILENO, tmp.as_mut_ptr().cast(), tmp.len()) {
|
||||
0 => continue,
|
||||
-1 => return None,
|
||||
n => buf.extend_from_slice(&tmp[..n as _]),
|
||||
}
|
||||
}
|
||||
String::from_utf8(buf).ok()?
|
||||
}
|
||||
};
|
||||
|
||||
// SAFETY: reset attrs to what they were before we became nosy
|
||||
unsafe { libc::tcsetattr(0, libc::TCSADRAIN, &termios) };
|
||||
buf
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ where
|
|||
LaneCount<N>: SupportedLaneCount,
|
||||
{
|
||||
fn cas<U>(self) -> U {
|
||||
assert!(std::mem::size_of::<U>() == std::mem::size_of::<Simd<T, N>>());
|
||||
assert!(std::mem::size_of::<U>() == std::mem::size_of::<Self>());
|
||||
unsafe { transmute_unchecked(self) }
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ where
|
|||
LaneCount<N>: SupportedLaneCount,
|
||||
{
|
||||
fn cas<U>(self) -> U {
|
||||
assert!(std::mem::size_of::<U>() == std::mem::size_of::<Mask<T, N>>());
|
||||
assert!(std::mem::size_of::<U>() == std::mem::size_of::<Self>());
|
||||
unsafe { transmute_unchecked(self) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,34 @@ impl<T: AsRef<[u8]>, const N: usize> Sixel<T, N> {
|
|||
where
|
||||
[(); N]: Basic,
|
||||
{
|
||||
#[cfg(unix)]
|
||||
let q = {
|
||||
extern crate libc;
|
||||
// SAFETY: is stdout a tty
|
||||
(unsafe { libc::isatty(0) } == 1)
|
||||
};
|
||||
#[cfg(not(unix))]
|
||||
let q = true;
|
||||
let colors = q
|
||||
.then_some(super::query("[?1;1;0S").and_then(|x| {
|
||||
// [?1;0;65536S
|
||||
if let [b'?', b'1', b';', b'0', b';', n @ ..] = x.as_bytes() {
|
||||
Some(
|
||||
n.iter()
|
||||
.copied()
|
||||
.take_while(u8::is_ascii_digit)
|
||||
.fold(0u16, |acc, x| {
|
||||
acc.saturating_mul(10).saturating_add((x - b'0') as u16)
|
||||
})
|
||||
.max(64)
|
||||
.min(0xfff),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}))
|
||||
.flatten()
|
||||
.unwrap_or(255);
|
||||
to.write_str("Pq")?;
|
||||
write!(to, r#""1;1;{};{}"#, self.width(), self.height())?;
|
||||
let buf;
|
||||
|
@ -63,14 +91,15 @@ impl<T: AsRef<[u8]>, const N: usize> Sixel<T, N> {
|
|||
&*buf
|
||||
};
|
||||
|
||||
let q = qwant::NeuQuant::new(15, 255, rgba);
|
||||
let q = qwant::NeuQuant::new(15, colors as _, rgba);
|
||||
|
||||
// TODO: don't colllect
|
||||
let pixels: Vec<u8> = rgba.iter().map(|&pix| q.index_of(pix) as u8).collect();
|
||||
let pixels: Vec<u16> = rgba.iter().map(|&pix| q.index_of(pix) as _).collect();
|
||||
|
||||
for ([r, g, b], i) in q
|
||||
.color_map_rgb()
|
||||
.map(|x| x.map(|x| (x as f32 * (100. / 255.)) as u32))
|
||||
.zip(0u8..)
|
||||
.zip(0u64..)
|
||||
{
|
||||
write!(to, "#{i};2;{r};{g};{b}")?;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue