11use std:: io:: Cursor ;
22
3- use image:: { ImageError , ImageFormat } ;
3+ use image:: { codecs :: { jpeg :: JpegEncoder , png :: { CompressionType , FilterType , PngEncoder } } , ImageEncoder , ImageError , ImageFormat } ;
44use js_sys:: Reflect ;
55use wasm_bindgen:: { prelude:: wasm_bindgen, JsCast , JsValue } ;
66
7+ enum EncoderOptions {
8+ Jpeg { quality : u8 } ,
9+ Png { compression : CompressionType , filter : FilterType } ,
10+ None ,
11+ }
12+
13+ #[ wasm_bindgen]
14+ pub struct EncoderInput {
15+ quality : Option < u8 > ,
16+ compression : Option < String > ,
17+ filter : Option < String > ,
18+ }
19+
20+ impl EncoderInput {
21+ fn to_options ( & self , format : ImageFormat ) -> EncoderOptions {
22+ match format {
23+ ImageFormat :: Jpeg => self . quality . map ( |v| EncoderOptions :: Jpeg { quality : v } ) . unwrap_or ( EncoderOptions :: None ) ,
24+ ImageFormat :: Png => {
25+ let compression = match self . compression . as_deref ( ) {
26+ Some ( "fast" ) => Some ( CompressionType :: Fast ) ,
27+ Some ( "best" ) => Some ( CompressionType :: Best ) ,
28+ Some ( "default" ) => Some ( CompressionType :: Default ) ,
29+ _ => None ,
30+ } ;
31+ let filter = match self . filter . as_deref ( ) {
32+ Some ( "no_filter" ) => Some ( FilterType :: NoFilter ) ,
33+ Some ( "sub" ) => Some ( FilterType :: Sub ) ,
34+ Some ( "up" ) => Some ( FilterType :: Up ) ,
35+ Some ( "avg" ) => Some ( FilterType :: Avg ) ,
36+ Some ( "paeth" ) => Some ( FilterType :: Paeth ) ,
37+ Some ( "adaptive" ) => Some ( FilterType :: Adaptive ) ,
38+ _ => None
39+ } ;
40+ match ( compression, filter) {
41+ ( Some ( c) , Some ( f) ) => EncoderOptions :: Png { compression : c, filter : f } ,
42+ ( _, _) => EncoderOptions :: None ,
43+ }
44+ }
45+ _ => EncoderOptions :: None ,
46+ }
47+ }
48+ }
49+
750fn map_image_err ( err : ImageError ) -> String {
8- format ! ( "Image processing error: {}" , err)
51+ format ! ( "Image processing error: {}" , err)
952}
1053
11- fn convert ( image_data : Vec < u8 > , input : ImageFormat , output : ImageFormat ) -> Result < Vec < u8 > , String > {
54+ fn convert ( image_data : Vec < u8 > , input : ImageFormat , output : ImageFormat , options : EncoderOptions ) -> Result < Vec < u8 > , String > {
1255 report_progress ( "Loading image..." ) ;
1356 let img = image:: load_from_memory_with_format ( & image_data, input) . map_err ( map_image_err) ?;
1457 let mut output_data: Vec < u8 > = Vec :: new ( ) ;
1558 report_progress ( "Converting to new format..." ) ;
16- img. write_to ( & mut Cursor :: new ( & mut output_data) , output) . map_err ( map_image_err) ?;
59+ match options {
60+ EncoderOptions :: Jpeg { quality } => {
61+ let mut encoder = JpegEncoder :: new_with_quality ( & mut output_data, quality) ;
62+ encoder. encode_image ( & img) . map_err ( map_image_err) ?;
63+ } ,
64+ EncoderOptions :: Png { compression, filter } => {
65+ let encoder = PngEncoder :: new_with_quality ( & mut output_data, compression, filter) ;
66+ encoder. write_image ( & img. as_bytes ( ) , img. width ( ) , img. height ( ) , img. color ( ) . into ( ) ) . map_err ( map_image_err) ?;
67+ } ,
68+ EncoderOptions :: None => img. write_to ( & mut Cursor :: new ( & mut output_data) , output) . map_err ( map_image_err) ?,
69+ } ;
1770 report_progress ( "Completed conversion." ) ;
1871 Ok ( output_data)
1972}
@@ -40,10 +93,11 @@ fn str_to_type(s: &str) -> Option<ImageFormat> {
4093}
4194
4295#[ wasm_bindgen]
43- pub fn convert_exposed ( image_data : Vec < u8 > , input : String , output : String ) -> Result < Vec < u8 > , String > {
96+ pub fn convert_exposed ( image_data : Vec < u8 > , input : String , output : String , options : EncoderInput ) -> Result < Vec < u8 > , String > {
4497 let input = str_to_type ( & input) . ok_or_else ( || format ! ( "Unsupported input format: {}" , input) ) ?;
4598 let output = str_to_type ( & output) . ok_or_else ( || format ! ( "Unsupported output format: {}" , output) ) ?;
46- convert ( image_data, input, output)
99+ let options = options. to_options ( output) ;
100+ convert ( image_data, input, output, options)
47101}
48102
49103fn report_progress ( message : & str ) {
0 commit comments