1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use super::*;

use image::io::Reader as ImgReader;
use image::{Bgr, Bgra, ImageFormat};

#[derive(Deref, DerefMut, Debug)]
pub struct ImageBuffer<P: image::Pixel, Cont>(pub image::ImageBuffer<P, Cont>);

#[derive(Deref, DerefMut)]
pub struct DynamicImage(pub image::DynamicImage);

impl FromField for DynamicImage {
    type Error = Error;
    type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;

    fn from_field(field: actix_multipart::Field) -> Self::Future {
        async move {
            let ct = field.content_type().clone();
            let vec = Vec::<u8>::from_field(field).await.unwrap();
            let tp = match ct.subtype() {
                mime::JPEG => Some(ImageFormat::Jpeg),
                mime::PNG => Some(ImageFormat::Png),
                mime::GIF => Some(ImageFormat::Gif),
                mime::BMP => Some(ImageFormat::Bmp),
                _ => None,
            };
            let cur = Cursor::new(&*vec);
            let rdr = match tp {
                Some(fmt) => ImgReader::with_format(cur, fmt),
                None => ImgReader::new(cur)
                    .with_guessed_format()
                    .expect("Cursor io never fails"),
            };

            Ok(Self(rdr.decode()?))
        }
        .boxed_local()
    }
}

macro_rules! ff_img(
	{ $ty:ident, $img:ty, $into:ident } => {
		#[derive(Deref, DerefMut, Debug)]
		pub struct $ty(pub $img);

		impl FromField for $ty {
			type Error = Error;
			type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;

			fn from_field(field: actix_multipart::Field) -> Self::Future {
				async move {
					let img = DynamicImage::from_field(field).await?;
					let img = img.0.$into();
					Ok(Self(img))
				}
				.boxed_local()
			}
		}
	};
);

#[cfg(feature = "mozjpeg")]
macro_rules! ff_img_mozjpeg(
	{ $ty:ident, $img:ty, $subp:ty, $into:ident, $into_img:ident } => {
		#[derive(Deref, DerefMut, Debug, Clone)]
		pub struct $ty(pub $img);

		impl FromField for $ty {
			type Error = Error;
			type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;

			fn from_field(field: actix_multipart::Field) -> Self::Future {
				use mozjpeg::{decompress::DctMethod, Decompress, ALL_MARKERS};

				if *field.content_type() == mime::IMAGE_JPEG {
					async move {
						let buf = Vec::<u8>::from_field(field).await.unwrap();
						let mut decomp = Decompress::with_markers(ALL_MARKERS)
							.from_mem(&buf[..])
							.map_err(|_| Error::MozjpgDecodeError)?;
						decomp.dct_method(DctMethod::IntegerFast);

						let (w, h) = decomp.size();
						let mut decomp = decomp.$into()
							.map_err(|_| Error::MozjpgDecodeError)?;
						let out = decomp
							.read_scanlines::<$subp>()
							.ok_or(Error::MozjpgDecodeError)?;

						let out: &[$subp] = &*out;
						let sz = out.len() * std::mem::size_of::<$subp>();
						let out: &[u8] = unsafe {
							std::slice::from_raw_parts(
                                out.as_ptr() as *const u8,
                                sz,
                            )
						};

						Ok(Self(<$img>::from_raw(w as u32, h as u32, out.to_vec())
										 .ok_or(Error::MozjpgDecodeError)?))
					}
					.boxed_local()
				} else {
					async move {
						let img = DynamicImage::from_field(field).await?;
						let img = img.0.$into_img();
						Ok(Self(img))
					}
					.boxed_local()
				}
			}
		}
	};
);

#[cfg(feature = "mozjpeg")]
ff_img_mozjpeg!(RgbImage, image::RgbImage, [u8; 3], rgb, into_rgb8);
#[cfg(not(feature = "mozjpeg"))]
ff_img!(RgbImage, image::RgbImage, into_rgb8);

#[cfg(feature = "mozjpeg")]
ff_img_mozjpeg!(RgbaImage, image::RgbaImage, [u8; 4], rgba, into_rgba8);
#[cfg(not(feature = "mozjpeg"))]
ff_img!(RgbaImage, image::RgbaImage, into_rgba8);

#[cfg(feature = "mozjpeg")]
ff_img_mozjpeg!(GrayImage, image::GrayImage, [u8; 1], grayscale, into_luma8);
#[cfg(not(feature = "mozjpeg"))]
ff_img!(GrayImage, image::GrayImage, into_luma8);

ff_img!(GrayAlphaImage, image::GrayAlphaImage, into_luma_alpha8);
ff_img!(BgrImage, image::ImageBuffer<Bgr<u8>, Vec<u8>>, into_bgr8);
ff_img!(BgraImage, image::ImageBuffer<Bgra<u8>, Vec<u8>>, into_bgra8);