1use std::fs;
2use std::path::{Path, PathBuf};
3
4use color_eyre::eyre::{self, Result};
5use image::{ColorType, DynamicImage, ImageReader};
6use ratatui::crossterm::terminal;
7
8pub fn convert_image_ext<T>(image_path: T) -> Result<PathBuf>
9where
10 T: AsRef<Path>,
11{
12 let image_path = image_path.as_ref();
13
14 if !image_path.is_file() {
15 eyre::bail!("Image does not exist: {}", image_path.display());
16 }
17
18 let image_path = dunce::canonicalize(image_path)?;
19
20 let image_ext = image_path.extension().unwrap().to_str().unwrap();
21 if image_ext == "webp" {
22 return Ok(image_path);
23 }
24
25 let image = ImageReader::open(&image_path)?
26 .with_guessed_format()?
27 .decode()?;
28
29 match new_image_ext(&image) {
30 Ok(new_image_ext) => {
31 if image_ext != new_image_ext {
32 let new_image_path = image_path.with_extension(new_image_ext);
33 tracing::info!(
34 "Perform image format conversion: from `{}` to `{}`",
35 image_path.display(),
36 new_image_path.display()
37 );
38
39 if new_image_ext == "webp" {
40 novel_api::save_as_webp(&image, 75.0, &new_image_path)?;
41 } else {
42 image.save(&new_image_path)?;
43 }
44
45 Ok(new_image_path)
46 } else {
47 Ok(image_path)
48 }
49 }
50 Err(err) => {
51 tracing::error!("Failed to convert image: {err}");
52 Ok(image_path)
53 }
54 }
55}
56
57pub fn convert_image_file_stem<T, E>(image_path: T, new_image_stem: E) -> Result<PathBuf>
58where
59 T: AsRef<Path>,
60 E: AsRef<str>,
61{
62 let image_path = image_path.as_ref();
63
64 if !image_path.is_file() {
65 eyre::bail!("Image does not exist: {}", image_path.display());
66 }
67
68 let image_path = dunce::canonicalize(image_path)?;
69 let image_dir = image_path.parent().unwrap();
70 let image_file_stem = image_path.file_stem().unwrap().to_str().unwrap();
71 let image_ext = image_path.extension().unwrap().to_str().unwrap();
72
73 if new_image_stem.as_ref() != image_file_stem {
74 let new_image_path = image_dir.join(format!("{}.{image_ext}", new_image_stem.as_ref()));
75
76 tracing::info!(
77 "Perform image copy: from `{}` to `{}`",
78 image_path.display(),
79 new_image_path.display()
80 );
81
82 fs::copy(image_path, &new_image_path)?;
83
84 Ok(new_image_path)
85 } else {
86 Ok(image_path)
87 }
88}
89
90pub fn new_image_ext(image: &DynamicImage) -> Result<&'static str> {
91 match image.color() {
92 ColorType::Rgb8 | ColorType::Rgba8 => Ok("webp"),
93 ColorType::L8
94 | ColorType::L16
95 | ColorType::La8
96 | ColorType::La16
97 | ColorType::Rgb16
98 | ColorType::Rgba16 => Ok("png"),
99 other => eyre::bail!("This color type is not supported: {other:?}"),
100 }
101}
102
103pub fn terminal_size() -> (u16, u16) {
104 terminal::size().unwrap_or((80, 24))
105}