Skip to content

Commit

Permalink
simplify interface for mobile use
Browse files Browse the repository at this point in the history
  • Loading branch information
o-tho committed Dec 2, 2024
1 parent 9cc8efd commit 92dea20
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 110 deletions.
272 changes: 164 additions & 108 deletions src/webapp/generate_report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,87 +99,53 @@ fn raw_data_to_container(data: &Vec<u8>) -> Option<Box<dyn ImageContainer + '_>>
}

impl GenerateReport {
pub async fn generate_reports(&mut self) {
let template = self.template.clone().unwrap();
let key = self.key.clone().unwrap();

if let Some(container_data) = self.raw_container_data.clone() {
let _ = async move {
let mut zip_buffer = Cursor::new(Vec::new());
let mut zip_writer = ZipWriter::new(&mut zip_buffer);
let mut csv_writer = csv::Writer::from_writer(std::io::Cursor::new(Vec::new()));
let _ = csv_writer.write_record(["Filename", "ID", "Score"]);

log::info!("Output files are set up, starting to iterate over the input images!");

let mut container = raw_data_to_container(&container_data).unwrap();
let iterator = container.to_iter();

let mut turn = 0;
let chunksize = 20;

log::info!(
"Working on images {}-{}",
turn * chunksize,
(turn + 1) * chunksize
);
*self.status.borrow_mut() =
Some(format!("Working on the first {} scans", chunksize));
gloo_timers::future::TimeoutFuture::new(50).await;
for chunk in &iterator.chunks(chunksize) {
let images: Vec<image::GrayImage> = chunk.collect();
let results: Vec<ImageReport> = images
.iter()
.enumerate()
.map(|(idx, img)| {
log::info!("processing {}", turn * chunksize + idx);
let mut scan = Scan {
img: img.clone(),
transformation: None,
};
scan.transformation = scan.find_transformation(&template);
scan.generate_imagereport(
&template,
&key,
&format!("page{}", idx + turn * chunksize),
)
})
.collect();

for r in &results {
let _ = r.add_to_zip(&mut zip_writer, &mut csv_writer);
}
fn simplified_update_view(&mut self, ctx: &Context) {
egui::CentralPanel::default().show(ctx, |ui| {
upload_button(
ui,
&ctx,
"📂 Upload Image",
FileType::Container,
self.data_channel.0.clone(),
);

if self.preview_image.borrow().is_none() {
*self.preview_image.borrow_mut() = Some(results[0].image.clone());
}
if self.raw_container_data.is_some() && self.preview_texture.is_none() {
if let Some(mut container) =
raw_data_to_container(&self.raw_container_data.clone().unwrap())
{
let img = container.to_iter().next().expect("could not open image");

turn += 1;
*self.status.borrow_mut() =
Some(format!("processed {} scans", turn * chunksize));
gloo_timers::future::TimeoutFuture::new(100).await;
let mut scan = Scan {
img: img.clone(),
transformation: None,
};
scan.transformation = scan.find_transformation(&self.template.clone().unwrap());
let report = scan.generate_imagereport(
&self.template.clone().unwrap(),
&self.key.clone().unwrap(),
&String::new(),
);
*self.preview_image.borrow_mut() = Some(report.image.clone());
*self.status.borrow_mut() = Some(format!(
"{} points (version {}, student ID {})",
report.score,
report.version.unwrap_or(0) + 1,
report.sid.unwrap_or(0)
));
}
}

let csv_data = csv_writer.into_inner().unwrap().into_inner();
let _ = zip_writer.start_file::<String, ()>(
"results.csv".to_string(),
FileOptions::default().compression_method(zip::CompressionMethod::Deflated),
);
let _ = zip_writer.write_all(&csv_data);

let _ = zip_writer.finish();

log::info!("The thing has been done!");

*self.zipped_results.borrow_mut() = Some(zip_buffer.into_inner());
if let Some(status) = &*self.status.borrow() {
ui.label(status);
}
.await;
}
if let Some(texture) = &self.preview_texture {
egui::ScrollArea::both().show(ui, |ui| {
ui.add(egui::Image::new(texture));
});
}
});
}
}

impl eframe::App for GenerateReport {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
fn full_update_view(&mut self, ctx: &Context) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.columns(5, |columns| {
columns[0].vertical(|ui| {
Expand Down Expand Up @@ -256,50 +222,140 @@ impl eframe::App for GenerateReport {
});
});

// check if we need to create the texture
if self.preview_image.borrow().is_some() && self.preview_texture.is_none() {
log::info!("creating texture");
let display =
rgb_to_egui_color_image(&self.preview_image.borrow().clone().unwrap());
self.preview_texture = Some(ui.ctx().load_texture(
"displayed_image",
display,
egui::TextureOptions::default(),
));
}

if let Some(texture) = &self.preview_texture {
egui::ScrollArea::both().show(ui, |ui| {
ui.add(egui::Image::new(texture));
});
}
});
}

// Handle incoming file data and deserialize as needed
while let Ok((file_type, data)) = self.data_channel.1.try_recv() {
match file_type {
FileType::Template => {
if let Ok(template) = serde_json::from_slice::<Template>(&data) {
self.template = Some(template);
log::info!("loaded template");
} else {
log::error!("could not parse template");
}
pub async fn generate_reports(&mut self) {
let template = self.template.clone().unwrap();
let key = self.key.clone().unwrap();

if let Some(container_data) = self.raw_container_data.clone() {
let _ = async move {
let mut zip_buffer = Cursor::new(Vec::new());
let mut zip_writer = ZipWriter::new(&mut zip_buffer);
let mut csv_writer = csv::Writer::from_writer(std::io::Cursor::new(Vec::new()));
let _ = csv_writer.write_record(["Filename", "ID", "Score"]);

log::info!("Output files are set up, starting to iterate over the input images!");

let mut container = raw_data_to_container(&container_data).unwrap();
let iterator = container.to_iter();

let mut turn = 0;
let chunksize = 20;

log::info!(
"Working on images {}-{}",
turn * chunksize,
(turn + 1) * chunksize
);
*self.status.borrow_mut() =
Some(format!("Working on the first {} scans", chunksize));
gloo_timers::future::TimeoutFuture::new(50).await;
for chunk in &iterator.chunks(chunksize) {
let images: Vec<image::GrayImage> = chunk.collect();
let results: Vec<ImageReport> = images
.iter()
.enumerate()
.map(|(idx, img)| {
log::info!("processing {}", turn * chunksize + idx);
let mut scan = Scan {
img: img.clone(),
transformation: None,
};
scan.transformation = scan.find_transformation(&template);
scan.generate_imagereport(
&template,
&key,
&format!("page{}", idx + turn * chunksize),
)
})
.collect();

for r in &results {
let _ = r.add_to_zip(&mut zip_writer, &mut csv_writer);
}
FileType::Key => {
if let Ok(key) = serde_json::from_slice::<ExamKey>(&data) {
self.key = Some(key);
log::info!("loaded key");
} else {
log::error!("could not parse template");
}

if self.preview_image.borrow().is_none() {
*self.preview_image.borrow_mut() = Some(results[0].image.clone());
}
FileType::Container => {
log::info!("uploaded data");
self.raw_container_data = Some(data);

turn += 1;
*self.status.borrow_mut() =
Some(format!("processed {} scans", turn * chunksize));
gloo_timers::future::TimeoutFuture::new(100).await;
}

let csv_data = csv_writer.into_inner().unwrap().into_inner();
let _ = zip_writer.start_file::<String, ()>(
"results.csv".to_string(),
FileOptions::default().compression_method(zip::CompressionMethod::Deflated),
);
let _ = zip_writer.write_all(&csv_data);

let _ = zip_writer.finish();

log::info!("The thing has been done!");

*self.zipped_results.borrow_mut() = Some(zip_buffer.into_inner());
}
.await;
}
}
}

impl eframe::App for GenerateReport {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
// Handle incoming file data and deserialize as needed
while let Ok((file_type, data)) = self.data_channel.1.try_recv() {
match file_type {
FileType::Template => {
if let Ok(template) = serde_json::from_slice::<Template>(&data) {
self.template = Some(template);
log::info!("loaded template");
} else {
log::error!("could not parse template");
}
}
FileType::Key => {
if let Ok(key) = serde_json::from_slice::<ExamKey>(&data) {
self.key = Some(key);
log::info!("loaded key");
} else {
log::error!("could not parse template");
}
_ => {}
}
FileType::Container => {
log::info!("uploaded data");
self.raw_container_data = Some(data);
}
_ => {}
}
} // check if we need to create the texture
if self.preview_image.borrow().is_some() && self.preview_texture.is_none() {
log::info!("creating texture");
let display = rgb_to_egui_color_image(&self.preview_image.borrow().clone().unwrap());
self.preview_texture =
Some(ctx.load_texture("displayed_image", display, egui::TextureOptions::default()));
}

let window = web_sys::window().expect("could not get window");
let dimensions = window.inner_width().and_then(|x| {
window.inner_height().and_then(|y| {
let x_pixels = x.as_f64().ok_or(wasm_bindgen::JsValue::NULL)?;
let y_pixels = y.as_f64().ok_or(wasm_bindgen::JsValue::NULL)?;
Ok((x_pixels, y_pixels))
})
});

match dimensions {
Ok((x, y)) if x < y => self.simplified_update_view(ctx),
_ => self.full_update_view(ctx),
}
}
}
1 change: 0 additions & 1 deletion src/webapp/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ pub fn decode_key_template(
use base64_url::decode;
use snap::raw::Decoder;
let decoded = decode(encoded)?;
log::info!("decoded");

let mut decoder = Decoder::new();
let decompressed = decoder.decompress_vec(&decoded)?;
Expand Down
2 changes: 1 addition & 1 deletion src/webapp/webapp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl eframe::App for WebApp {
fn update(&mut self, ctx: &Context, frame: &mut eframe::Frame) {
let location = web_sys::window().expect("huge websys error").location();

if !location.hash().unwrap().is_empty() {
if !location.hash().unwrap().is_empty() && self.generate_report.template.is_none() {
let result = decode_key_template(&location.hash().unwrap().as_str()[1..]);
if let Ok((key, template)) = result {
self.current_view = ViewType::GenerateReport;
Expand Down

0 comments on commit 92dea20

Please sign in to comment.