Skip to content

Commit

Permalink
v0.0.9
Browse files Browse the repository at this point in the history
  • Loading branch information
ksk001100 committed Mar 30, 2022
1 parent 8636983 commit e76d36a
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 55 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "picterm"
version = "0.0.8"
version = "0.0.9"
authors = ["Keisuke Toyota <[email protected]>"]
edition = "2018"
repository = "https://github.com/ksk001100/picterm"
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

[![crates.io](https://img.shields.io/crates/v/picterm.svg)](https://crates.io/crates/picterm)
![releases count](https://img.shields.io/github/release/ksk001100/picterm.svg)
![download count](https://img.shields.io/crates/d/picterm)
![issues count](https://img.shields.io/github/issues/ksk001100/picterm.svg)
![forks count](https://img.shields.io/github/forks/ksk001100/picterm.svg)
![license](https://img.shields.io/github/license/ksk001100/picterm.svg)
Expand Down Expand Up @@ -32,6 +33,8 @@ $ picterm # => Current directory
$ picterm ./
$ picterm $HOME/Downloads/
$ picterm ~/Pictures/sample.png
$ picterm ~/Pictures/sample.png --gray # => Gray scale mode
$ picterm ~/Pictures/ -g # => Gray scale mode
```

## Support file format
Expand Down
5 changes: 3 additions & 2 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
actions::{Action, Actions},
state::AppState,
},
image::ImageMode,
inputs::key::Key,
io::IoEvent,
};
Expand Down Expand Up @@ -88,7 +89,7 @@ impl<'a> App<'a> {
self.is_loading
}

pub fn initialized(&mut self) {
pub fn initialized(&mut self, mode: ImageMode) {
let args: Vec<String> = std::env::args().collect();
let path = if args[1..].is_empty() { "./" } else { &args[1] };
self.actions = vec![
Expand All @@ -98,7 +99,7 @@ impl<'a> App<'a> {
Action::Show,
]
.into();
self.state = AppState::initialized(path);
self.state = AppState::initialized(path, mode);
}

pub fn loaded(&mut self) {
Expand Down
20 changes: 18 additions & 2 deletions src/app/state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::utils;
use crate::{image::ImageMode, utils};
use std::path::PathBuf;
use tui::text::Spans;

Expand All @@ -11,6 +11,7 @@ pub enum AppState<'a> {
term_size: Option<TermSize>,
current_image: Option<Vec<Spans<'a>>>,
current_image_info: Option<ImageInfo>,
mode: ImageMode,
},
}

Expand All @@ -28,7 +29,7 @@ pub struct ImageInfo {
}

impl<'a> AppState<'a> {
pub fn initialized(path: &str) -> Self {
pub fn initialized(path: &str, mode: ImageMode) -> Self {
let paths = utils::get_image_paths(path);
let selected_index = 0;
let current_image = None;
Expand All @@ -40,6 +41,7 @@ impl<'a> AppState<'a> {
term_size,
current_image,
current_image_info,
mode,
}
}

Expand Down Expand Up @@ -143,6 +145,20 @@ impl<'a> AppState<'a> {
None
}
}

pub fn set_image_mode(&mut self, m: ImageMode) {
if let Self::Initialized { mode, .. } = self {
*mode = m;
}
}

pub fn get_image_mode(&self) -> Option<ImageMode> {
if let Self::Initialized { mode, .. } = self {
Some(mode.clone())
} else {
None
}
}
}

impl<'a> Default for AppState<'a> {
Expand Down
55 changes: 40 additions & 15 deletions src/image.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
use ansi_rgb::Background;
use image::{DynamicImage, GenericImageView, Rgba};
use image::{DynamicImage, GenericImageView, LumaA, Rgba};
use rgb::RGB8;

#[derive(Debug, Clone)]
pub enum ImageMode {
Rgba,
GrayScale,
}

pub fn image_fit_size(img: &DynamicImage, term_w: u32, term_h: u32) -> (u32, u32) {
let (img_width, img_height) = img.dimensions();
let (w, h) = get_dimensions(img_width, img_height, term_w, term_h);
Expand Down Expand Up @@ -33,26 +39,45 @@ pub fn get_dimensions(width: u32, height: u32, bound_width: u32, bound_height: u
}
}

pub fn print_term_image(img: DynamicImage) {
pub fn print_term_image(img: DynamicImage, mode: ImageMode) {
let size = crossterm::terminal::size().unwrap();
let (w, h) = image_fit_size(&img, size.0 as u32, size.1 as u32);
let imgbuf = img
.resize_exact(w, h, image::imageops::FilterType::Triangle)
.to_rgba8();
let imgbuf = img.resize_exact(w, h, image::imageops::FilterType::Triangle);
let (width, height) = imgbuf.dimensions();

for y in 0..height {
for x in 0..width {
let pixel = imgbuf.get_pixel(x, y);
let Rgba(data) = *pixel;
match mode {
ImageMode::Rgba => {
let imgbuf = imgbuf.to_rgba8();
for y in 0..height {
for x in 0..width {
let pixel = imgbuf.get_pixel(x, y);
let Rgba(data) = *pixel;

if data[3] == 0 {
print!(" ");
} else {
let bg = RGB8::new(data[0], data[1], data[2]);
print!("{}", " ".bg(bg));
}
}
println!();
}
}
ImageMode::GrayScale => {
let imgbuf = imgbuf.to_luma_alpha8();
for y in 0..height {
for x in 0..width {
let pixel = imgbuf.get_pixel(x, y);
let LumaA(data) = *pixel;

if data[3] == 0 {
print!(" ");
} else {
let bg = RGB8::new(data[0], data[1], data[2]);
print!("{}", " ".bg(bg));
if data[1] == 0 {
print!(" ");
} else {
print!("{}", " ".bg(RGB8::new(data[0], data[0], data[0])));
}
}
println!();
}
}
println!();
}
}
77 changes: 55 additions & 22 deletions src/io/handler.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{
app::{state::ImageInfo, App},
image::image_fit_size,
image::{image_fit_size, ImageMode},
io::IoEvent,
};
use eyre::Result;
use image::{GenericImageView, Rgba};
use image::{GenericImageView, LumaA, Rgba};
use std::sync::Arc;
use tui::{
style::{Color, Style},
Expand All @@ -22,17 +22,17 @@ impl<'a> IoAsyncHandler<'a> {

pub async fn handle_io_event(&mut self, io_event: IoEvent) {
let _ = match io_event {
IoEvent::Initialize => self.do_initialize().await,
IoEvent::Initialize(mode) => self.do_initialize(mode).await,
IoEvent::LoadImage => self.do_load_image().await,
};

let mut app = self.app.lock().await;
app.loaded();
}

async fn do_initialize(&mut self) -> Result<()> {
async fn do_initialize(&mut self, mode: ImageMode) -> Result<()> {
let mut app = self.app.lock().await;
app.initialized();
app.initialized(mode);

Ok(())
}
Expand All @@ -58,6 +58,11 @@ impl<'a> IoAsyncHandler<'a> {
app.state.get_term_size()
};

let opt_mode = {
let app = self.app.lock().await;
app.state.get_image_mode()
};

{
if let Some(path) = opt_path {
if let Some(term_size) = opt_term_size {
Expand All @@ -79,28 +84,56 @@ impl<'a> IoAsyncHandler<'a> {
};

let (w, h) = image_fit_size(&img, term_size.width, term_size.height);
let imgbuf = img
.resize_exact(w, h, image::imageops::FilterType::Triangle)
.to_rgba8();
let imgbuf = img.resize_exact(w, h, image::imageops::FilterType::Triangle);
let (width, height) = imgbuf.dimensions();

let mut r = result.lock().await;
for y in 0..height {
let mut line = vec![];
for x in 0..width {
let pixel = imgbuf.get_pixel(x, y);
let Rgba(data) = *pixel;

if data[3] == 0 {
line.push(Span::from(" "));
} else {
line.push(Span::styled(
" ",
Style::default().bg(Color::Rgb(data[0], data[1], data[2])),
));

if let Some(mode) = opt_mode {
match mode {
ImageMode::Rgba => {
let imgbuf = imgbuf.to_rgba8();
for y in 0..height {
let mut line = vec![];
for x in 0..width {
let pixel = imgbuf.get_pixel(x, y);
let Rgba(data) = *pixel;

if data[3] == 0 {
line.push(Span::from(" "));
} else {
line.push(Span::styled(
" ",
Style::default()
.bg(Color::Rgb(data[0], data[1], data[2])),
));
}
}
(*r).push(Spans::from(line))
}
}
ImageMode::GrayScale => {
let imgbuf = imgbuf.to_luma_alpha8();
for y in 0..height {
let mut line = vec![];
for x in 0..width {
let pixel = imgbuf.get_pixel(x, y);
let LumaA(data) = *pixel;

if data[1] == 0 {
line.push(Span::from(" "));
} else {
line.push(Span::styled(
" ",
Style::default()
.bg(Color::Rgb(data[0], data[0], data[0])),
));
}
}
(*r).push(Spans::from(line))
}
}
}
(*r).push(Spans::from(line));
}

let mut app = self.app.lock().await;
Expand Down
4 changes: 3 additions & 1 deletion src/io/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub mod handler;

use crate::image::ImageMode;

#[derive(Debug, Clone)]
pub enum IoEvent {
Initialize,
Initialize(ImageMode),
LoadImage,
}
5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod utils;

use crate::{
app::{ui, App, AppReturn},
image::ImageMode,
io::IoEvent,
};
use crossterm::{
Expand All @@ -18,7 +19,7 @@ use inputs::{events::Events, InputEvent};
use std::{io::stdout, sync::Arc, time::Duration};
use tui::{backend::CrosstermBackend, Terminal};

pub async fn start_ui<'a>(app: &Arc<tokio::sync::Mutex<App<'a>>>) -> Result<()> {
pub async fn start_ui<'a>(app: &Arc<tokio::sync::Mutex<App<'a>>>, mode: ImageMode) -> Result<()> {
let mut stdout = stdout();
enable_raw_mode()?;
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
Expand All @@ -32,7 +33,7 @@ pub async fn start_ui<'a>(app: &Arc<tokio::sync::Mutex<App<'a>>>) -> Result<()>

{
let mut app = app.lock().await;
app.dispatch(IoEvent::Initialize).await;
app.dispatch(IoEvent::Initialize(mode)).await;
}

loop {
Expand Down
Loading

0 comments on commit e76d36a

Please sign in to comment.