make_thumbnail.rs (2192B)
1 // Copyright 2022 Adobe. All rights reserved. 2 // This file is licensed to you under the Apache License, 3 // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) 4 // or the MIT license (http://opensource.org/licenses/MIT), 5 // at your option. 6 7 // Unless required by applicable law or agreed to in writing, 8 // this software is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or 10 // implied. See the LICENSE-MIT and LICENSE-APACHE files for the 11 // specific language governing permissions and limitations under 12 // each license. 13 14 use std::io::{Read, Seek}; 15 16 use anyhow::{Error, Result}; 17 use image::{io::Reader, ImageFormat}; 18 19 // max edge size allowed in pixels for thumbnail creation 20 const THUMBNAIL_LONGEST_EDGE: u32 = 1024; 21 const THUMBNAIL_JPEG_QUALITY: u8 = 80; 22 23 /// utility to generate a thumbnail from a stream 24 /// returns Result (format, image_bits) if successful, otherwise Error 25 pub fn make_thumbnail_from_stream<R: Read + Seek + ?Sized>( 26 format: &str, 27 stream: &mut R, 28 ) -> Result<(String, Vec<u8>)> { 29 let format = ImageFormat::from_extension(format) 30 .or_else(|| ImageFormat::from_mime_type(format)) 31 .ok_or(Error::msg(format!("format not supported {format}")))?; 32 33 let reader = Reader::with_format(std::io::BufReader::new(stream), format); 34 let mut img = reader.decode()?; 35 36 let longest_edge = THUMBNAIL_LONGEST_EDGE; 37 38 // generate a thumbnail image scaled down and in jpeg format 39 if img.width() > longest_edge || img.height() > longest_edge { 40 img = img.thumbnail(longest_edge, longest_edge); 41 } 42 43 // for png files, use png thumbnails for transparency 44 // for other supported types try a jpeg thumbnail 45 let (output_format, format) = match format { 46 ImageFormat::Png => (image::ImageOutputFormat::Png, "image/png"), 47 _ => ( 48 image::ImageOutputFormat::Jpeg(THUMBNAIL_JPEG_QUALITY), 49 "image/jpeg", 50 ), 51 }; 52 let thumbnail_bits = Vec::new(); 53 let mut cursor = std::io::Cursor::new(thumbnail_bits); 54 img.write_to(&mut cursor, output_format)?; 55 56 let format = format.to_owned(); 57 Ok((format, cursor.into_inner())) 58 }