Compare commits
No commits in common. "07e6c52e94f3cd600ba03624edc070a24d363cbf" and "f09a02a58d8e7bf2bdd3e7209d80f3be4fe2787d" have entirely different histories.
07e6c52e94
...
f09a02a58d
9 changed files with 70 additions and 632 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "bingus"
|
name = "bingus"
|
||||||
version = "0.9.0"
|
version = "0.8.0"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description.workspace = true
|
description.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
#[cfg(feature = "printpdf")]
|
|
||||||
pub use printpdf;
|
pub use printpdf;
|
||||||
#[cfg(feature = "printpdf")]
|
|
||||||
mod pdf;
|
mod pdf;
|
||||||
#[cfg(feature = "shiva")]
|
#[cfg(feature = "shiva")]
|
||||||
mod shiva;
|
mod shiva;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,2 @@
|
||||||
#[cfg(feature = "font-kit")]
|
|
||||||
mod fontkit;
|
mod fontkit;
|
||||||
#[cfg(feature = "font-kit")]
|
|
||||||
pub use fontkit::Font;
|
pub use fontkit::Font;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
#[cfg(feature = "image")]
|
|
||||||
mod image;
|
mod image;
|
||||||
#[cfg(feature = "image")]
|
|
||||||
pub use image::ImageBuffer as Image;
|
pub use image::ImageBuffer as Image;
|
||||||
#[cfg(feature = "image")]
|
|
||||||
pub use image::*;
|
pub use image::*;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
#![deny(unused_crate_dependencies)]
|
|
||||||
|
|
||||||
#[cfg(feature = "binary")]
|
#[cfg(feature = "binary")]
|
||||||
pub mod bin;
|
pub mod bin;
|
||||||
#[cfg(feature = "documents")]
|
#[cfg(feature = "documents")]
|
||||||
|
|
@ -25,13 +23,13 @@ pub mod dynamic {
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(all(feature = "documents", feature = "shiva"))]
|
#[cfg(feature = "documents")]
|
||||||
use super::doc::ShivaDocument;
|
use super::doc::ShivaDocument;
|
||||||
#[cfg(all(feature = "fonts", feature = "font-kit"))]
|
#[cfg(feature = "fonts")]
|
||||||
use super::fnt::Font as FontKitFont;
|
use super::fnt::Font as FontKitFont;
|
||||||
#[cfg(all(feature = "pictures", feature = "image"))]
|
#[cfg(feature = "pictures")]
|
||||||
use super::img::{self, DynamicImage};
|
use super::img::{self, DynamicImage};
|
||||||
#[cfg(all(feature = "music", feature = "symphonia"))]
|
#[cfg(feature = "music")]
|
||||||
use super::snd::{self, Audio};
|
use super::snd::{self, Audio};
|
||||||
#[cfg(feature = "text")]
|
#[cfg(feature = "text")]
|
||||||
use super::txt::Text;
|
use super::txt::Text;
|
||||||
|
|
@ -40,32 +38,32 @@ pub mod dynamic {
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
#[cfg(all(feature = "fonts", feature = "font-kit"))]
|
#[cfg(feature = "fonts")]
|
||||||
use font_kit::error::FontLoadingError;
|
use font_kit::error::FontLoadingError;
|
||||||
pub use infer::*;
|
pub use infer::*;
|
||||||
#[cfg(all(feature = "documents", feature = "printpdf"))]
|
#[cfg(feature = "documents")]
|
||||||
use printpdf::PdfDocument;
|
use printpdf::PdfDocument;
|
||||||
#[cfg(all(feature = "documents", feature = "shiva"))]
|
#[cfg(feature = "documents")]
|
||||||
use shiva::core::{bytes, Document, DocumentType};
|
use shiva::core::{bytes, Document, DocumentType};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub enum DynamicBendable<'a> {
|
pub enum DynamicBendable<'a> {
|
||||||
#[cfg(all(feature = "pictures", feature = "image"))]
|
#[cfg(feature = "pictures")]
|
||||||
Image(DynamicImage),
|
Image(DynamicImage),
|
||||||
#[cfg(feature = "binary")]
|
#[cfg(feature = "binary")]
|
||||||
Binary(Bytes),
|
Binary(Bytes),
|
||||||
#[cfg(all(feature = "music", feature = "symphonia"))]
|
#[cfg(feature = "music")]
|
||||||
Sound(Audio),
|
Sound(Audio),
|
||||||
#[cfg(feature = "text")]
|
#[cfg(feature = "text")]
|
||||||
Text(Text<'a>),
|
Text(Text<'a>),
|
||||||
#[cfg(not(feature = "text"))]
|
#[cfg(not(feature = "text"))]
|
||||||
Phantom(PhantomData<&'a ()>),
|
Phantom(PhantomData<&'a ()>),
|
||||||
#[cfg(all(feature = "documents", feature = "shiva"))]
|
#[cfg(feature = "documents")]
|
||||||
Doc(ShivaDocument),
|
Doc(ShivaDocument),
|
||||||
#[cfg(all(feature = "documents", feature = "printpdf"))]
|
#[cfg(feature = "documents")]
|
||||||
Archive(PdfDocument),
|
Archive(PdfDocument),
|
||||||
Meta,
|
Meta,
|
||||||
#[cfg(all(feature = "fonts", feature = "font-kit"))]
|
#[cfg(feature = "fonts")]
|
||||||
Font(FontKitFont),
|
Font(FontKitFont),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,22 +85,22 @@ pub mod dynamic {
|
||||||
pub enum OpenError {
|
pub enum OpenError {
|
||||||
#[error("io: {0}")]
|
#[error("io: {0}")]
|
||||||
Io(#[from] io::Error),
|
Io(#[from] io::Error),
|
||||||
#[cfg(all(feature = "pictures", feature = "image"))]
|
#[cfg(feature = "pictures")]
|
||||||
#[error("image: {0}")]
|
#[error("image: {0}")]
|
||||||
Image(#[from] img::ImageError),
|
Image(#[from] img::ImageError),
|
||||||
#[cfg(all(feature = "music", feature = "symphonia"))]
|
#[cfg(feature = "music")]
|
||||||
#[error("audio: {0}")]
|
#[error("audio: {0}")]
|
||||||
Audio(#[from] snd::AudioOpenError),
|
Audio(#[from] snd::AudioOpenError),
|
||||||
#[cfg(all(feature = "documents", feature = "printpdf"))]
|
#[cfg(feature = "documents")]
|
||||||
#[error("pdf: {0}")]
|
#[error("pdf: {0}")]
|
||||||
Pdf(String),
|
Pdf(String),
|
||||||
#[cfg(feature = "text")]
|
#[cfg(feature = "text")]
|
||||||
#[error("text: {0}")]
|
#[error("text: {0}")]
|
||||||
Text(#[from] FromUtf8Error),
|
Text(#[from] FromUtf8Error),
|
||||||
#[cfg(all(feature = "documents", feature = "shiva"))]
|
#[cfg(feature = "documents")]
|
||||||
#[error("document: {0}")]
|
#[error("document: {0}")]
|
||||||
Document(#[from] ShivaError),
|
Document(#[from] ShivaError),
|
||||||
#[cfg(all(feature = "fonts", feature = "font-kit"))]
|
#[cfg(feature = "fonts")]
|
||||||
#[error("font: {0:?}")]
|
#[error("font: {0:?}")]
|
||||||
Font(#[from] FontLoadingError),
|
Font(#[from] FontLoadingError),
|
||||||
}
|
}
|
||||||
|
|
@ -157,11 +155,11 @@ pub mod dynamic {
|
||||||
.map(
|
.map(
|
||||||
|(matcher, extension)| -> Result<DynamicBendable, OpenError> {
|
|(matcher, extension)| -> Result<DynamicBendable, OpenError> {
|
||||||
Ok(match matcher {
|
Ok(match matcher {
|
||||||
#[cfg(all(feature = "pictures", feature = "image"))]
|
#[cfg(feature = "pictures")]
|
||||||
Image => DynamicBendable::Image(img::load_from_memory(&bytes)?),
|
Image => DynamicBendable::Image(img::load_from_memory(&bytes)?),
|
||||||
#[cfg(all(feature = "music", feature = "symphonia"))]
|
#[cfg(feature = "music")]
|
||||||
Audio => DynamicBendable::Sound(crate::snd::Audio::open(Cursor::new(bytes), None)?),
|
Audio => DynamicBendable::Sound(crate::snd::Audio::open(Cursor::new(bytes), None)?),
|
||||||
#[cfg(all(feature = "documents", feature = "printpdf"))]
|
#[cfg(feature = "documents")]
|
||||||
Archive if extension == "pdf" => DynamicBendable::Archive(
|
Archive if extension == "pdf" => DynamicBendable::Archive(
|
||||||
PdfDocument::try_from_data_bytes(
|
PdfDocument::try_from_data_bytes(
|
||||||
bytes,
|
bytes,
|
||||||
|
|
@ -170,7 +168,7 @@ pub mod dynamic {
|
||||||
)
|
)
|
||||||
.map_err(OpenError::Pdf)?,
|
.map_err(OpenError::Pdf)?,
|
||||||
),
|
),
|
||||||
#[cfg(all(feature = "documents", feature = "shiva"))]
|
#[cfg(feature = "documents")]
|
||||||
Archive | Doc => {
|
Archive | Doc => {
|
||||||
let document_type = DocumentType::from_extension(extension)
|
let document_type = DocumentType::from_extension(extension)
|
||||||
.ok_or(ShivaUnknownExtensionError)
|
.ok_or(ShivaUnknownExtensionError)
|
||||||
|
|
@ -184,7 +182,7 @@ pub mod dynamic {
|
||||||
document_type,
|
document_type,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
#[cfg(all(feature = "fonts", feature = "font-kit"))]
|
#[cfg(feature = "fonts")]
|
||||||
Font => DynamicBendable::Font(FontKitFont::try_from_data_bytes(
|
Font => DynamicBendable::Font(FontKitFont::try_from_data_bytes(
|
||||||
bytes,
|
bytes,
|
||||||
(),
|
(),
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
#[cfg(feature = "symphonia")]
|
|
||||||
pub use symphonia::core::*;
|
pub use symphonia::core::*;
|
||||||
mod raw;
|
mod raw;
|
||||||
pub use raw::*;
|
pub use raw::*;
|
||||||
#[cfg(feature = "symphonia")]
|
|
||||||
mod simphonia;
|
mod simphonia;
|
||||||
#[cfg(feature = "symphonia")]
|
|
||||||
pub use simphonia::*;
|
pub use simphonia::*;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ keywords.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
bingus = "0.8"
|
bingus = "0.6"
|
||||||
strum = { version = "0", features = ["derive"] }
|
strum = { version = "0", features = ["derive"] }
|
||||||
derive-new = "0"
|
derive-new = "0"
|
||||||
clap = { version = "4.5.40", features = ["derive"] }
|
clap = { version = "4.5.40", features = ["derive"] }
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,17 @@ use strum::{Display, EnumString};
|
||||||
pub(crate) struct Cli {
|
pub(crate) struct Cli {
|
||||||
/// Input file or standard input ("-").
|
/// Input file or standard input ("-").
|
||||||
pub(crate) input: FileOrStd<Stdin>,
|
pub(crate) input: FileOrStd<Stdin>,
|
||||||
|
#[command(subcommand)]
|
||||||
|
pub(crate) output_format: OutputFormat,
|
||||||
/// Output file or standard output ("-").
|
/// Output file or standard output ("-").
|
||||||
pub(crate) output: FileOrStd<Stdout>,
|
pub(crate) output: FileOrStd<Stdout>,
|
||||||
/// Output format
|
|
||||||
#[command(subcommand)]
|
|
||||||
pub(crate) output_format: Option<OutputFormat>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Parser)]
|
#[derive(Clone, Copy, Parser)]
|
||||||
#[cfg_attr(debug_assertions, derive(Debug))]
|
#[cfg_attr(debug_assertions, derive(Debug))]
|
||||||
pub struct Dimensions {
|
pub struct Dimensions {
|
||||||
pub width: Option<u32>,
|
pub width: u32,
|
||||||
pub height: Option<u32>,
|
pub height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Parser)]
|
#[derive(Clone, Copy, Parser)]
|
||||||
|
|
@ -41,23 +40,16 @@ pub struct ShivaFormat {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Parser)]
|
#[derive(Clone, Copy, Parser)]
|
||||||
pub struct Mp3Format {
|
pub struct Mp3Format {
|
||||||
|
#[arg(default_value = "44100")]
|
||||||
pub sample_rate: u32,
|
pub sample_rate: u32,
|
||||||
|
#[arg(default_value = "128")]
|
||||||
pub bitrate: u16,
|
pub bitrate: u16,
|
||||||
|
#[arg(default_value = "5")]
|
||||||
pub quality: u8,
|
pub quality: u8,
|
||||||
|
#[arg(default_value_t)]
|
||||||
pub sample_format: Mp3SampleFormat,
|
pub sample_format: Mp3SampleFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Mp3Format {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
sample_rate: 44100,
|
|
||||||
bitrate: 128,
|
|
||||||
quality: 5,
|
|
||||||
sample_format: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, EnumString, Default, Display)]
|
#[derive(Clone, Copy, EnumString, Default, Display)]
|
||||||
#[strum(ascii_case_insensitive)]
|
#[strum(ascii_case_insensitive)]
|
||||||
pub enum Mp3SampleFormat {
|
pub enum Mp3SampleFormat {
|
||||||
|
|
@ -71,19 +63,12 @@ pub enum Mp3SampleFormat {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Parser)]
|
#[derive(Clone, Copy, Parser)]
|
||||||
pub struct WavFormat {
|
pub struct WavFormat {
|
||||||
|
#[arg(default_value = "48000")]
|
||||||
pub sample_rate: u32,
|
pub sample_rate: u32,
|
||||||
|
#[arg(default_value_t)]
|
||||||
pub sample_format: WavSampleFormat,
|
pub sample_format: WavSampleFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WavFormat {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
sample_rate: 48000,
|
|
||||||
sample_format: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, EnumString, Display, Default)]
|
#[derive(Clone, Copy, EnumString, Display, Default)]
|
||||||
#[strum(ascii_case_insensitive)]
|
#[strum(ascii_case_insensitive)]
|
||||||
pub enum WavSampleFormat {
|
pub enum WavSampleFormat {
|
||||||
|
|
@ -96,20 +81,12 @@ pub enum WavSampleFormat {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Parser)]
|
#[derive(Clone, Copy, Parser)]
|
||||||
pub struct FlacFormat {
|
pub struct FlacFormat {
|
||||||
|
#[arg(default_value = "48000")]
|
||||||
pub sample_rate: usize,
|
pub sample_rate: usize,
|
||||||
#[arg(value_parser = flac_bps_value_parser)]
|
#[arg(value_parser = flac_bps_value_parser, default_value = "16")]
|
||||||
pub bps: usize,
|
pub bps: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FlacFormat {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
sample_rate: 48000,
|
|
||||||
bps: 16,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flac_bps_value_parser(input: &str) -> anyhow::Result<usize> {
|
fn flac_bps_value_parser(input: &str) -> anyhow::Result<usize> {
|
||||||
input.parse().context("not a number").and_then(|n| match n {
|
input.parse().context("not a number").and_then(|n| match n {
|
||||||
8 | 16 | 24 => Ok(n),
|
8 | 16 | 24 => Ok(n),
|
||||||
|
|
@ -129,8 +106,8 @@ impl From<WavSampleFormat> for hound::SampleFormat {
|
||||||
impl From<Dimensions> for bingus::img::Dimensions {
|
impl From<Dimensions> for bingus::img::Dimensions {
|
||||||
fn from(value: Dimensions) -> Self {
|
fn from(value: Dimensions) -> Self {
|
||||||
Self {
|
Self {
|
||||||
width: value.width.unwrap_or_default(),
|
width: value.width,
|
||||||
height: value.height.unwrap_or_default(),
|
height: value.height,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -196,10 +173,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Parser, Default)]
|
#[derive(Clone, Parser)]
|
||||||
pub(crate) enum OutputFormat {
|
pub(crate) enum OutputFormat {
|
||||||
#[default]
|
|
||||||
Auto,
|
|
||||||
Bytes,
|
Bytes,
|
||||||
Pdf,
|
Pdf,
|
||||||
ShivaDocument(ShivaFormat),
|
ShivaDocument(ShivaFormat),
|
||||||
|
|
|
||||||
559
bong/src/main.rs
559
bong/src/main.rs
|
|
@ -1,5 +1,3 @@
|
||||||
#![deny(unused_crate_dependencies)]
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
fs::File,
|
fs::File,
|
||||||
|
|
@ -8,12 +6,12 @@ use std::{
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context};
|
use anyhow::{anyhow, bail, Context};
|
||||||
use bingus::{
|
use bingus::{
|
||||||
doc::{printpdf::PdfDocument, DocumentType, ShivaDocument, ShivaFormat},
|
doc::{printpdf::PdfDocument, ShivaDocument},
|
||||||
dynamic::{self, DynamicBendable},
|
dynamic::{self, DynamicBendable},
|
||||||
fnt::Font,
|
fnt::Font,
|
||||||
img::{
|
img::{
|
||||||
Dimensions, GrayAlphaImage, GrayImage, Image, ImageFormat, Luma, LumaA, Rgb, Rgb32FImage,
|
GrayAlphaImage, GrayImage, Image, Luma, LumaA, Rgb, Rgb32FImage, RgbImage, Rgba,
|
||||||
RgbImage, Rgba, Rgba32FImage, RgbaImage,
|
Rgba32FImage, RgbaImage,
|
||||||
},
|
},
|
||||||
snd::{conv::IntoSample, sample::i24, RawSamples},
|
snd::{conv::IntoSample, sample::i24, RawSamples},
|
||||||
txt::Text,
|
txt::Text,
|
||||||
|
|
@ -44,7 +42,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
.context("reading input")?;
|
.context("reading input")?;
|
||||||
buf
|
buf
|
||||||
};
|
};
|
||||||
let bytes = match dynamic::open(&mut Cursor::new(input_bytes.clone()))
|
let mut bytes = match dynamic::open(&mut Cursor::new(input_bytes.clone()))
|
||||||
.context("guessing media type / loading media")?
|
.context("guessing media type / loading media")?
|
||||||
.or(String::from_utf8(input_bytes.clone())
|
.or(String::from_utf8(input_bytes.clone())
|
||||||
.ok()
|
.ok()
|
||||||
|
|
@ -72,484 +70,11 @@ fn main() -> anyhow::Result<()> {
|
||||||
.context("bending input into bytes")?;
|
.context("bending input into bytes")?;
|
||||||
match output {
|
match output {
|
||||||
cli::FileOrStd::File(file) => {
|
cli::FileOrStd::File(file) => {
|
||||||
match output_format.unwrap_or_default() {
|
match output_format {
|
||||||
cli::OutputFormat::Auto => {
|
cli::OutputFormat::Bytes => {
|
||||||
let extension = file
|
|
||||||
.extension()
|
|
||||||
.and_then(|os_str| os_str.to_str())
|
|
||||||
.map(|s| s.to_ascii_lowercase());
|
|
||||||
if let Some(ext) = &extension {
|
|
||||||
match ext.as_str() {
|
|
||||||
"pdf" => {
|
|
||||||
File::bend_from(
|
|
||||||
PdfDocument::bend_from(bytes, (), Default::default())
|
|
||||||
.map_err(|s| anyhow!("{}", s))
|
|
||||||
.context("bending into PDF document")?
|
|
||||||
.into_data_bytes(),
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing PDF to output file")?;
|
|
||||||
}
|
|
||||||
_valid_shiva_extension
|
|
||||||
if DocumentType::from_extension(ext).is_some() =>
|
|
||||||
{
|
|
||||||
let document_type = DocumentType::from_extension(ext).unwrap();
|
|
||||||
File::bend_from(
|
|
||||||
ShivaDocument::bend_from(
|
|
||||||
bytes,
|
|
||||||
ShivaFormat::new(document_type, document_type),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("bending into a Shiva Document")?,
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing Shiva Document to output file")?;
|
|
||||||
}
|
|
||||||
"ttf" | "ttc" | "otf" | "otc" | "cff" | "pfb" | "pfa" | "pfm"
|
|
||||||
| "afm" | "bdf" | "pcf" | "fon" | "fnt" | "svg" | "dfont" | "woff"
|
|
||||||
| "woff2" | "eot" => {
|
|
||||||
File::bend_from(
|
|
||||||
Font::bend_from(bytes, (), Default::default())
|
|
||||||
.context("bending to font")?
|
|
||||||
.into_data_bytes(),
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing font to output file")?;
|
|
||||||
}
|
|
||||||
"mp3" => {
|
|
||||||
eprintln!("warning: Rust MP3 lame encoder is freaky!");
|
|
||||||
let mp3_format = Mp3Format::default();
|
|
||||||
let Mp3Format {
|
|
||||||
bitrate,
|
|
||||||
quality,
|
|
||||||
sample_rate,
|
|
||||||
sample_format,
|
|
||||||
} = mp3_format;
|
|
||||||
let buff = {
|
|
||||||
use mp3lame_encoder::{Bitrate::*, Quality::*};
|
|
||||||
let mut encoder = Mp3EncoderBuilder::new()
|
|
||||||
.context("Failed to create MP3 encoder builder")?;
|
|
||||||
encoder
|
|
||||||
.set_num_channels(1)
|
|
||||||
.context("Failed to set MP3 encoder channels")?;
|
|
||||||
encoder
|
|
||||||
.set_sample_rate(sample_rate)
|
|
||||||
.context("Failed to set MP3 encoder sample rate")?;
|
|
||||||
encoder
|
|
||||||
.set_brate(match bitrate {
|
|
||||||
8 => Kbps8,
|
|
||||||
16 => Kbps16,
|
|
||||||
24 => Kbps24,
|
|
||||||
32 => Kbps32,
|
|
||||||
40 => Kbps40,
|
|
||||||
48 => Kbps48,
|
|
||||||
64 => Kbps64,
|
|
||||||
80 => Kbps80,
|
|
||||||
96 => Kbps96,
|
|
||||||
112 => Kbps112,
|
|
||||||
128 => Kbps128,
|
|
||||||
160 => Kbps160,
|
|
||||||
192 => Kbps192,
|
|
||||||
224 => Kbps224,
|
|
||||||
256 => Kbps256,
|
|
||||||
320 => Kbps320,
|
|
||||||
_ => bail!("invalid MP3 bitrate"),
|
|
||||||
})
|
|
||||||
.context("Failed to set MP3 encoder bitrate")?;
|
|
||||||
encoder
|
|
||||||
.set_quality(match quality {
|
|
||||||
0 => Best,
|
|
||||||
1 => SecondBest,
|
|
||||||
2 => NearBest,
|
|
||||||
3 => VeryNice,
|
|
||||||
4 => Nice,
|
|
||||||
5 => Good,
|
|
||||||
6 => Decent,
|
|
||||||
7 => Ok,
|
|
||||||
8 => SecondWorst,
|
|
||||||
9 => Worst,
|
|
||||||
_ => bail!("invalid MP3 quality"),
|
|
||||||
})
|
|
||||||
.context("Failed to set MP3 encoder quality")?;
|
|
||||||
|
|
||||||
let mut encoder = encoder
|
|
||||||
.build()
|
|
||||||
.context("Failed to initialize MP3 encoder")?;
|
|
||||||
|
|
||||||
let (encoded_size, mut output) = {
|
|
||||||
match sample_format {
|
|
||||||
cli::Mp3SampleFormat::U16 => {
|
|
||||||
let (left, right): (Vec<_>, Vec<_>) =
|
|
||||||
RawSamples::<u16>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
.chunks_exact(2)
|
|
||||||
.map(|c| (c[0], c[1]))
|
|
||||||
.unzip();
|
|
||||||
let input = DualPcm {
|
|
||||||
left: &left,
|
|
||||||
right: &right,
|
|
||||||
};
|
|
||||||
let mut output = Vec::with_capacity(
|
|
||||||
mp3lame_encoder::max_required_buffer_size(
|
|
||||||
left.len() + right.len(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
(
|
|
||||||
encoder
|
|
||||||
.encode(input, output.spare_capacity_mut())
|
|
||||||
.context("Failed MP3 encoding")?,
|
|
||||||
output,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
cli::Mp3SampleFormat::I16 => {
|
|
||||||
let (left, right): (Vec<_>, Vec<_>) =
|
|
||||||
RawSamples::<i16>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
.chunks_exact(2)
|
|
||||||
.map(|c| (c[0], c[1]))
|
|
||||||
.unzip();
|
|
||||||
let input = DualPcm {
|
|
||||||
left: &left,
|
|
||||||
right: &right,
|
|
||||||
};
|
|
||||||
let mut output = Vec::with_capacity(
|
|
||||||
mp3lame_encoder::max_required_buffer_size(
|
|
||||||
left.len() + right.len(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
(
|
|
||||||
encoder
|
|
||||||
.encode(input, output.spare_capacity_mut())
|
|
||||||
.context("Failed MP3 encoding")?,
|
|
||||||
output,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
cli::Mp3SampleFormat::I32 => {
|
|
||||||
let (left, right): (Vec<_>, Vec<_>) =
|
|
||||||
RawSamples::<i32>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
.chunks_exact(2)
|
|
||||||
.map(|c| (c[0], c[1]))
|
|
||||||
.unzip();
|
|
||||||
let input = DualPcm {
|
|
||||||
left: &left,
|
|
||||||
right: &right,
|
|
||||||
};
|
|
||||||
let mut output = Vec::with_capacity(
|
|
||||||
mp3lame_encoder::max_required_buffer_size(
|
|
||||||
left.len() + right.len(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
(
|
|
||||||
encoder
|
|
||||||
.encode(input, output.spare_capacity_mut())
|
|
||||||
.context("Failed MP3 encoding")?,
|
|
||||||
output,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
cli::Mp3SampleFormat::F32 => {
|
|
||||||
let (left, right): (Vec<_>, Vec<_>) =
|
|
||||||
RawSamples::<f32>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
.chunks_exact(2)
|
|
||||||
.map(|c| (c[0], c[1]))
|
|
||||||
.unzip();
|
|
||||||
let input = DualPcm {
|
|
||||||
left: &left,
|
|
||||||
right: &right,
|
|
||||||
};
|
|
||||||
let mut output = Vec::with_capacity(
|
|
||||||
mp3lame_encoder::max_required_buffer_size(
|
|
||||||
left.len() + right.len(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
(
|
|
||||||
encoder
|
|
||||||
.encode(input, output.spare_capacity_mut())
|
|
||||||
.context("Failed MP3 encoding")?,
|
|
||||||
output,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
cli::Mp3SampleFormat::F64 => {
|
|
||||||
let (left, right): (Vec<_>, Vec<_>) =
|
|
||||||
RawSamples::<f64>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.into_inner()
|
|
||||||
.chunks_exact(2)
|
|
||||||
.map(|c| (c[0], c[1]))
|
|
||||||
.unzip();
|
|
||||||
let input = DualPcm {
|
|
||||||
left: &left,
|
|
||||||
right: &right,
|
|
||||||
};
|
|
||||||
let mut output = Vec::with_capacity(
|
|
||||||
mp3lame_encoder::max_required_buffer_size(
|
|
||||||
left.len() + right.len(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
(
|
|
||||||
encoder
|
|
||||||
.encode(input, output.spare_capacity_mut())
|
|
||||||
.context("Failed MP3 encoding")?,
|
|
||||||
output,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
unsafe {
|
|
||||||
output.set_len(output.len().wrapping_add(encoded_size));
|
|
||||||
}
|
|
||||||
let encoded_size = encoder
|
|
||||||
.flush::<FlushGap>(output.spare_capacity_mut())
|
|
||||||
.context(
|
|
||||||
"Failed MP3 flushing (don't know what that means)",
|
|
||||||
)?;
|
|
||||||
unsafe {
|
|
||||||
output.set_len(output.len().wrapping_add(encoded_size));
|
|
||||||
}
|
|
||||||
output
|
|
||||||
};
|
|
||||||
File::bend_from(buff, Box::new(file), Default::default())
|
|
||||||
.context("writing MP3 to output file")?;
|
|
||||||
}
|
|
||||||
"wav" => {
|
|
||||||
let wav_format = Default::default();
|
|
||||||
let WavFormat {
|
|
||||||
sample_rate,
|
|
||||||
sample_format,
|
|
||||||
} = wav_format;
|
|
||||||
match sample_format {
|
|
||||||
cli::WavSampleFormat::I8 => {
|
|
||||||
let samples = RawSamples::<i8>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap_infallible();
|
|
||||||
let mut buff = Cursor::new(Vec::with_capacity(
|
|
||||||
samples.as_ref().len() * 8,
|
|
||||||
));
|
|
||||||
{
|
|
||||||
let mut writer = WavWriter::new(
|
|
||||||
&mut buff,
|
|
||||||
WavSpec {
|
|
||||||
channels: 1,
|
|
||||||
sample_rate,
|
|
||||||
bits_per_sample: i8::BITS as u16,
|
|
||||||
sample_format: sample_format.into(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.context("Failed to create WAV writer")?;
|
|
||||||
for sample in samples.as_ref() {
|
|
||||||
writer.write_sample(*sample)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File::try_from_data_bytes(
|
|
||||||
buff.into_inner(),
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing WAV data to output file")?
|
|
||||||
}
|
|
||||||
cli::WavSampleFormat::I16 => {
|
|
||||||
let samples = RawSamples::<i16>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap_infallible();
|
|
||||||
let mut buff = Cursor::new(Vec::with_capacity(
|
|
||||||
samples.as_ref().len() * 8,
|
|
||||||
));
|
|
||||||
{
|
|
||||||
let mut writer = WavWriter::new(
|
|
||||||
&mut buff,
|
|
||||||
WavSpec {
|
|
||||||
channels: 1,
|
|
||||||
sample_rate,
|
|
||||||
bits_per_sample: i16::BITS as u16,
|
|
||||||
sample_format: sample_format.into(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.context("Failed to create WAV writer")?;
|
|
||||||
for sample in samples.as_ref() {
|
|
||||||
writer.write_sample(*sample)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File::try_from_data_bytes(
|
|
||||||
buff.into_inner(),
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing WAV data to output file")?
|
|
||||||
}
|
|
||||||
cli::WavSampleFormat::I32 => {
|
|
||||||
let samples = RawSamples::<i32>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap_infallible();
|
|
||||||
let mut buff = Cursor::new(Vec::with_capacity(
|
|
||||||
samples.as_ref().len() * 8,
|
|
||||||
));
|
|
||||||
{
|
|
||||||
let mut writer = WavWriter::new(
|
|
||||||
&mut buff,
|
|
||||||
WavSpec {
|
|
||||||
channels: 1,
|
|
||||||
sample_rate,
|
|
||||||
bits_per_sample: i32::BITS as u16,
|
|
||||||
sample_format: sample_format.into(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.context("Failed to create WAV writer")?;
|
|
||||||
for sample in samples.as_ref() {
|
|
||||||
writer.write_sample(*sample)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File::try_from_data_bytes(
|
|
||||||
buff.into_inner(),
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing WAV data to output file")?
|
|
||||||
}
|
|
||||||
cli::WavSampleFormat::F32 => {
|
|
||||||
let samples = RawSamples::<f32>::bend_from(
|
|
||||||
bytes,
|
|
||||||
(),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.unwrap_infallible();
|
|
||||||
let mut buff = Cursor::new(Vec::with_capacity(
|
|
||||||
samples.as_ref().len() * 8,
|
|
||||||
));
|
|
||||||
{
|
|
||||||
let mut writer = WavWriter::new(
|
|
||||||
&mut buff,
|
|
||||||
WavSpec {
|
|
||||||
channels: 1,
|
|
||||||
sample_rate,
|
|
||||||
bits_per_sample: 32,
|
|
||||||
sample_format: sample_format.into(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.context("Failed to create WAV writer")?;
|
|
||||||
for sample in samples.as_ref() {
|
|
||||||
writer.write_sample(*sample)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File::try_from_data_bytes(
|
|
||||||
buff.into_inner(),
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing WAV data to output file")?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
"flac" => {
|
|
||||||
let flac_format = Default::default();
|
|
||||||
let FlacFormat { sample_rate, bps } = flac_format;
|
|
||||||
let config = flacenc::config::Encoder::default()
|
|
||||||
.into_verified()
|
|
||||||
.expect("Config data error.");
|
|
||||||
let samples =
|
|
||||||
RawSamples::<i32>::bend_from(bytes, (), Default::default())
|
|
||||||
.unwrap_infallible();
|
|
||||||
let source = flacenc::source::MemSource::from_samples(
|
|
||||||
samples.as_ref().iter().copied()
|
|
||||||
.map(|sample| match bps {
|
|
||||||
8 => IntoSample::<i8>::into_sample(sample) as i32,
|
|
||||||
16 => IntoSample::<i16>::into_sample(sample) as i32,
|
|
||||||
24 => IntoSample::<i24>::into_sample(sample).inner(),
|
|
||||||
_=> unimplemented!("sorry, the current implementation for the flac encoder doesn't support any other bitrate than 8, 16 or 24.")
|
|
||||||
})
|
|
||||||
.collect::<Vec<i32>>()
|
|
||||||
.as_slice(),
|
|
||||||
1,
|
|
||||||
bps,
|
|
||||||
sample_rate,
|
|
||||||
);
|
|
||||||
let flac_stream = flacenc::encode_with_fixed_block_size(
|
|
||||||
&config,
|
|
||||||
source,
|
|
||||||
config.block_size,
|
|
||||||
)
|
|
||||||
.expect("Encode failed.");
|
|
||||||
|
|
||||||
// `Stream` imlpements `BitRepr` so you can obtain the encoded stream via
|
|
||||||
// `ByteSink` struct that implements `BitSink`.
|
|
||||||
let mut sink = flacenc::bitsink::ByteSink::new();
|
|
||||||
flac_stream
|
|
||||||
.write(&mut sink)
|
|
||||||
.context("Failed to write samples to FLAC byte sink")?;
|
|
||||||
File::try_from_data_bytes(
|
|
||||||
sink.into_inner(),
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing FLAC data to output file")?;
|
|
||||||
}
|
|
||||||
"txt" => {
|
|
||||||
File::bend_from(
|
|
||||||
Text::try_from_data_bytes(bytes, (), Default::default())
|
|
||||||
.context("invalid UTF-8")?,
|
|
||||||
Box::new(file),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.context("writing text to output file")?;
|
|
||||||
}
|
|
||||||
_valid_image_extension
|
|
||||||
if ImageFormat::from_extension(ext).is_some() =>
|
|
||||||
{
|
|
||||||
let len = bytes.len();
|
|
||||||
RgbImage::from_data_bytes(
|
|
||||||
bytes,
|
|
||||||
Dimensions::square((len / 3).isqrt() as u32),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.save(file)
|
|
||||||
.context("writing image data to output file")?
|
|
||||||
}
|
|
||||||
"bin" => {
|
|
||||||
File::bend_from(bytes, Box::new(file), Default::default())
|
File::bend_from(bytes, Box::new(file), Default::default())
|
||||||
.context("writing to file")?;
|
.context("writing to file")?;
|
||||||
}
|
}
|
||||||
_ => bail!("Unknown file extension! Can't guess output file type. Please use one of the available types instead (see --help)."),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bail!("Can't guess the output file type without a file extension. Please specify one.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cli::OutputFormat::Pdf => {
|
cli::OutputFormat::Pdf => {
|
||||||
File::bend_from(
|
File::bend_from(
|
||||||
PdfDocument::bend_from(bytes, (), Default::default())
|
PdfDocument::bend_from(bytes, (), Default::default())
|
||||||
|
|
@ -946,126 +471,76 @@ fn main() -> anyhow::Result<()> {
|
||||||
.context("writing text to output file")?;
|
.context("writing text to output file")?;
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageLuma8(dimensions) => {
|
cli::OutputFormat::ImageLuma8(dimensions) => {
|
||||||
let len = bytes.len();
|
GrayImage::from_data_bytes(bytes, dimensions.into(), Default::default())
|
||||||
GrayImage::from_data_bytes(
|
|
||||||
bytes,
|
|
||||||
if_zero_adjust(dimensions.into(), len),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageLumaA8(dimensions) => {
|
cli::OutputFormat::ImageLumaA8(dimensions) => {
|
||||||
let len = bytes.len();
|
GrayAlphaImage::from_data_bytes(bytes, dimensions.into(), Default::default())
|
||||||
GrayAlphaImage::from_data_bytes(
|
|
||||||
bytes,
|
|
||||||
if_zero_adjust(dimensions.into(), len),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageRgb8(dimensions) => {
|
cli::OutputFormat::ImageRgb8(dimensions) => {
|
||||||
let len = bytes.len();
|
RgbImage::from_data_bytes(bytes, dimensions.into(), Default::default())
|
||||||
RgbImage::from_data_bytes(
|
|
||||||
bytes,
|
|
||||||
if_zero_adjust(dimensions.into(), len),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageRgba8(dimensions) => {
|
cli::OutputFormat::ImageRgba8(dimensions) => {
|
||||||
let len = bytes.len();
|
RgbaImage::from_data_bytes(bytes, dimensions.into(), Default::default())
|
||||||
RgbaImage::from_data_bytes(
|
|
||||||
bytes,
|
|
||||||
if_zero_adjust(dimensions.into(), len),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageLuma16(dimensions) => {
|
cli::OutputFormat::ImageLuma16(dimensions) => {
|
||||||
let len = bytes.len();
|
|
||||||
Image::<Luma<u16>, Vec<u16>>::from_data_bytes(
|
Image::<Luma<u16>, Vec<u16>>::from_data_bytes(
|
||||||
bytes,
|
bytes,
|
||||||
if_zero_adjust(dimensions.into(), len),
|
dimensions.into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageLumaA16(dimensions) => {
|
cli::OutputFormat::ImageLumaA16(dimensions) => {
|
||||||
let len = bytes.len();
|
|
||||||
Image::<LumaA<u16>, Vec<u16>>::from_data_bytes(
|
Image::<LumaA<u16>, Vec<u16>>::from_data_bytes(
|
||||||
bytes,
|
bytes,
|
||||||
if_zero_adjust(dimensions.into(), len),
|
dimensions.into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageRgb16(dimensions) => {
|
cli::OutputFormat::ImageRgb16(dimensions) => {
|
||||||
let len = bytes.len();
|
|
||||||
Image::<Rgb<u16>, Vec<u16>>::from_data_bytes(
|
Image::<Rgb<u16>, Vec<u16>>::from_data_bytes(
|
||||||
bytes,
|
bytes,
|
||||||
if_zero_adjust(dimensions.into(), len),
|
dimensions.into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageRgba16(dimensions) => {
|
cli::OutputFormat::ImageRgba16(dimensions) => {
|
||||||
let len = bytes.len();
|
|
||||||
Image::<Rgba<u16>, Vec<u16>>::from_data_bytes(
|
Image::<Rgba<u16>, Vec<u16>>::from_data_bytes(
|
||||||
bytes,
|
bytes,
|
||||||
if_zero_adjust(dimensions.into(), len),
|
dimensions.into(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)
|
)
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageRgb32F(dimensions) => {
|
cli::OutputFormat::ImageRgb32F(dimensions) => {
|
||||||
let len = bytes.len();
|
Rgb32FImage::from_data_bytes(bytes, dimensions.into(), Default::default())
|
||||||
Rgb32FImage::from_data_bytes(
|
|
||||||
bytes,
|
|
||||||
if_zero_adjust(dimensions.into(), len),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::ImageRgba32F(dimensions) => {
|
cli::OutputFormat::ImageRgba32F(dimensions) => {
|
||||||
let len = bytes.len();
|
Rgba32FImage::from_data_bytes(bytes, dimensions.into(), Default::default())
|
||||||
Rgba32FImage::from_data_bytes(
|
|
||||||
bytes,
|
|
||||||
if_zero_adjust(dimensions.into(), len),
|
|
||||||
Default::default(),
|
|
||||||
)
|
|
||||||
.save(file)
|
.save(file)
|
||||||
.context("writing image data to output file")?
|
.context("writing image data to output file")?
|
||||||
}
|
}
|
||||||
cli::OutputFormat::Bytes => {
|
|
||||||
File::bend_from(bytes, Box::new(file), Default::default())
|
|
||||||
.context("writing to file")?;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
cli::FileOrStd::Std(_) => Stdout::new()
|
cli::FileOrStd::Std(_) => Stdout::new()
|
||||||
.write_all(&bytes)
|
.write_all(&mut bytes)
|
||||||
.context("writing to stdout")?,
|
.context("writing to stdout")?,
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn if_zero_adjust(dimensions: Dimensions, bytes_len: usize) -> Dimensions {
|
|
||||||
if dimensions == Dimensions::square(0) {
|
|
||||||
Dimensions::square((bytes_len / 3).isqrt() as u32)
|
|
||||||
} else if dimensions.width == 0 {
|
|
||||||
Dimensions::square(dimensions.height)
|
|
||||||
} else if dimensions.height == 0 {
|
|
||||||
Dimensions::square(dimensions.width)
|
|
||||||
} else {
|
|
||||||
dimensions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue