@@ -1,6 +1,7 @@
|
||||
pub mod routes;
|
||||
|
||||
use std::{
|
||||
cmp::max,
|
||||
collections::VecDeque,
|
||||
iter::Iterator,
|
||||
sync::{
|
||||
@@ -232,3 +233,15 @@ pub fn generate_path_dto(
|
||||
|
||||
get_path
|
||||
}
|
||||
|
||||
fn resize_dimensions(width: u32, height: u32) -> (u32, u32) {
|
||||
let wratio = 300.0 / width as f64;
|
||||
let hratio = 300.0 / height as f64;
|
||||
|
||||
let ratio = f64::min(wratio, hratio);
|
||||
|
||||
(
|
||||
max((width as f64 * ratio).round() as u64, 1) as u32,
|
||||
max((height as f64 * ratio).round() as u64, 1) as u32
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,14 @@ use std::{
|
||||
collections::{BTreeSet, HashMap},
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
num::NonZeroU32,
|
||||
ops::DerefMut,
|
||||
sync::atomic::Ordering
|
||||
};
|
||||
use image::DynamicImage;
|
||||
|
||||
use fast_image_resize as fir;
|
||||
use fast_image_resize::PixelType;
|
||||
use rustracing_jaeger::Span;
|
||||
use tiny_http::{Request, Response, ResponseBox, StatusCode};
|
||||
|
||||
@@ -15,7 +19,7 @@ use crate::{
|
||||
dto,
|
||||
header,
|
||||
metrics,
|
||||
routes::{filters::UserInfo, get_reply, AppError, ChannelReader}
|
||||
routes::{filters::UserInfo, fs::resize_dimensions, get_reply, AppError, ChannelReader}
|
||||
};
|
||||
|
||||
pub fn root(_: &Span, _: &mut Request, _: &mut DBConnection, info: UserInfo) -> Result<ResponseBox, AppError> {
|
||||
@@ -164,6 +168,7 @@ pub fn upload(
|
||||
|
||||
let mut file_size = 0_i64;
|
||||
let file_name = format!("./files/{}", node.id);
|
||||
let mut file_buf = Vec::<u8>::new();
|
||||
{
|
||||
let _span = metrics::span("receive_file", span);
|
||||
let mut buf = vec![0_u8; 8 * 1024 * 1024];
|
||||
@@ -176,6 +181,9 @@ pub fn upload(
|
||||
if r == 0 {
|
||||
break;
|
||||
}
|
||||
if file_size < 20 * 1024 * 1024 {
|
||||
file_buf.write_all(&buf[..r]).unwrap();
|
||||
}
|
||||
file.write_all(&buf[..r]).unwrap();
|
||||
file_size += r as i64;
|
||||
}
|
||||
@@ -185,19 +193,73 @@ pub fn upload(
|
||||
.with_label_values(&[node.owner_id.to_string().as_str()])
|
||||
.add(file_size - node.size.unwrap_or(0));
|
||||
{
|
||||
let _span = metrics::span("generate_preview", span);
|
||||
let prev_span = metrics::span("generate_preview", span);
|
||||
node.has_preview = (|| {
|
||||
if file_size > 20 * 1024 * 1024 {
|
||||
if file_size > file_buf.len() as i64 {
|
||||
return None;
|
||||
}
|
||||
let mime = mime_guess::from_path(std::path::Path::new(&node.name)).first()?.to_string();
|
||||
let img = image::load(
|
||||
std::io::BufReader::new(File::open(file_name.clone()).unwrap()),
|
||||
image::ImageFormat::from_mime_type(mime)?
|
||||
)
|
||||
.ok()?;
|
||||
let img = img.resize(300, 300, image::imageops::FilterType::Triangle);
|
||||
img.save(std::path::Path::new(&(file_name + "_preview.jpg"))).expect("Failed to save preview image");
|
||||
let img = {
|
||||
let _span = metrics::span("generate_preview_load", &prev_span);
|
||||
image::load_from_memory_with_format(
|
||||
file_buf.as_slice(),
|
||||
image::ImageFormat::from_mime_type(mime)?
|
||||
)
|
||||
.ok()?
|
||||
};
|
||||
let img = {
|
||||
let _span = metrics::span("generate_preview_convert", &prev_span);
|
||||
let width = NonZeroU32::try_from(img.width()).unwrap();
|
||||
let height = NonZeroU32::try_from(img.height()).unwrap();
|
||||
match img {
|
||||
DynamicImage::ImageLuma8(v) => fir::Image::from_vec_u8(width, height, v.into_raw(), fir::PixelType::U8),
|
||||
DynamicImage::ImageLumaA8(v) => fir::Image::from_vec_u8(width, height, v.into_raw(), fir::PixelType::U8x2),
|
||||
DynamicImage::ImageRgb8(v) => fir::Image::from_vec_u8(width, height, v.into_raw(), fir::PixelType::U8x3),
|
||||
DynamicImage::ImageRgba8(v) => fir::Image::from_vec_u8(width, height, v.into_raw(), fir::PixelType::U8x4),
|
||||
DynamicImage::ImageLuma16(_) => fir::Image::from_vec_u8(width, height, img.to_luma8().into_raw(), fir::PixelType::U8),
|
||||
DynamicImage::ImageLumaA16(_) => fir::Image::from_vec_u8(width, height, img.to_luma_alpha8().into_raw(), fir::PixelType::U8x2),
|
||||
DynamicImage::ImageRgb16(_) => fir::Image::from_vec_u8(width, height, img.to_rgb8().into_raw(), fir::PixelType::U8x3),
|
||||
DynamicImage::ImageRgba16(_) => fir::Image::from_vec_u8(width, height, img.to_rgba8().into_raw(), fir::PixelType::U8x4),
|
||||
DynamicImage::ImageRgb32F(_) => fir::Image::from_vec_u8(width, height, img.to_rgb8().into_raw(), fir::PixelType::U8x3),
|
||||
DynamicImage::ImageRgba32F(_) => fir::Image::from_vec_u8(width, height, img.to_rgba8().into_raw(), fir::PixelType::U8x4),
|
||||
_ => fir::Image::from_vec_u8(width, height, img.to_rgba8().into_raw(), fir::PixelType::U8x4)
|
||||
}.expect("Failed to convert preview image")
|
||||
};
|
||||
let img = {
|
||||
let _span = metrics::span("generate_preview_resize", &prev_span);
|
||||
let new_dim = resize_dimensions(img.width().get(), img.height().get());
|
||||
let mut dst = fir::Image::new(
|
||||
NonZeroU32::try_from(new_dim.0).unwrap(),
|
||||
NonZeroU32::try_from(new_dim.1).unwrap(),
|
||||
img.pixel_type()
|
||||
);
|
||||
fir::Resizer::new(fir::ResizeAlg::SuperSampling(
|
||||
fir::FilterType::Hamming,
|
||||
2
|
||||
))
|
||||
.resize(&img.view(), &mut dst.view_mut())
|
||||
.expect("Failed to resize preview image");
|
||||
dst
|
||||
};
|
||||
let _span = metrics::span("generate_preview_save", &prev_span);
|
||||
let mut file = std::io::BufWriter::new(
|
||||
File::create(std::path::Path::new(&(file_name + "_preview.jpg")))
|
||||
.expect("Failed to open preview image file")
|
||||
);
|
||||
image::codecs::jpeg::JpegEncoder::new(&mut file)
|
||||
.encode(
|
||||
img.buffer(),
|
||||
img.width().get(),
|
||||
img.height().get(),
|
||||
match img.pixel_type() {
|
||||
PixelType::U8 => image::ColorType::L8,
|
||||
PixelType::U8x2 => image::ColorType::La8,
|
||||
PixelType::U8x3 => image::ColorType::Rgb8,
|
||||
PixelType::U8x4 => image::ColorType::Rgba8,
|
||||
_ => unreachable!()
|
||||
}
|
||||
)
|
||||
.expect("Failed to save preview image");
|
||||
Some(())
|
||||
})()
|
||||
.is_some();
|
||||
|
||||
Reference in New Issue
Block a user