mirror of
https://github.com/bend-n/fimg.git
synced 2024-12-22 10:28:21 -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 }
|
wgpu = { version = "0.19.1", default-features = false, optional = true }
|
||||||
atools = "0.1.0"
|
atools = "0.1.0"
|
||||||
qwant = { version = "1.0.0", optional = true }
|
qwant = { version = "1.0.0", optional = true }
|
||||||
|
libc = "0.2.153"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
windows = { version = "0.53.0", features = [
|
windows = { version = "0.53.0", features = [
|
||||||
|
@ -67,7 +68,7 @@ text = ["fontdue"]
|
||||||
blur = ["slur"]
|
blur = ["slur"]
|
||||||
term = ["qwant", "save", "scale", "windows"]
|
term = ["qwant", "save", "scale", "windows"]
|
||||||
real-show = ["minifb", "text"]
|
real-show = ["minifb", "text"]
|
||||||
default = ["save", "scale"]
|
default = ["save", "scale", "term"]
|
||||||
wgpu-convert = ["dep:wgpu"]
|
wgpu-convert = ["dep:wgpu"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
const_option,
|
const_option,
|
||||||
array_chunks,
|
array_chunks,
|
||||||
let_chains,
|
let_chains,
|
||||||
|
try_blocks,
|
||||||
test
|
test
|
||||||
)]
|
)]
|
||||||
#![warn(
|
#![warn(
|
||||||
|
|
78
src/term.rs
78
src/term.rs
|
@ -114,9 +114,27 @@ where
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
// https://github.com/benjajaja/ratatui-image/blob/master/src/picker.rs#L226
|
// https://github.com/benjajaja/ratatui-image/blob/master/src/picker.rs#L226
|
||||||
fn guess_harder(&self, to: &mut impl Write) -> Option<Result> {
|
fn guess_harder(&self, to: &mut impl Write) -> Option<Result> {
|
||||||
extern crate libc;
|
// contains a kitty gfx and sixel query, the `\x1b[c` is for sixels
|
||||||
use std::{io::Read, mem::MaybeUninit};
|
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;")
|
||||||
|
|| buf.contains("?4;")
|
||||||
|
|| buf.contains(";4c")
|
||||||
|
|| buf.contains("?4c")
|
||||||
|
{
|
||||||
|
Some(Sixel(self.as_ref()).write(to))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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<()> {
|
fn r(result: i32) -> Option<()> {
|
||||||
(result != -1).then_some(())
|
(result != -1).then_some(())
|
||||||
}
|
}
|
||||||
|
@ -138,41 +156,41 @@ where
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
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];
|
let buf = try {
|
||||||
'l: loop {
|
// SAFETY: linux time out'd reading
|
||||||
let n = stdin.read(&mut b).ok()?;
|
unsafe {
|
||||||
if n == 0 {
|
println!("{device_query_code}");
|
||||||
continue;
|
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,
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
for b in b {
|
match libc::read(libc::STDIN_FILENO, tmp.as_mut_ptr().cast(), tmp.len()) {
|
||||||
buf.push(b as char);
|
0 => continue,
|
||||||
if b == b'c' {
|
-1 => return None,
|
||||||
break 'l;
|
n => buf.extend_from_slice(&tmp[..n as _]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String::from_utf8(buf).ok()?
|
||||||
}
|
}
|
||||||
buf
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// SAFETY: reset attrs to what they were before we became nosy
|
// SAFETY: reset attrs to what they were before we became nosy
|
||||||
unsafe { libc::tcsetattr(0, libc::TCSADRAIN, &termios) };
|
unsafe { libc::tcsetattr(0, libc::TCSADRAIN, &termios) };
|
||||||
|
buf
|
||||||
if buf.contains("_Gi=31;OK") {
|
|
||||||
Some(Kitty(self.as_ref()).write(to))
|
|
||||||
} else if buf.contains(";4;")
|
|
||||||
|| buf.contains("?4;")
|
|
||||||
|| buf.contains(";4c")
|
|
||||||
|| buf.contains("?4c")
|
|
||||||
{
|
|
||||||
Some(Sixel(self.as_ref()).write(to))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ where
|
||||||
LaneCount<N>: SupportedLaneCount,
|
LaneCount<N>: SupportedLaneCount,
|
||||||
{
|
{
|
||||||
fn cas<U>(self) -> U {
|
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) }
|
unsafe { transmute_unchecked(self) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ where
|
||||||
LaneCount<N>: SupportedLaneCount,
|
LaneCount<N>: SupportedLaneCount,
|
||||||
{
|
{
|
||||||
fn cas<U>(self) -> U {
|
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) }
|
unsafe { transmute_unchecked(self) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,34 @@ impl<T: AsRef<[u8]>, const N: usize> Sixel<T, N> {
|
||||||
where
|
where
|
||||||
[(); N]: Basic,
|
[(); 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")?;
|
to.write_str("Pq")?;
|
||||||
write!(to, r#""1;1;{};{}"#, self.width(), self.height())?;
|
write!(to, r#""1;1;{};{}"#, self.width(), self.height())?;
|
||||||
let buf;
|
let buf;
|
||||||
|
@ -63,14 +91,15 @@ impl<T: AsRef<[u8]>, const N: usize> Sixel<T, N> {
|
||||||
&*buf
|
&*buf
|
||||||
};
|
};
|
||||||
|
|
||||||
let q = qwant::NeuQuant::new(15, 255, rgba);
|
let q = qwant::NeuQuant::new(15, colors as _, rgba);
|
||||||
|
|
||||||
// TODO: don't colllect
|
// 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
|
for ([r, g, b], i) in q
|
||||||
.color_map_rgb()
|
.color_map_rgb()
|
||||||
.map(|x| x.map(|x| (x as f32 * (100. / 255.)) as u32))
|
.map(|x| x.map(|x| (x as f32 * (100. / 255.)) as u32))
|
||||||
.zip(0u8..)
|
.zip(0u64..)
|
||||||
{
|
{
|
||||||
write!(to, "#{i};2;{r};{g};{b}")?;
|
write!(to, "#{i};2;{r};{g};{b}")?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue