thumbnail.rs (3144B)
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 image::{io::Reader, ImageFormat}; 17 18 use crate::{Error, Result}; 19 20 // max edge size allowed in pixels for thumbnail creation 21 const THUMBNAIL_LONGEST_EDGE: u32 = 1024; 22 23 /// utility to generate a thumbnail from a file at path 24 /// returns Result (format, image_bits) if successful, otherwise Error 25 #[cfg(feature = "file_io")] 26 pub fn make_thumbnail(path: &std::path::Path) -> Result<(String, Vec<u8>)> { 27 let format = ImageFormat::from_path(path)?; 28 29 let mut img = image::open(path)?; 30 let longest_edge = THUMBNAIL_LONGEST_EDGE; 31 32 // generate a thumbnail image scaled down and in jpeg format 33 if img.width() > longest_edge || img.height() > longest_edge { 34 img = img.thumbnail(longest_edge, longest_edge); 35 } 36 // for png files, use png thumbnails if there is an alpha channel 37 // for other supported types try a jpeg thumbnail 38 let (output_format, format) = match format { 39 ImageFormat::Png if img.color().has_alpha() => (ImageFormat::Png, "image/png"), 40 _ => (ImageFormat::Jpeg, "image/jpeg"), 41 }; 42 let thumbnail_bits = Vec::new(); 43 let mut cursor = std::io::Cursor::new(thumbnail_bits); 44 img.write_to(&mut cursor, output_format)?; 45 46 let format = format.to_owned(); 47 Ok((format, cursor.into_inner())) 48 } 49 50 /// utility to generate a thumbnail from a file at path 51 /// returns Result (format, image_bits) if successful, otherwise Error 52 pub fn make_thumbnail_from_stream<R: Read + Seek + ?Sized>( 53 format: &str, 54 stream: &mut R, 55 ) -> Result<(String, Vec<u8>)> { 56 let format = ImageFormat::from_extension(format) 57 .or_else(|| ImageFormat::from_mime_type(format)) 58 .ok_or(Error::UnsupportedType)?; 59 60 let reader = Reader::with_format(std::io::BufReader::new(stream), format); 61 let mut img = reader.decode()?; 62 63 let longest_edge = THUMBNAIL_LONGEST_EDGE; 64 65 // generate a thumbnail image scaled down and in jpeg format 66 if img.width() > longest_edge || img.height() > longest_edge { 67 img = img.thumbnail(longest_edge, longest_edge); 68 } 69 70 // for png files, use png thumbnails for transparency 71 // for other supported types try a jpeg thumbnail 72 let (output_format, format) = match format { 73 ImageFormat::Png => (ImageFormat::Png, "image/png"), 74 _ => (ImageFormat::Jpeg, "image/jpeg"), 75 }; 76 let thumbnail_bits = Vec::new(); 77 let mut cursor = std::io::Cursor::new(thumbnail_bits); 78 img.write_to(&mut cursor, output_format)?; 79 80 let format = format.to_owned(); 81 Ok((format, cursor.into_inner())) 82 }