From 8c1b1e8c72d4923194fa1f0b5a69ceb71b03af7c Mon Sep 17 00:00:00 2001 From: Kristof Date: Thu, 20 Apr 2023 10:40:39 +0200 Subject: [PATCH 1/8] improve encode_block perf by about 10% with faster integer encoding --- src/codecs/jpeg/encoder.rs | 119 ++++++++++++++++++++++++++++++++----- 1 file changed, 104 insertions(+), 15 deletions(-) diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index b350595f6f..7675ec6d8f 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::io::{self, Write}; +use std::num::NonZeroI32; use crate::error::{ ImageError, ImageResult, ParameterError, ParameterErrorKind, UnsupportedError, @@ -189,6 +190,7 @@ impl BitWriter { } } + #[inline] fn write_bits(&mut self, bits: u16, size: u8) -> io::Result<()> { if size == 0 { return Ok(()); @@ -216,6 +218,7 @@ impl BitWriter { self.write_bits(0x7F, 7) } + #[inline] fn huffman_encode(&mut self, val: u8, table: &[(u8, u16); 256]) -> io::Result<()> { let (size, code) = table[val as usize]; @@ -765,24 +768,23 @@ fn build_quantization_segment(m: &mut Vec, precision: u8, identifier: u8, qt } } +#[inline] fn encode_coefficient(coefficient: i32) -> (u8, u16) { - let mut magnitude = coefficient.unsigned_abs() as u16; - let mut num_bits = 0u8; + // since this is inlined, in the main AC case the compiler figures out that coefficient cannot be zero, so BSR on x86 doesn't need a branch + if let Some(nz) = NonZeroI32::new(coefficient) { + let leading_zeros = nz.unsigned_abs().leading_zeros() as u8; - while magnitude > 0 { - magnitude >>= 1; - num_bits += 1; - } + // first shift right signed by 31 to make everything 1 if negative, + // then shift right unsigned to make the leading bits 0 + let adjustment = ((nz.get() >> 31) as u32) >> leading_zeros; - let mask = (1 << num_bits as usize) - 1; + let n = (nz.get() as u32).wrapping_add(adjustment) as u16; // turn v into a 2s complement of s bits + let s = 32 - leading_zeros; - let val = if coefficient < 0 { - (coefficient - 1) as u16 & mask + return (s, n); } else { - coefficient as u16 & mask - }; - - (num_bits, val) + return (0, 0); + } } #[inline] @@ -863,8 +865,9 @@ mod tests { use super::super::JpegDecoder; use super::{ build_frame_header, build_huffman_segment, build_jfif_header, build_quantization_segment, - build_scan_header, Component, JpegEncoder, PixelDensity, DCCLASS, LUMADESTINATION, - STD_LUMA_DC_CODE_LENGTHS, STD_LUMA_DC_VALUES, + build_scan_header, encode_coefficient, BitWriter, Component, JpegEncoder, PixelDensity, + DCCLASS, LUMADESTINATION, STD_LUMA_AC_HUFF_LUT, STD_LUMA_DC_CODE_LENGTHS, + STD_LUMA_DC_HUFF_LUT, STD_LUMA_DC_VALUES, }; fn decode(encoded: &[u8]) -> Vec { @@ -1076,6 +1079,92 @@ mod tests { assert_eq!(buf, expected) } + #[test] + fn test_encode_coefficient() { + for i in -32768..=32767 { + let (s, n) = encode_coefficient(i); + + assert_eq!(s as u32, 32 - i.unsigned_abs().leading_zeros()); + + let n2 = if i > 0 { i } else { i - 1 + (1 << s) } as u16; + assert_eq!(n, n2, "s={0}", s); + } + } + + #[test] + fn encode_block_all_zero() { + let mut output = Vec::new(); + let mut bitwriter = BitWriter::new(&mut output); + + let block = [0i32; 64]; + bitwriter + .write_block(&block, 0, &STD_LUMA_DC_HUFF_LUT, &STD_LUMA_AC_HUFF_LUT) + .unwrap(); + bitwriter.pad_byte().unwrap(); + + assert_eq!(output[..], [43u8]) + } + + /// This is the sample block from the JPEG standard, there is only one canonical way to encode this + #[test] + fn encode_block_sample_block() { + let mut output = Vec::new(); + let mut bitwriter = BitWriter::new(&mut output); + + let block: [i32; 64] = [ + -416, 18, 10, 7, -2, 2, 0, -1, -8, -1, -1, -1, 0, 0, 0, 0, -2, 2, 4, 0, 0, 0, 0, 0, -1, + 0, -1, 0, 0, 0, 0, -1, -1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + + bitwriter + .write_block(&block, 0, &STD_LUMA_DC_HUFF_LUT, &STD_LUMA_AC_HUFF_LUT) + .unwrap(); + bitwriter.pad_byte().unwrap(); + + assert_eq!( + output[..], + [252, 95, 212, 173, 212, 93, 78, 24, 15, 48, 43, 112, 223, 135, 249, 252, 43] + ) + } + + #[cfg(feature = "benchmarks")] + #[bench] + fn bench_encode_coefficient(b: &mut Bencher) { + b.iter(|| { + test::black_box(encode_coefficient(test::black_box(-100))); + test::black_box(encode_coefficient(test::black_box(100))) + }) + } + + #[cfg(feature = "benchmarks")] + #[bench] + fn bench_encode_block(b: &mut Bencher) { + b.iter(|| { + let mut output = Vec::with_capacity(256); + let mut bitwriter = BitWriter::new(&mut output); + + static BLOCK: [i32; 64] = [ + -416, 180, 100, 71, -42, 20, 20, -51, -18, -19, -182, -151, 120, 120, 120, 120, + -120, 22, 441, 120, 660, 120, 100, 101, -123, 0, -132, 0, 0, 0, 0, -12, -121, 442, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]; + + bitwriter + .write_block( + &test::black_box(BLOCK), + 0, + &test::black_box(STD_LUMA_DC_HUFF_LUT), + &test::black_box(STD_LUMA_AC_HUFF_LUT), + ) + .unwrap(); + bitwriter.pad_byte().unwrap(); + + test::black_box(bitwriter); + }) + } + #[cfg(feature = "benchmarks")] #[bench] fn bench_jpeg_encoder_new(b: &mut Bencher) { From 02f9fe82a44f4b8be899f7ab305fe17106da9f76 Mon Sep 17 00:00:00 2001 From: Kristof Date: Thu, 20 Apr 2023 18:28:57 +0200 Subject: [PATCH 2/8] shrink code for write_bits --- src/codecs/jpeg/encoder.rs | 84 +++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index 7675ec6d8f..d93d3c1a83 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -197,20 +197,25 @@ impl BitWriter { } self.nbits += size; - self.accumulator |= u32::from(bits) << (32 - self.nbits) as usize; + + let mut tmp_accumulator = self.accumulator | u32::from(bits) << (32 - self.nbits) as usize; while self.nbits >= 8 { - let byte = self.accumulator >> 24; + let byte = tmp_accumulator >> 24; self.w.write_all(&[byte as u8])?; if byte == 0xFF { - self.w.write_all(&[0x00])?; + // set top byte to 0 so we can avoid calling write_all twice + // which causes a bunch of branching and inlines to be emitted + tmp_accumulator &= 0x00ffffff; + } else { + self.nbits -= 8; + tmp_accumulator <<= 8; } - - self.nbits -= 8; - self.accumulator <<= 8; } + self.accumulator = tmp_accumulator; + Ok(()) } @@ -1131,38 +1136,66 @@ mod tests { #[cfg(feature = "benchmarks")] #[bench] fn bench_encode_coefficient(b: &mut Bencher) { + b.iter(|| test::black_box(encode_coefficient(test::black_box(-100)))); + + b.iter(|| test::black_box(encode_coefficient(test::black_box(100)))); + } + + #[cfg(feature = "benchmarks")] + #[bench] + fn bench_bitwriter(b: &mut Bencher) { + let mut output = Vec::with_capacity(65536); + let mut bitwriter = BitWriter::new(&mut output); + b.iter(|| { - test::black_box(encode_coefficient(test::black_box(-100))); - test::black_box(encode_coefficient(test::black_box(100))) - }) + let val = test::black_box(1); + let len = test::black_box(1); + + bitwriter.write_bits(val, len).unwrap(); + }); + + test::black_box(bitwriter); + test::black_box(output); } #[cfg(feature = "benchmarks")] #[bench] fn bench_encode_block(b: &mut Bencher) { - b.iter(|| { - let mut output = Vec::with_capacity(256); - let mut bitwriter = BitWriter::new(&mut output); + let mut output = Vec::with_capacity(65536); + + static BLOCK: [i32; 64] = [ + -416, 180, 100, 71, -42, 20, 20, -51, -18, -19, -182, -151, 120, 120, 120, 120, -120, + 22, 441, 120, 660, 120, 100, 101, -123, 0, -132, 0, 0, 0, 0, -12, -121, 442, 10, 10, + 10, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, + ]; - static BLOCK: [i32; 64] = [ - -416, 180, 100, 71, -42, 20, 20, -51, -18, -19, -182, -151, 120, 120, 120, 120, - -120, 22, 441, 120, 660, 120, 100, 101, -123, 0, -132, 0, 0, 0, 0, -12, -121, 442, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - ]; + // allocate a large buffer that we walk through so that we don't get unrealistic behavior with everything in the L1 cache + let mut memoryvec = Vec::new(); + memoryvec.resize(1024 * 1024, BLOCK); + let mut numiter = 0; + let mut bitwriter = BitWriter::new(&mut output); + + b.iter(|| { bitwriter .write_block( - &test::black_box(BLOCK), - 0, + &memoryvec[numiter % (1024 * 1024)], + test::black_box(0), &test::black_box(STD_LUMA_DC_HUFF_LUT), &test::black_box(STD_LUMA_AC_HUFF_LUT), ) .unwrap(); - bitwriter.pad_byte().unwrap(); - test::black_box(bitwriter); - }) + numiter += 1; + }); + + bitwriter.pad_byte().unwrap(); + drop(bitwriter); + + b.bytes = output.len() as u64 / (numiter as u64); + + test::black_box(output); } #[cfg(feature = "benchmarks")] @@ -1170,7 +1203,10 @@ mod tests { fn bench_jpeg_encoder_new(b: &mut Bencher) { b.iter(|| { let mut y = vec![]; - let _x = JpegEncoder::new(&mut y); + let x = JpegEncoder::new(&mut y); + + test::black_box(x); + test::black_box(y); }) } } From 272671c7b54bd1adeaab82c0c784f465a5fd76aa Mon Sep 17 00:00:00 2001 From: Kristof Date: Thu, 20 Apr 2023 18:36:45 +0200 Subject: [PATCH 3/8] don't use unsigned_abs as it is unstable in older versions --- src/codecs/jpeg/encoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index d93d3c1a83..f6249dce1a 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -777,7 +777,7 @@ fn build_quantization_segment(m: &mut Vec, precision: u8, identifier: u8, qt fn encode_coefficient(coefficient: i32) -> (u8, u16) { // since this is inlined, in the main AC case the compiler figures out that coefficient cannot be zero, so BSR on x86 doesn't need a branch if let Some(nz) = NonZeroI32::new(coefficient) { - let leading_zeros = nz.unsigned_abs().leading_zeros() as u8; + let leading_zeros = nz.abs().leading_zeros() as u8; // first shift right signed by 31 to make everything 1 if negative, // then shift right unsigned to make the leading bits 0 From b1aabafbbb4a1dd9b52866ce03d36a8d29370732 Mon Sep 17 00:00:00 2001 From: Kristof Date: Thu, 20 Apr 2023 21:51:02 +0200 Subject: [PATCH 4/8] updated minimum rust to 1.64 to support stabilized NonZeroU32::unsigned_abs. This has a significant speed impact on leading zero calc on x86 --- src/codecs/jpeg/encoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index f6249dce1a..d93d3c1a83 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -777,7 +777,7 @@ fn build_quantization_segment(m: &mut Vec, precision: u8, identifier: u8, qt fn encode_coefficient(coefficient: i32) -> (u8, u16) { // since this is inlined, in the main AC case the compiler figures out that coefficient cannot be zero, so BSR on x86 doesn't need a branch if let Some(nz) = NonZeroI32::new(coefficient) { - let leading_zeros = nz.abs().leading_zeros() as u8; + let leading_zeros = nz.unsigned_abs().leading_zeros() as u8; // first shift right signed by 31 to make everything 1 if negative, // then shift right unsigned to make the leading bits 0 From 6ce094b9a3133b134b0cfbaf12ef4cb1f4f42cd9 Mon Sep 17 00:00:00 2001 From: Kristof Date: Sat, 22 Apr 2023 13:57:20 +0200 Subject: [PATCH 5/8] flush 2 bytes at a time --- src/codecs/jpeg/encoder.rs | 185 +++++++++++++++++++++++++++++++++---- 1 file changed, 167 insertions(+), 18 deletions(-) diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index d93d3c1a83..db317459f1 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -1,6 +1,7 @@ #![allow(clippy::too_many_arguments)] use std::borrow::Cow; +use std::convert::TryFrom; use std::io::{self, Write}; use std::num::NonZeroI32; @@ -186,41 +187,56 @@ impl BitWriter { BitWriter { w, accumulator: 0, - nbits: 0, + nbits: 32, } } #[inline] fn write_bits(&mut self, bits: u16, size: u8) -> io::Result<()> { - if size == 0 { - return Ok(()); - } + self.nbits -= size; + // use wrapping_shl allow for nop for 0 bits + self.accumulator |= u32::from(bits).wrapping_shl(u32::from(self.nbits)); + + // flush 16 bits at a time, since then we are guaranteed to always fit another 16 bits + if self.nbits <= 16 { + let bits_to_write = (self.accumulator >> 16) as u16; + + // test to see if there are any 0xff bytes that need to be escaped, then + // take slow path to flush the accumulator (less than 1% of the time) + if (bits_to_write & 0x8080 & !bits_to_write.wrapping_add(0x0101)) != 0 { + return self.flush_bits_slow(); + } else { + self.w.write_all(&bits_to_write.to_be_bytes())?; - self.nbits += size; + self.accumulator <<= 16; + self.nbits += 16; + } + } - let mut tmp_accumulator = self.accumulator | u32::from(bits) << (32 - self.nbits) as usize; + Ok(()) + } - while self.nbits >= 8 { - let byte = tmp_accumulator >> 24; + #[inline(never)] + #[cold] + fn flush_bits_slow(&mut self) -> io::Result<()> { + while self.nbits <= 24 { + let byte = self.accumulator >> 24; self.w.write_all(&[byte as u8])?; if byte == 0xFF { - // set top byte to 0 so we can avoid calling write_all twice - // which causes a bunch of branching and inlines to be emitted - tmp_accumulator &= 0x00ffffff; - } else { - self.nbits -= 8; - tmp_accumulator <<= 8; + self.w.write_all(&[0x00])?; } - } - self.accumulator = tmp_accumulator; + self.nbits += 8; + self.accumulator <<= 8; + } Ok(()) } fn pad_byte(&mut self) -> io::Result<()> { - self.write_bits(0x7F, 7) + self.write_bits(0x7F, 7)?; + self.flush_bits_slow() } #[inline] @@ -234,7 +250,7 @@ impl BitWriter { self.write_bits(code, size) } - fn write_block( + fn write_block_old( &mut self, block: &[i32; 64], prevdc: i32, @@ -278,6 +294,72 @@ impl BitWriter { Ok(dcval) } + fn write_block( + &mut self, + block: &[i32; 64], + prevdc: i32, + dctable: &[(u8, u16); 256], + actable: &[(u8, u16); 256], + ) -> io::Result { + // Differential DC encoding + let dcval = block[0]; + let diff = dcval - prevdc; + let (size, value) = encode_coefficient(diff); + + self.huffman_encode(size, dctable)?; + self.write_bits(value, size)?; + + // Figure F.2 + let mut bpos = 1; + loop { + let mut tmp = block[UNZIGZAG[bpos] as usize]; + bpos += 1; + + let size; + let value; + let symbol; + + if tmp == 0 { + let mut zero_run = 0; + + loop { + if bpos == 64 { + self.huffman_encode(0x00, actable)?; + return Ok(dcval); + } + + tmp = block[UNZIGZAG[bpos] as usize]; + bpos += 1; + zero_run += 1; + + if tmp != 0 { + while zero_run > 15 { + self.huffman_encode(0xF0, actable)?; + zero_run -= 16; + } + + (size, value) = encode_coefficient(tmp as i32); + symbol = (zero_run << 4) | size; + + break; + } + } + } else { + (size, value) = encode_coefficient(tmp as i32); + symbol = size; + } + + self.huffman_encode(symbol, actable)?; + self.write_bits(value, size)?; + + if bpos == 64 { + break; + } + } + + Ok(dcval) + } + fn write_marker(&mut self, marker: u8) -> io::Result<()> { self.w.write_all(&[0xFF, marker]) } @@ -1096,6 +1178,33 @@ mod tests { } } + #[test] + fn test_bitwriter() { + let mut output = Vec::new(); + let mut bitwriter = BitWriter::new(&mut output); + + bitwriter.write_bits(0, 0).unwrap(); + bitwriter.write_bits(1, 1).unwrap(); + bitwriter.write_bits(0, 1).unwrap(); + + for i in 1..15 { + // test bit pattern 10, 110, 1110, 11110, etc + bitwriter + .write_bits(((1u32 << i) - 2) as u16, i + 1) + .unwrap(); + } + + bitwriter.pad_byte().unwrap(); + + assert_eq!( + output[..], + [ + 132, 206, 121, 243, 243, 249, 254, 127, 207, 252, 255, 0, 231, 255, 0, 159, 255, 0, + 127 + ] + ) + } + #[test] fn encode_block_all_zero() { let mut output = Vec::new(); @@ -1198,6 +1307,46 @@ mod tests { test::black_box(output); } + #[cfg(feature = "benchmarks")] + #[bench] + fn bench_encode_block_old(b: &mut Bencher) { + let mut output = Vec::with_capacity(65536); + + static BLOCK: [i32; 64] = [ + -416, 180, 100, 71, -42, 20, 20, -51, -18, -19, -182, -151, 120, 120, 120, 120, -120, + 22, 441, 120, 660, 120, 100, 101, -123, 0, -132, 0, 0, 0, 0, -12, -121, 442, 10, 10, + 10, 0, 0, 0, 0, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, + ]; + + // allocate a large buffer that we walk through so that we don't get unrealistic behavior with everything in the L1 cache + let mut memoryvec = Vec::new(); + memoryvec.resize(1024 * 1024, BLOCK); + + let mut numiter = 0; + let mut bitwriter = BitWriter::new(&mut output); + + b.iter(|| { + bitwriter + .write_block_old( + &memoryvec[numiter % (1024 * 1024)], + test::black_box(0), + &test::black_box(STD_LUMA_DC_HUFF_LUT), + &test::black_box(STD_LUMA_AC_HUFF_LUT), + ) + .unwrap(); + + numiter += 1; + }); + + bitwriter.pad_byte().unwrap(); + drop(bitwriter); + + b.bytes = output.len() as u64 / (numiter as u64); + + test::black_box(output); + } + #[cfg(feature = "benchmarks")] #[bench] fn bench_jpeg_encoder_new(b: &mut Bencher) { From 8693351f2b1f849261b30df38f35f9e488ff53d4 Mon Sep 17 00:00:00 2001 From: Kristof Date: Thu, 29 Feb 2024 10:25:53 +0100 Subject: [PATCH 6/8] fix merge --- src/codecs/jpeg/encoder.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index db317459f1..2847f88fbf 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -250,6 +250,7 @@ impl BitWriter { self.write_bits(code, size) } + #[cfg(feature = "benchmarks")] fn write_block_old( &mut self, block: &[i32; 64], @@ -260,7 +261,7 @@ impl BitWriter { // Differential DC encoding let dcval = block[0]; let diff = dcval - prevdc; - let (size, value) = encode_coefficient(diff); + let (size, value) = encode_coefficient_old(diff); self.huffman_encode(size, dctable)?; self.write_bits(value, size)?; @@ -277,7 +278,7 @@ impl BitWriter { zero_run -= 16; } - let (size, value) = encode_coefficient(block[k as usize]); + let (size, value) = encode_coefficient_old(block[k as usize]); let symbol = (zero_run << 4) | size; self.huffman_encode(symbol, actable)?; @@ -855,6 +856,27 @@ fn build_quantization_segment(m: &mut Vec, precision: u8, identifier: u8, qt } } +#[cfg(feature = "benchmarks")] +fn encode_coefficient_old(coefficient: i32) -> (u8, u16) { + let mut magnitude = coefficient.unsigned_abs() as u16; + let mut num_bits = 0u8; + + while magnitude > 0 { + magnitude >>= 1; + num_bits += 1; + } + + let mask = (1 << num_bits as usize) - 1; + + let val = if coefficient < 0 { + (coefficient - 1) as u16 & mask + } else { + coefficient as u16 & mask + }; + + (num_bits, val) +} + #[inline] fn encode_coefficient(coefficient: i32) -> (u8, u16) { // since this is inlined, in the main AC case the compiler figures out that coefficient cannot be zero, so BSR on x86 doesn't need a branch From b6ec25291eb5a76c2515c807d0d3765d3bd7e083 Mon Sep 17 00:00:00 2001 From: Kristof Date: Sat, 2 Mar 2024 09:06:43 +0100 Subject: [PATCH 7/8] fix clippy --- src/codecs/jpeg/encoder.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index 2847f88fbf..1ce6199be2 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -339,14 +339,14 @@ impl BitWriter { zero_run -= 16; } - (size, value) = encode_coefficient(tmp as i32); + (size, value) = encode_coefficient(tmp); symbol = (zero_run << 4) | size; break; } } } else { - (size, value) = encode_coefficient(tmp as i32); + (size, value) = encode_coefficient(tmp); symbol = size; } @@ -890,9 +890,9 @@ fn encode_coefficient(coefficient: i32) -> (u8, u16) { let n = (nz.get() as u32).wrapping_add(adjustment) as u16; // turn v into a 2s complement of s bits let s = 32 - leading_zeros; - return (s, n); + (s, n) } else { - return (0, 0); + (0, 0) } } From eb88b3fe88a81c69443a1e09084fd0c7fba39e8f Mon Sep 17 00:00:00 2001 From: Kristof Date: Sat, 2 Mar 2024 09:16:11 +0100 Subject: [PATCH 8/8] fix clippy --- src/codecs/jpeg/encoder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codecs/jpeg/encoder.rs b/src/codecs/jpeg/encoder.rs index 1ce6199be2..8f7df00826 100644 --- a/src/codecs/jpeg/encoder.rs +++ b/src/codecs/jpeg/encoder.rs @@ -1,7 +1,6 @@ #![allow(clippy::too_many_arguments)] use std::borrow::Cow; -use std::convert::TryFrom; use std::io::{self, Write}; use std::num::NonZeroI32;