1+ use std:: io:: Cursor ;
2+
13use napi:: { bindgen_prelude:: * , JsBuffer } ;
24use napi_derive:: napi;
35
@@ -17,8 +19,30 @@ pub fn compress_jpeg_sync(
1719 input : Buffer ,
1820 options : Option < JpegCompressOptions > ,
1921) -> Result < JsBuffer > {
22+ let options = options. unwrap_or_default ( ) ;
23+ let quality = options. quality . unwrap_or ( 100 ) ;
24+ if quality != 100 {
25+ let img = image:: load_from_memory_with_format ( input. as_ref ( ) , image:: ImageFormat :: Jpeg )
26+ . map_err ( |err| {
27+ Error :: new (
28+ Status :: InvalidArg ,
29+ format ! ( "Load input jpeg image failed {}" , err) ,
30+ )
31+ } ) ?;
32+ let mut dest = Cursor :: new ( Vec :: with_capacity ( input. len ( ) ) ) ;
33+ let mut encoder = image:: codecs:: jpeg:: JpegEncoder :: new_with_quality ( & mut dest, quality as u8 ) ;
34+ encoder. encode_image ( & img) . map_err ( |err| {
35+ Error :: new (
36+ Status :: GenericFailure ,
37+ format ! ( "Encode image from input jpeg failed {}" , err) ,
38+ )
39+ } ) ?;
40+ return env
41+ . create_buffer_with_data ( dest. into_inner ( ) )
42+ . map ( |b| b. into_raw ( ) ) ;
43+ }
2044 let ( buf, outsize, de_c_info, compress_c_info) =
21- unsafe { moz_jpeg_compress ( input. as_ref ( ) , & options. unwrap_or_default ( ) ) } ?;
45+ unsafe { moz_jpeg_compress ( input. as_ref ( ) , & options) } ?;
2246 unsafe {
2347 env. create_buffer_with_borrowed_data (
2448 buf,
@@ -63,9 +87,6 @@ unsafe fn moz_jpeg_compress(
6387 mozjpeg_sys:: jpeg_read_header ( & mut de_c_info, 1 ) ;
6488 let src_coef_arrays = mozjpeg_sys:: jpeg_read_coefficients ( & mut de_c_info) ;
6589 mozjpeg_sys:: jpeg_copy_critical_parameters ( & de_c_info, & mut compress_c_info) ;
66- if let Some ( quality) = opts. quality {
67- mozjpeg_sys:: jpeg_set_quality ( & mut compress_c_info, quality as i32 , 0 ) ;
68- }
6990 if opts. optimize_scans . unwrap_or ( true ) {
7091 mozjpeg_sys:: jpeg_c_set_bool_param (
7192 & mut compress_c_info,
@@ -138,40 +159,69 @@ pub struct CompressJpegTask {
138159 input : Buffer ,
139160}
140161
162+ pub enum JpegOptimizeOutput {
163+ Lossless ( ThreadsafeMozjpegCompressOutput ) ,
164+ Lossy ( Vec < u8 > ) ,
165+ }
166+
141167#[ napi]
142168impl Task for CompressJpegTask {
143- type Output = ThreadsafeMozjpegCompressOutput ;
169+ type Output = JpegOptimizeOutput ;
144170 type JsValue = JsBuffer ;
145171
146172 fn compute ( & mut self ) -> Result < Self :: Output > {
173+ let quality = self . options . quality . unwrap_or ( 100 ) ;
174+ if quality != 100 {
175+ let img = image:: load_from_memory_with_format ( self . input . as_ref ( ) , image:: ImageFormat :: Jpeg )
176+ . map_err ( |err| {
177+ Error :: new (
178+ Status :: InvalidArg ,
179+ format ! ( "Load input jpeg image failed {}" , err) ,
180+ )
181+ } ) ?;
182+ let mut dest = Cursor :: new ( Vec :: with_capacity ( self . input . len ( ) ) ) ;
183+ let mut encoder =
184+ image:: codecs:: jpeg:: JpegEncoder :: new_with_quality ( & mut dest, quality as u8 ) ;
185+ encoder. encode_image ( & img) . map_err ( |err| {
186+ Error :: new (
187+ Status :: GenericFailure ,
188+ format ! ( "Encode image from input jpeg failed {}" , err) ,
189+ )
190+ } ) ?;
191+ return Ok ( JpegOptimizeOutput :: Lossy ( dest. into_inner ( ) ) ) ;
192+ }
147193 unsafe { moz_jpeg_compress ( self . input . as_ref ( ) , & self . options ) } . map (
148- |( buf, len, de_c_info, compress_c_info) | ThreadsafeMozjpegCompressOutput {
149- buf,
150- len,
151- de_c_info,
152- compress_c_info,
194+ |( buf, len, de_c_info, compress_c_info) | {
195+ JpegOptimizeOutput :: Lossless ( ThreadsafeMozjpegCompressOutput {
196+ buf,
197+ len,
198+ de_c_info,
199+ compress_c_info,
200+ } )
153201 } ,
154202 )
155203 }
156204
157205 fn resolve ( & mut self , env : Env , output : Self :: Output ) -> Result < Self :: JsValue > {
158- let ThreadsafeMozjpegCompressOutput {
159- buf,
160- len,
161- de_c_info,
162- compress_c_info,
163- } = output;
164- unsafe {
165- env. create_buffer_with_borrowed_data (
206+ match output {
207+ JpegOptimizeOutput :: Lossless ( ThreadsafeMozjpegCompressOutput {
166208 buf,
167209 len,
168- ( de_c_info, compress_c_info, buf) ,
169- |( mut input, mut output, buf) , _| {
170- mozjpeg_sys:: jpeg_destroy_decompress ( & mut input) ;
171- mozjpeg_sys:: jpeg_destroy_compress ( & mut output) ;
172- libc:: free ( buf as * mut std:: ffi:: c_void ) ;
173- } ,
174- )
210+ de_c_info,
211+ compress_c_info,
212+ } ) => unsafe {
213+ env. create_buffer_with_borrowed_data (
214+ buf,
215+ len,
216+ ( de_c_info, compress_c_info, buf) ,
217+ |( mut input, mut output, buf) , _| {
218+ mozjpeg_sys:: jpeg_destroy_decompress ( & mut input) ;
219+ mozjpeg_sys:: jpeg_destroy_compress ( & mut output) ;
220+ libc:: free ( buf as * mut std:: ffi:: c_void ) ;
221+ } ,
222+ )
223+ } ,
224+ JpegOptimizeOutput :: Lossy ( buf) => env. create_buffer_with_data ( buf) ,
175225 }
176226 . map ( |v| v. into_raw ( ) )
177227 }
0 commit comments