download pictures in the frontend and then create data-urls from blobs

This commit is contained in:
Johannes Heuel
2023-03-08 15:03:36 +01:00
parent fbcea9e77b
commit db2bf1994e
14 changed files with 500 additions and 165 deletions

View File

@@ -30,6 +30,8 @@ lazy_static = "1.4"
parking_lot = "0.12"
dotenv = "0.15.0"
dotenv_codegen = "0.15.0"
kamadak-exif = "0.5.5"
image-meta = "0.1.2"
[features]
default = []

View File

@@ -5,7 +5,7 @@ function getFilesDataTransferItems(dataTransferItems) {
// nothing to do
} else if (item.isFile) {
item.file(file => {
file.filepath = path + "/" + file.name; //save full path
file.filepath = path + file.name; //save full path
folder.push(file);
resolve(file);
});
@@ -17,7 +17,7 @@ function getFilesDataTransferItems(dataTransferItems) {
folder.push({ name: item.name, subfolder: subfolder });
for (let entry of entries)
entriesPromises.push(
traverseFileTreePromise(entry, path + "/" + item.name, subfolder)
traverseFileTreePromise(entry, path + "/" + item.name + "/", subfolder)
);
resolve(Promise.all(entriesPromises));
});

View File

@@ -1,3 +1,5 @@
use std::io::Cursor;
use super::BasePage;
use crate::gallery::Grid;
use crate::hooks::use_user_context;
@@ -16,6 +18,10 @@ use yew_hooks::prelude::*;
use common::OutputPicture;
pub struct MetaData {
width: u32,
height: u32,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct PhotosWrapper {
photos: Vec<String>,
@@ -25,6 +31,17 @@ pub struct PhotosUrlsWrapper {
photos: Vec<(String, String)>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct DetailPhoto {
key: String,
width: u32,
height: u32,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct DetailPhotoWrapper {
photos: Vec<DetailPhoto>,
}
#[function_component(Home)]
pub fn home() -> Html {
let user_ctx = use_user_context();
@@ -39,7 +56,7 @@ pub fn home() -> Html {
use_effect_with_deps(
move |_| {
wasm_bindgen_futures::spawn_local(async move {
let url = "/api/pictures/";
let url = "/api/photos/get";
let fetched_pictures: Vec<OutputPicture> = Request::get(url)
.send()
.await
@@ -118,7 +135,9 @@ pub fn home() -> Html {
console_log!("end", uiae.join("\n"));
let photos: PhotosUrlsWrapper = Request::post("/api/photos/upload")
.json(&PhotosWrapper { photos: uiae })
.json(&PhotosWrapper {
photos: uiae.clone(),
})
.unwrap()
.send()
.await
@@ -128,19 +147,48 @@ pub fn home() -> Html {
.unwrap();
console_log!("{}", serde_json::to_string(&photos).unwrap());
let mut metadata: Vec<MetaData> = Vec::new();
let mut promises: Vec<Promise> = Vec::new();
for (file, (_, url)) in files.iter().zip(photos.photos) {
for (file, (key, url)) in files.iter().zip(photos.photos) {
console_log!("uploading: ", &file.name(), &url);
let promise = read_file(file.clone());
if let Ok(content) = wasm_bindgen_futures::JsFuture::from(promise).await {
let buffer: ArrayBuffer = content.dyn_into().unwrap();
let typed_buffer: js_sys::Uint8Array = js_sys::Uint8Array::new(&buffer);
let mut buf = vec![0; typed_buffer.length() as usize];
typed_buffer.copy_to(&mut buf[..]);
console_log!(
serde_json::to_string(&buf.len()).unwrap(),
serde_json::to_string(&buf).unwrap()
);
typed_buffer.copy_to(&mut buf);
// console_log!(
// serde_json::to_string(&buf.len()).unwrap(),
// serde_json::to_string(&buf).unwrap()
// );
let mut md = MetaData {
width: 0,
height: 0,
};
let meta = image_meta::load_from_buf(&buf).unwrap();
console_log!(format!(
"dims: {}x{}",
meta.dimensions.width, meta.dimensions.height
));
console_log!(format!("animation: {:?}", meta.is_animation()));
console_log!(format!("format: {:?}", meta.format));
md.height = meta.dimensions.height;
md.width = meta.dimensions.width;
let exifreader = exif::Reader::new();
let mut cursor = Cursor::new(&buf);
if let Ok(exif) = exifreader.read_from_container(&mut cursor) {
for f in exif.fields() {
console_log!(format!(
"{} {} {}",
f.tag,
f.ifd_num,
f.display_value().with_unit(&exif)
));
}
}
metadata.push(md);
promises.push(upload(buffer, file.type_(), url.clone()));
}
}
@@ -152,6 +200,25 @@ pub fn home() -> Html {
};
}
let photos: DetailPhotoWrapper = Request::post("/api/photos/upload/done")
.json(&DetailPhotoWrapper {
photos: uiae
.iter()
.zip(metadata)
.map(|(p, md)| DetailPhoto {
key: p.clone(),
width: md.width,
height: md.height,
})
.collect(),
})
.unwrap()
.send()
.await
.unwrap()
.json()
.await
.unwrap();
console_log!("all uploaded");
});
});

View File

@@ -16,7 +16,7 @@ pub struct GridProps {
#[function_component(Grid)]
pub fn grid(props: &GridProps) -> Html {
let target_height = 100;
let target_height = 200;
let container_width = if props.width == 0 { 0 } else { props.width - 4 };
let margin = 2;
if container_width == 0 {
@@ -54,6 +54,7 @@ pub fn grid(props: &GridProps) -> Html {
"display: flex;",
"flex-wrap: wrap;",
"flex-direction: row;",
"min-height: 10vh",
)}>
{ props.pictures.iter().zip(dimensions).map(|(p, d)|
html!{

View File

@@ -1,4 +1,8 @@
use common::OutputPicture;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::{window, Blob, HtmlElement, Request, RequestInit, Response, Url};
use weblog::console_log;
use yew::prelude::*;
#[derive(Clone, Debug, Properties, PartialEq)]
@@ -19,9 +23,42 @@ pub fn picture(props: &PictureProps) -> Html {
let margin = props.margin.to_string();
let width = props.width.to_string();
let height = props.height.to_string();
let node = use_node_ref();
{
let node = node.clone();
use_effect_with_deps(
move |_| {
wasm_bindgen_futures::spawn_local(async move {
let mut opts = RequestInit::new();
opts.method("GET");
let request = Request::new_with_str_and_init(&thumb, &opts).unwrap();
let window = web_sys::window().unwrap();
let resp = JsFuture::from(window.fetch_with_request(&request))
.await
.unwrap();
let resp: Response = resp.dyn_into().unwrap();
let blob: Blob = JsFuture::from(resp.blob().unwrap())
.await
.unwrap()
.dyn_into()
.unwrap();
let url = Url::create_object_url_with_blob(&blob).unwrap();
if let Some(element) = node.cast::<HtmlElement>() {
element.set_attribute("src", &url);
}
});
|| ()
},
(),
);
}
html! {
<>
<img style={format!("margin: {}px; display: block;", margin)} src={thumb} width={width} height={height} />
<img ref={node} style={format!("margin: {}px; display: block;", margin)} width={width} height={height} />
</>
}
}