refactor: restructure project into a workspace by introducing a plugin API crate and modularizing individual plugin definitions.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "convertis-image-ascii"
|
||||
build = "../../plugin-build.rs"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
convertis-plugin-api.workspace = true
|
||||
image.workspace = true
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (C) 2026 Elias Wendland <eliaswendland@pm.me>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 3 exclusively.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use convertis_plugin_api::{Conversion, ConversionRequest, OptionSpec, Plugin, PluginMetadata};
|
||||
const FORMATS: &[&str] = &["png", "jpeg", "gif", "webp", "bmp", "tiff", "ico"];
|
||||
struct ImageAscii;
|
||||
|
||||
impl Plugin for ImageAscii {
|
||||
fn metadata(&self) -> PluginMetadata {
|
||||
PluginMetadata {
|
||||
id: "image-ascii".into(),
|
||||
package: "convertis-image-ascii".into(),
|
||||
description: "Render images as ASCII text".into(),
|
||||
conversions: FORMATS
|
||||
.iter()
|
||||
.map(|from| Conversion::file(from, "text", (255, 180, 230)))
|
||||
.collect(),
|
||||
options: vec![
|
||||
OptionSpec {
|
||||
name: "width".into(),
|
||||
help: "Output width in characters".into(),
|
||||
default: Some("80".into()),
|
||||
},
|
||||
OptionSpec {
|
||||
name: "characters".into(),
|
||||
help: "Dark-to-light character ramp".into(),
|
||||
default: Some("@%#*+=-:. ".into()),
|
||||
},
|
||||
OptionSpec {
|
||||
name: "invert".into(),
|
||||
help: "Reverse the character ramp".into(),
|
||||
default: Some("false".into()),
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn convert(&self, request: &ConversionRequest) -> Result<(), String> {
|
||||
let image = image::open(&request.input).map_err(|error| error.to_string())?;
|
||||
let width: u32 = request
|
||||
.options
|
||||
.get("width")
|
||||
.map(String::as_str)
|
||||
.unwrap_or("80")
|
||||
.parse()
|
||||
.map_err(|_| "width must be a positive integer")?;
|
||||
if width == 0 {
|
||||
return Err("width must be greater than zero".into());
|
||||
}
|
||||
let height = ((image.height() as f32 / image.width() as f32) * width as f32 * 0.5)
|
||||
.round()
|
||||
.max(1.0) as u32;
|
||||
let grayscale = image
|
||||
.resize_exact(width, height, image::imageops::FilterType::Triangle)
|
||||
.to_luma8();
|
||||
let mut ramp: Vec<char> = request
|
||||
.options
|
||||
.get("characters")
|
||||
.map(String::as_str)
|
||||
.unwrap_or("@%#*+=-:. ")
|
||||
.chars()
|
||||
.collect();
|
||||
if ramp.len() < 2 {
|
||||
return Err("characters must contain at least two characters".into());
|
||||
}
|
||||
if request
|
||||
.options
|
||||
.get("invert")
|
||||
.is_some_and(|value| value == "true")
|
||||
{
|
||||
ramp.reverse();
|
||||
}
|
||||
let mut output = String::with_capacity((width as usize + 1) * height as usize);
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let value = grayscale.get_pixel(x, y)[0] as usize;
|
||||
output.push(ramp[value * (ramp.len() - 1) / 255]);
|
||||
}
|
||||
output.push('\n');
|
||||
}
|
||||
std::fs::write(&request.output, output).map_err(|error| error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
convertis_plugin_api::export_plugin!(ImageAscii, "image-ascii");
|
||||
Reference in New Issue
Block a user