use std::{cmp, io::Cursor, num::Saturating as Sat};
use conduit::{checked, err, Result};
use image::{imageops::FilterType, DynamicImage};
use ruma::{http_headers::ContentDisposition, media::Method, Mxc, UInt, UserId};
use tokio::{
fs,
io::{AsyncReadExt, AsyncWriteExt},
};
use super::{data::Metadata, FileMeta};
/// Dimension specification for a thumbnail.
#[derive(Debug)]
pub struct Dim {
pub width: u32,
pub height: u32,
pub method: Method,
}
impl super::Service {
/// Uploads or replaces a file thumbnail.
#[allow(clippy::too_many_arguments)]
pub async fn upload_thumbnail(
&self, mxc: &Mxc<'_>, user: Option<&UserId>, content_disposition: Option<&ContentDisposition>,
content_type: Option<&str>, dim: &Dim, file: &[u8],
) -> Result<()> {
let key = self
.db
.create_file_metadata(mxc, user, dim, content_disposition, content_type)?;
//TODO: Dangling metadata in database if creation fails
let mut f = self.create_media_file(&key).await?;
f.write_all(file).await?;
Ok(())
}
/// Downloads a file's thumbnail.
///
/// Here's an example on how it works:
///
/// - Client requests an image with width=567, height=567
/// - Server rounds that up to (800, 600), so it doesn't have to save too
/// many thumbnails
/// - Server rounds that up again to (958, 600) to fix the aspect ratio
/// (only for width,height>96)
/// - Server creates the thumbnail and sends it to the user
///
/// For width,height <= 96 the server uses another thumbnailing algorithm
/// which crops the image afterwards.
#[tracing::instrument(skip(self), name = "thumbnail", level = "debug")]
pub async fn get_thumbnail(&self, mxc: &Mxc<'_>, dim: &Dim) -> Result