Skip to content

Commit

Permalink
feat(cli): added mozjpeg codec
Browse files Browse the repository at this point in the history
  • Loading branch information
SalOne22 committed Mar 16, 2024
1 parent 5a2c2f9 commit 37359e2
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/cli/codecs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
use clap::Command;

use self::{farbfeld::farbfeld, jpeg::jpeg, jpeg_xl::jpeg_xl, png::png, ppm::ppm, qoi::qoi};
use self::{
farbfeld::farbfeld, jpeg::jpeg, jpeg_xl::jpeg_xl, mozjpeg::mozjpeg, png::png, ppm::ppm,
qoi::qoi,
};

mod farbfeld;
mod jpeg;
mod jpeg_xl;
mod mozjpeg;
mod png;
mod ppm;
mod qoi;

impl Codecs for Command {
fn codecs(self) -> Self {
self.subcommands([farbfeld(), jpeg(), jpeg_xl(), png(), ppm(), qoi()])
self.subcommands([
farbfeld(),
jpeg(),
jpeg_xl(),
mozjpeg(),
png(),
ppm(),
qoi(),
])
}
}

Expand Down
37 changes: 37 additions & 0 deletions src/cli/codecs/mozjpeg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use clap::{arg, value_parser, Command};

pub fn mozjpeg() -> Command {
Command::new("mozjpeg")
.alias("moz")
.about("Encode images into JPEG format using MozJpeg codec")
.args([
arg!(-q --quality <NUM> "Quality, values 60-80 are recommended")
.value_parser(value_parser!(u8).range(1..=100))
.default_value("75"),
arg!(--chroma_quality <NUM> "Separate chrome quality")
.value_parser(value_parser!(u8).range(1..=100)),
arg!(--baseline "Set to use baseline encoding (by default is progressive)"),
arg!(--no_optimize_coding "Set to make files larger for no reason"),
arg!(--smoothing <NUM> "Use MozJPEG's smoothing")
.value_parser(value_parser!(u8).range(1..=100)),
arg!(--colorspace <COLOR> "Set color space of JPEG being written")
.value_parser(["ycbcr", "grayscale", "rgb"])
.default_value("ycbcr"),
arg!(--multipass "Specifies whether multiple scans should be considered during trellis quantization"),
arg!(--subsample <PIX> "Sets chroma subsampling")
.value_parser(value_parser!(u8).range(1..=4)),
arg!(--qtable <TABLE> "Use a specific quantization table")
.value_parser([
"AhumadaWatsonPeterson",
"AnnexK",
"Flat",
"KleinSilversteinCarney",
"MSSSIM",
"NRobidoux",
"PSNRHVS",
"PetersonAhumadaWatson",
"WatsonTaylorBorthwick"
])
.default_value("NRobidoux")
])
}
80 changes: 80 additions & 0 deletions src/cli/pipeline.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{collections::BTreeMap, fs::read, path::Path};

use clap::ArgMatches;
use mozjpeg::qtable;
use rimage::codecs::mozjpeg::{MozJpegEncoder, MozJpegOptions};
use zune_core::{bytestream::ZByteReader, options::EncoderOptions};
use zune_image::{
codecs::{
Expand Down Expand Up @@ -131,6 +133,84 @@ pub fn encoder(matches: &ArgMatches) -> Result<(Box<dyn EncoderTrait>, &'static
Ok((Box::new(JpegEncoder::new_with_options(options)), "jpg"))
}
"jpeg_xl" => Ok((Box::new(JxlEncoder::new()), "jxl")),
"mozjpeg" => {
let quality = *matches.get_one::<u8>("quality").unwrap() as f32;
let chroma_quality = matches
.get_one::<u8>("chroma_quality")
.map(|q| *q as f32)
.unwrap_or(quality);

let options = MozJpegOptions {
quality,
progressive: !matches.get_flag("baseline"),
optimize_coding: !matches.get_flag("no_optimize_coding"),
smoothing: matches
.get_one::<u8>("smoothing")
.copied()
.unwrap_or_default(),
color_space: match matches.get_one::<String>("colorspace").unwrap().as_str() {
"ycbcr" => mozjpeg::ColorSpace::JCS_YCbCr,
"rgb" => mozjpeg::ColorSpace::JCS_EXT_RGB,
"grayscale" => mozjpeg::ColorSpace::JCS_GRAYSCALE,
_ => unreachable!(),
},
trellis_multipass: matches.get_flag("multipass"),
chroma_subsample: matches.get_one::<u8>("subsample").copied(),

luma_qtable: matches
.get_one::<String>("qtable")
.map(|c| match c.as_str() {
"AhumadaWatsonPeterson" => {
qtable::AhumadaWatsonPeterson.scaled(quality, quality)
}
"AnnexK" => qtable::AnnexK_Luma.scaled(quality, quality),
"Flat" => qtable::Flat.scaled(quality, quality),
"KleinSilversteinCarney" => {
qtable::KleinSilversteinCarney.scaled(quality, quality)
}
"MSSSIM" => qtable::MSSSIM_Luma.scaled(quality, quality),
"NRobidoux" => qtable::NRobidoux.scaled(quality, quality),
"PSNRHVS" => qtable::PSNRHVS_Luma.scaled(quality, quality),
"PetersonAhumadaWatson" => {
qtable::PetersonAhumadaWatson.scaled(quality, quality)
}
"WatsonTaylorBorthwick" => {
qtable::WatsonTaylorBorthwick.scaled(quality, quality)
}
_ => unreachable!(),
}),

chroma_qtable: matches
.get_one::<String>("qtable")
.map(|c| match c.as_str() {
"AhumadaWatsonPeterson" => {
qtable::AhumadaWatsonPeterson.scaled(chroma_quality, chroma_quality)
}
"AnnexK" => {
qtable::AnnexK_Chroma.scaled(chroma_quality, chroma_quality)
}
"Flat" => qtable::Flat.scaled(chroma_quality, chroma_quality),
"KleinSilversteinCarney" => qtable::KleinSilversteinCarney
.scaled(chroma_quality, chroma_quality),
"MSSSIM" => {
qtable::MSSSIM_Chroma.scaled(chroma_quality, chroma_quality)
}
"NRobidoux" => qtable::NRobidoux.scaled(chroma_quality, chroma_quality),
"PSNRHVS" => {
qtable::PSNRHVS_Chroma.scaled(chroma_quality, chroma_quality)
}
"PetersonAhumadaWatson" => {
qtable::PetersonAhumadaWatson.scaled(chroma_quality, chroma_quality)
}
"WatsonTaylorBorthwick" => {
qtable::WatsonTaylorBorthwick.scaled(chroma_quality, chroma_quality)
}
_ => unreachable!(),
}),
};

Ok((Box::new(MozJpegEncoder::new_with_options(options)), "jpg"))
}
"png" => Ok((Box::new(PngEncoder::new()), "png")),
"ppm" => Ok((Box::new(PPMEncoder::new()), "ppm")),
"qoi" => Ok((Box::new(QoiEncoder::new()), "qoi")),
Expand Down

0 comments on commit 37359e2

Please sign in to comment.