@@ -45,7 +45,7 @@ pub fn encode(wand: &mut MagickWand, quality: u8) -> Result<Vec<u8>> {
45
45
let lib_heif = LibHeif :: new ( ) ;
46
46
let mut context = HeifContext :: new ( ) ?;
47
47
let mut encoder = lib_heif. encoder_for_format ( CompressionFormat :: Hevc ) ?;
48
- encoder. set_quality ( EncoderQuality :: Lossy ( quality) ) ?;
48
+ encoder. set_quality ( EncoderQuality :: Lossy ( interpolate_quality ( quality) ) ) ?;
49
49
let handle = context. encode_image ( & image, & mut encoder, None ) ?;
50
50
51
51
// add metadata
@@ -61,6 +61,59 @@ pub fn encode(wand: &mut MagickWand, quality: u8) -> Result<Vec<u8>> {
61
61
. map_err ( |e| anyhow ! ( "Failed to write to bytes: {}" , e) )
62
62
}
63
63
64
+ fn interpolate_quality ( quality : u8 ) -> u8 {
65
+ let biases = vec ! [
66
+ ( 70 , 50. ) ,
67
+ ( 85 , 60. ) ,
68
+ ( 92 , 70. ) ,
69
+ ( 95 , 80. ) ,
70
+ ( 100 , 100. ) ,
71
+ ] ;
72
+
73
+ let tolerance = 0.1 ;
74
+
75
+ let mut lower: Option < ( i32 , f32 ) > = None ;
76
+ let mut upper: Option < ( i32 , f32 ) > = None ;
77
+
78
+ for ( i, & ( q, biased) ) in biases. iter ( ) . enumerate ( ) {
79
+ if q == quality {
80
+ return biased as u8 ;
81
+ } else if q < quality {
82
+ lower = Some ( ( i as i32 , biased) ) ;
83
+ } else if q > quality {
84
+ upper = Some ( ( i as i32 , biased) ) ;
85
+ break ;
86
+ }
87
+ }
88
+
89
+ match ( lower, upper) {
90
+ ( Some ( ( lower_idx, lower_size) ) , Some ( ( upper_idx, upper_size) ) ) => {
91
+ let lower_quality = biases[ lower_idx as usize ] . 0 as f32 ;
92
+ let upper_quality = biases[ upper_idx as usize ] . 0 as f32 ;
93
+ let quality_ratio = ( quality as f32 - lower_quality) / ( upper_quality - lower_quality) ;
94
+ let interpolated_size = lower_size + quality_ratio * ( upper_size - lower_size) ;
95
+
96
+ if ( interpolated_size - lower_size) . abs ( ) < tolerance {
97
+ return lower_size as u8 ;
98
+ } else if ( interpolated_size - upper_size) . abs ( ) < tolerance {
99
+ return upper_size as u8 ;
100
+ } else {
101
+ return interpolated_size as u8 ;
102
+ }
103
+ }
104
+ ( Some ( ( _lower_idx, lower_size) ) , None ) => {
105
+ return lower_size as u8 ;
106
+ }
107
+ ( None , Some ( ( _upper_idx, upper_size) ) ) => {
108
+ return upper_size as u8 ;
109
+ }
110
+ _ => {
111
+ // never reached
112
+ panic ! ( "Unable to interpolate file size" )
113
+ } ,
114
+ }
115
+ }
116
+
64
117
fn get_image_profile < T : AsRef < str > > ( wand : & mut MagickWand , name : T ) -> Option < Vec < u8 > > {
65
118
let c_name = CString :: new ( name. as_ref ( ) ) . unwrap ( ) ;
66
119
let mut n = 0 ;
0 commit comments