From 6108b2dd35ec0e54b2c73344418b1e221a3834f2 Mon Sep 17 00:00:00 2001
From: Stephen <webmaster@scd31.com>
Date: Fri, 21 Apr 2023 22:04:12 -0300
Subject: [PATCH] use minor jpeg compression even with HQ images

---
 src/control.rs | 14 ++++----------
 src/img.rs     | 43 +++++++++++--------------------------------
 src/ssdv.rs    | 11 ++---------
 3 files changed, 17 insertions(+), 51 deletions(-)

diff --git a/src/control.rs b/src/control.rs
index 7a21b0e..5cff55f 100644
--- a/src/control.rs
+++ b/src/control.rs
@@ -36,8 +36,8 @@ impl Controller {
         let mut manager = ImgManager::new(self.config.paths.clone(), cmd_rx);
 
         loop {
-            while let Some((idx, bytes, lossless)) = manager.next() {
-                if let Err(e) = self.process_image(&bytes, idx, &img_tx, lossless) {
+            while let Some((idx, bytes)) = manager.next() {
+                if let Err(e) = self.process_image(&bytes, idx, &img_tx) {
                     eprintln!("Error processing image: {e}");
                 }
             }
@@ -48,14 +48,8 @@ impl Controller {
         }
     }
 
-    fn process_image(
-        &self,
-        img: &[u8],
-        idx: u8,
-        tx: &SyncSender<FecPacket>,
-        lossless: bool,
-    ) -> anyhow::Result<()> {
-        for p in ssdv_encode(&self.config.callsign, img, idx, lossless)? {
+    fn process_image(&self, img: &[u8], idx: u8, tx: &SyncSender<FecPacket>) -> anyhow::Result<()> {
+        for p in ssdv_encode(&self.config.callsign, img, idx)? {
             tx.send(p.into()).context("TX thread died")?;
         }
 
diff --git a/src/img.rs b/src/img.rs
index c94d71b..16efd83 100644
--- a/src/img.rs
+++ b/src/img.rs
@@ -2,6 +2,7 @@ use image::{imageops::FilterType, io::Reader as ImageReader, ImageOutputFormat};
 use std::{fs, io::Cursor, path::PathBuf, sync::mpsc::Receiver};
 
 const IMG_DIM: u32 = 1024;
+const IMG_MAX_SIZE: u32 = 2048;
 const JPEG_QUALITY: u8 = 100; // let ssdv do the compression
 
 #[derive(Debug)]
@@ -17,21 +18,10 @@ impl ImgInfo {
     pub fn compressed_jpeg_bytes(&self) -> anyhow::Result<Vec<u8>> {
         let img = ImageReader::open(&self.path)?.decode()?;
 
-        // want a 512x512 image
-        // first - resize so that the smaller dimension is 512x512
-        let img = if img.width() > img.height() {
-            img.resize(10_000, IMG_DIM, FilterType::Triangle)
-        } else {
-            img.resize(IMG_DIM, 10_000, FilterType::Triangle)
-        };
-
-        // second - crop to 512x512
-        let img = img.crop_imm(
-            (img.width() - IMG_DIM) / 2,
-            (img.height() - IMG_DIM) / 2,
-            IMG_DIM,
-            IMG_DIM,
-        );
+        // want a imagine that's 512 on one side
+        // resize so that the larger dimension is 512
+        // TODO make this better. needs to be smaller than IMG_DIM but still % 16 on both sides
+        let img = img.resize(IMG_DIM, IMG_DIM, FilterType::Triangle);
 
         let mut bytes = vec![];
 
@@ -47,21 +37,10 @@ impl ImgInfo {
     pub fn lossless_jpeg_bytes(&self) -> anyhow::Result<Vec<u8>> {
         let img = ImageReader::open(&self.path)?.decode()?;
 
-        // turn image into a square, making it bigger in the process
-        // must be divisible by 16
-        let mut dim = img.width().max(img.height());
-        let offset = dim % 16;
-        dim += (16 - offset) % 16;
-
-        img.crop_imm(0, 0, dim, dim);
+        let img = img.resize(IMG_MAX_SIZE, IMG_MAX_SIZE, FilterType::Lanczos3);
 
         let mut bytes = vec![];
-
-        img.write_to(
-            &mut Cursor::new(&mut bytes),
-            ImageOutputFormat::Jpeg(JPEG_QUALITY),
-        )?;
-
+        img.write_to(&mut Cursor::new(&mut bytes), ImageOutputFormat::Jpeg(100))?;
         Ok(bytes)
     }
 }
@@ -101,7 +80,7 @@ impl ImgManager {
     // not making this an iterator since
     // it's entirely valid to have a Some(...)
     // after a None
-    pub fn next(&mut self) -> Option<(u8, Vec<u8>, bool)> {
+    pub fn next(&mut self) -> Option<(u8, Vec<u8>)> {
         loop {
             if let Ok(req) = self.rx.try_recv() {
                 let img = self
@@ -111,7 +90,7 @@ impl ImgManager {
                     .and_then(|img| img.lossless_jpeg_bytes().ok());
 
                 if let Some(img) = img {
-                    return Some((self.inc_tx(None), img, true));
+                    return Some((self.inc_tx(None), img));
                 }
             }
 
@@ -142,7 +121,7 @@ impl ImgManager {
                 // not perfect. ideally we would keep looking through the new images
                 // if this Err'd
                 if let Ok(x) = bytes {
-                    return Some((self.inc_tx(Some(new_id)), x, false));
+                    return Some((self.inc_tx(Some(new_id)), x));
                 }
             }
 
@@ -162,7 +141,7 @@ impl ImgManager {
                 self.inc_iter(true);
 
                 if let Ok(x) = bytes {
-                    return Some((self.inc_tx(Some(old_idx)), x, false));
+                    return Some((self.inc_tx(Some(old_idx)), x));
                 }
             }
 
diff --git a/src/ssdv.rs b/src/ssdv.rs
index b9b3bae..63784d3 100644
--- a/src/ssdv.rs
+++ b/src/ssdv.rs
@@ -4,14 +4,7 @@ use crate::packet::RawPacket;
 
 // TODO eventually rewrite Ssdv in Rust?
 // Don't want to use FFI because then segfaults can hurt us
-pub fn ssdv_encode(
-    callsign: &str,
-    img: &[u8],
-    img_idx: u8,
-    lossless: bool,
-) -> anyhow::Result<Vec<RawPacket>> {
-    let quality = if lossless { "7" } else { "6" };
-
+pub fn ssdv_encode(callsign: &str, img: &[u8], img_idx: u8) -> anyhow::Result<Vec<RawPacket>> {
     let (stdout, stderr) = subprocess::Exec::cmd("ssdv")
         .args(&[
             "-e",
@@ -19,7 +12,7 @@ pub fn ssdv_encode(
             callsign,
             "-n",
             "-q",
-            quality,
+            "6",
             "-i",
             &format!("{}", img_idx),
         ])
-- 
GitLab