@@ -347,6 +347,24 @@ fn write_run<W: Write>(
347
347
Ok ( ( ) )
348
348
}
349
349
350
+ /// Allows fine-tuning some encoder parameters.
351
+ ///
352
+ /// Pass to [`WebPEncoder::set_params()`].
353
+ #[ non_exhaustive]
354
+ #[ derive( Clone , Debug ) ]
355
+ pub struct EncoderParams {
356
+ /// Use a predictor transform. Enabled by default.
357
+ pub use_predictor_transform : bool ,
358
+ }
359
+
360
+ impl Default for EncoderParams {
361
+ fn default ( ) -> Self {
362
+ Self {
363
+ use_predictor_transform : true ,
364
+ }
365
+ }
366
+ }
367
+
350
368
/// Encode image data with the indicated color type.
351
369
///
352
370
/// # Panics
@@ -358,6 +376,7 @@ fn encode_frame<W: Write>(
358
376
width : u32 ,
359
377
height : u32 ,
360
378
color : ColorType ,
379
+ params : EncoderParams ,
361
380
) -> Result < ( ) , EncodingError > {
362
381
let w = & mut BitWriter {
363
382
writer,
@@ -392,11 +411,13 @@ fn encode_frame<W: Write>(
392
411
w. write_bits ( 0b101 , 3 ) ?;
393
412
394
413
// predictor transform
395
- w. write_bits ( 0b111001 , 6 ) ?;
396
- w. write_bits ( 0x0 , 1 ) ?; // no color cache
397
- write_single_entry_huffman_tree ( w, 2 ) ?;
398
- for _ in 0 ..4 {
399
- write_single_entry_huffman_tree ( w, 0 ) ?;
414
+ if params. use_predictor_transform {
415
+ w. write_bits ( 0b111001 , 6 ) ?;
416
+ w. write_bits ( 0x0 , 1 ) ?; // no color cache
417
+ write_single_entry_huffman_tree ( w, 2 ) ?;
418
+ for _ in 0 ..4 {
419
+ write_single_entry_huffman_tree ( w, 0 ) ?;
420
+ }
400
421
}
401
422
402
423
// transforms done
@@ -429,18 +450,20 @@ fn encode_frame<W: Write>(
429
450
}
430
451
431
452
// compute predictor transform
432
- let row_bytes = width as usize * 4 ;
433
- for y in ( 1 ..height as usize ) . rev ( ) {
434
- let ( prev, current) =
435
- pixels[ ( y - 1 ) * row_bytes..] [ ..row_bytes * 2 ] . split_at_mut ( row_bytes) ;
436
- for ( c, p) in current. iter_mut ( ) . zip ( prev) {
437
- * c = c. wrapping_sub ( * p) ;
453
+ if params. use_predictor_transform {
454
+ let row_bytes = width as usize * 4 ;
455
+ for y in ( 1 ..height as usize ) . rev ( ) {
456
+ let ( prev, current) =
457
+ pixels[ ( y - 1 ) * row_bytes..] [ ..row_bytes * 2 ] . split_at_mut ( row_bytes) ;
458
+ for ( c, p) in current. iter_mut ( ) . zip ( prev) {
459
+ * c = c. wrapping_sub ( * p) ;
460
+ }
438
461
}
462
+ for i in ( 4 ..row_bytes) . rev ( ) {
463
+ pixels[ i] = pixels[ i] . wrapping_sub ( pixels[ i - 4 ] ) ;
464
+ }
465
+ pixels[ 3 ] = pixels[ 3 ] . wrapping_sub ( 255 ) ;
439
466
}
440
- for i in ( 4 ..row_bytes) . rev ( ) {
441
- pixels[ i] = pixels[ i] . wrapping_sub ( pixels[ i - 4 ] ) ;
442
- }
443
- pixels[ 3 ] = pixels[ 3 ] . wrapping_sub ( 255 ) ;
444
467
445
468
// compute frequencies
446
469
let mut frequencies0 = [ 0u32 ; 256 ] ;
@@ -506,8 +529,10 @@ fn encode_frame<W: Write>(
506
529
}
507
530
if is_alpha {
508
531
write_huffman_tree ( w, & frequencies3, & mut lengths3, & mut codes3) ?;
509
- } else {
532
+ } else if params . use_predictor_transform {
510
533
write_single_entry_huffman_tree ( w, 0 ) ?;
534
+ } else {
535
+ write_single_entry_huffman_tree ( w, 255 ) ?;
511
536
}
512
537
write_single_entry_huffman_tree ( w, 1 ) ?;
513
538
@@ -597,6 +622,7 @@ pub struct WebPEncoder<W> {
597
622
icc_profile : Vec < u8 > ,
598
623
exif_metadata : Vec < u8 > ,
599
624
xmp_metadata : Vec < u8 > ,
625
+ params : EncoderParams ,
600
626
}
601
627
602
628
impl < W : Write > WebPEncoder < W > {
@@ -609,6 +635,7 @@ impl<W: Write> WebPEncoder<W> {
609
635
icc_profile : Vec :: new ( ) ,
610
636
exif_metadata : Vec :: new ( ) ,
611
637
xmp_metadata : Vec :: new ( ) ,
638
+ params : EncoderParams :: default ( ) ,
612
639
}
613
640
}
614
641
@@ -627,6 +654,11 @@ impl<W: Write> WebPEncoder<W> {
627
654
self . xmp_metadata = xmp_metadata;
628
655
}
629
656
657
+ /// Set the `EncoderParams` to use.
658
+ pub fn set_params ( & mut self , params : EncoderParams ) {
659
+ self . params = params;
660
+ }
661
+
630
662
/// Encode image data with the indicated color type.
631
663
///
632
664
/// # Panics
@@ -640,7 +672,7 @@ impl<W: Write> WebPEncoder<W> {
640
672
color : ColorType ,
641
673
) -> Result < ( ) , EncodingError > {
642
674
let mut frame = Vec :: new ( ) ;
643
- encode_frame ( & mut frame, data, width, height, color) ?;
675
+ encode_frame ( & mut frame, data, width, height, color, self . params ) ?;
644
676
645
677
// If the image has no metadata, it can be encoded with the "simple" WebP container format.
646
678
if self . icc_profile . is_empty ( )
@@ -757,45 +789,67 @@ mod tests {
757
789
758
790
#[ test]
759
791
fn roundtrip_libwebp ( ) {
792
+ roundtrip_libwebp_params ( EncoderParams :: default ( ) ) ;
793
+ roundtrip_libwebp_params ( EncoderParams {
794
+ use_predictor_transform : false ,
795
+ ..Default :: default ( )
796
+ } ) ;
797
+ }
798
+
799
+ fn roundtrip_libwebp_params ( params : EncoderParams ) {
800
+ println ! ( "Testing {params:?}" ) ;
801
+
760
802
let mut img = vec ! [ 0 ; 256 * 256 * 4 ] ;
761
803
rand:: thread_rng ( ) . fill_bytes ( & mut img) ;
762
804
763
805
let mut output = Vec :: new ( ) ;
764
- WebPEncoder :: new ( & mut output)
806
+ let mut encoder = WebPEncoder :: new ( & mut output) ;
807
+ encoder. set_params ( params. clone ( ) ) ;
808
+ encoder
765
809
. encode ( & img[ ..256 * 256 * 3 ] , 256 , 256 , crate :: ColorType :: Rgb8 )
766
810
. unwrap ( ) ;
767
- webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
811
+ let decoded = webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
812
+ assert ! ( & img[ ..256 * 256 * 3 ] == & * decoded) ;
768
813
769
814
let mut output = Vec :: new ( ) ;
770
- WebPEncoder :: new ( & mut output)
815
+ let mut encoder = WebPEncoder :: new ( & mut output) ;
816
+ encoder. set_params ( params. clone ( ) ) ;
817
+ encoder
771
818
. encode ( & img, 256 , 256 , crate :: ColorType :: Rgba8 )
772
819
. unwrap ( ) ;
773
- webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
820
+ let decoded = webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
821
+ assert ! ( & img == & * decoded) ;
774
822
775
823
let mut output = Vec :: new ( ) ;
776
824
let mut encoder = WebPEncoder :: new ( & mut output) ;
825
+ encoder. set_params ( params. clone ( ) ) ;
777
826
encoder. set_icc_profile ( vec ! [ 0 ; 10 ] ) ;
778
827
encoder
779
828
. encode ( & img, 256 , 256 , crate :: ColorType :: Rgba8 )
780
829
. unwrap ( ) ;
781
- webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
830
+ let decoded = webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
831
+ assert ! ( & img == & * decoded) ;
782
832
783
833
let mut output = Vec :: new ( ) ;
784
834
let mut encoder = WebPEncoder :: new ( & mut output) ;
835
+ encoder. set_params ( params. clone ( ) ) ;
785
836
encoder. set_exif_metadata ( vec ! [ 0 ; 10 ] ) ;
786
837
encoder
787
838
. encode ( & img, 256 , 256 , crate :: ColorType :: Rgba8 )
788
839
. unwrap ( ) ;
789
- webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
840
+ let decoded = webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
841
+ assert ! ( & img == & * decoded) ;
790
842
791
843
let mut output = Vec :: new ( ) ;
792
844
let mut encoder = WebPEncoder :: new ( & mut output) ;
845
+ encoder. set_params ( params. clone ( ) ) ;
793
846
encoder. set_xmp_metadata ( vec ! [ 0 ; 7 ] ) ;
794
847
encoder. set_icc_profile ( vec ! [ 0 ; 8 ] ) ;
795
848
encoder. set_icc_profile ( vec ! [ 0 ; 9 ] ) ;
796
849
encoder
797
850
. encode ( & img, 256 , 256 , crate :: ColorType :: Rgba8 )
798
851
. unwrap ( ) ;
799
- webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
852
+ let decoded = webp:: Decoder :: new ( & output) . decode ( ) . unwrap ( ) ;
853
+ assert ! ( & img == & * decoded) ;
800
854
}
801
855
}
0 commit comments