Skip to content

Commit e0a80af

Browse files
committed
added padding test, fixed corresponding bugs, removed printlns
1 parent 9f704d8 commit e0a80af

File tree

1 file changed

+146
-63
lines changed

1 file changed

+146
-63
lines changed

src/predictor.rs

+146-63
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ impl RevPredict for RevHorizontalPredictor {
109109
/// Reverse predictor convenienve function for horizontal differencing
110110
///
111111
/// From image-tiff
112+
///
113+
/// This should be used _after_ endianness fixing
112114
pub fn rev_hpredict_nsamp(buf: &mut [u8], bit_depth: u16, samples: usize) {
113115
match bit_depth {
114116
0..=8 => {
@@ -203,7 +205,7 @@ impl RevPredict for RevFloatingPointPredictor {
203205
16 => rev_predict_f16(in_buf, out_buf, predictor_info.samples_per_pixel as _),
204206
32 => rev_predict_f32(in_buf, out_buf, predictor_info.samples_per_pixel as _),
205207
64 => rev_predict_f64(in_buf, out_buf, predictor_info.samples_per_pixel as _),
206-
_ => panic!("thou shalt not predict with float16"),
208+
_ => panic!("thou shalt not predict f24"),
207209
}
208210
}
209211
} else {
@@ -219,15 +221,18 @@ impl RevPredict for RevFloatingPointPredictor {
219221
{
220222
let mut out_row = BytesMut::zeroed(input_row_stride);
221223
match bit_depth {
222-
16 => rev_predict_f16(in_buf, out_buf, predictor_info.samples_per_pixel as _),
224+
16 => {
225+
rev_predict_f16(in_buf, &mut out_row, predictor_info.samples_per_pixel as _)
226+
}
223227
32 => {
224228
rev_predict_f32(in_buf, &mut out_row, predictor_info.samples_per_pixel as _)
225229
}
226230
64 => {
227231
rev_predict_f64(in_buf, &mut out_row, predictor_info.samples_per_pixel as _)
228232
}
229-
_ => panic!("thou shalt not predict f16"),
233+
_ => panic!("thou shalt not predict f24"),
230234
}
235+
// remove the padding bytes
231236
out_buf.copy_from_slice(&out_row[..output_row_stride]);
232237
}
233238
}
@@ -250,7 +255,7 @@ pub fn rev_predict_f16(input: &mut [u8], output: &mut [u8], samples: usize) {
250255
for (i, chunk) in output.chunks_mut(2).enumerate() {
251256
chunk.copy_from_slice(&u16::to_ne_bytes(
252257
// convert to native-endian
253-
// preserve original byte-order
258+
// floating predictor is be-like
254259
u16::from_be_bytes([input[i], input[input.len() / 2 + i]]),
255260
));
256261
}
@@ -267,20 +272,20 @@ pub fn rev_predict_f32(input: &mut [u8], output: &mut [u8], samples: usize) {
267272
for i in samples..input.len() {
268273
input[i] = input[i].wrapping_add(input[i - samples]);
269274
}
270-
println!("output: {output:?}, {:?}", output.len());
271275
// reverse byte shuffle and fix endianness
272276
for (i, chunk) in output.chunks_mut(4).enumerate() {
273-
println!("i:{i:?}");
274-
chunk.copy_from_slice(&u32::to_ne_bytes(
277+
chunk.copy_from_slice(
275278
// convert to native-endian
276-
// preserve original byte-order
277-
u32::from_be_bytes([
278-
input[i],
279-
input[input.len() / 4 + i],
280-
input[input.len() / 4 * 2 + i],
281-
input[input.len() / 4 * 3 + i],
282-
]),
283-
));
279+
&u32::to_ne_bytes(
280+
// floating predictor is be-like
281+
u32::from_be_bytes([
282+
input[i],
283+
input[input.len() / 4 + i],
284+
input[input.len() / 4 * 2 + i],
285+
input[input.len() / 4 * 3 + i],
286+
]),
287+
),
288+
);
284289
}
285290
}
286291

@@ -295,16 +300,22 @@ pub fn rev_predict_f64(input: &mut [u8], output: &mut [u8], samples: usize) {
295300
}
296301

297302
for (i, chunk) in output.chunks_mut(8).enumerate() {
298-
chunk.copy_from_slice(&u64::to_ne_bytes(u64::from_be_bytes([
299-
input[i],
300-
input[input.len() / 8 + i],
301-
input[input.len() / 8 * 2 + i],
302-
input[input.len() / 8 * 3 + i],
303-
input[input.len() / 8 * 4 + i],
304-
input[input.len() / 8 * 5 + i],
305-
input[input.len() / 8 * 6 + i],
306-
input[input.len() / 8 * 7 + i],
307-
])));
303+
chunk.copy_from_slice(
304+
// convert to native-endian
305+
&u64::to_ne_bytes(
306+
// floating predictor is be-like
307+
u64::from_be_bytes([
308+
input[i],
309+
input[input.len() / 8 + i],
310+
input[input.len() / 8 * 2 + i],
311+
input[input.len() / 8 * 3 + i],
312+
input[input.len() / 8 * 4 + i],
313+
input[input.len() / 8 * 5 + i],
314+
input[input.len() / 8 * 6 + i],
315+
input[input.len() / 8 * 7 + i],
316+
]),
317+
),
318+
);
308319
}
309320
}
310321

@@ -453,7 +464,7 @@ mod test {
453464
assert_eq!(p.rev_predict_fix_endianness(buffer, &predictor_info, x, y).unwrap(), res);
454465
println!("testing i32");
455466
predictor_info.bits_per_sample = &[32];
456-
let buffer = Bytes::from(input.iter().flat_map(|v| (*v as i32).to_le_bytes()).collect::<Vec<_>>());
467+
let buffer = Bytes::from(input.iter().flat_map(|v| v.to_le_bytes()).collect::<Vec<_>>());
457468
let res = Bytes::from(expected.iter().flat_map(|v| (*v as i32).to_ne_bytes()).collect::<Vec<_>>());
458469
assert_eq!(p.rev_predict_fix_endianness(buffer, &predictor_info, x, y).unwrap(), res);
459470
println!("testing i64");
@@ -508,7 +519,7 @@ mod test {
508519
assert_eq!(-1i32 as u32, u32::MAX);
509520
println!("testing i32");
510521
predictor_info.bits_per_sample = &[32];
511-
let buffer = Bytes::from(input.iter().flat_map(|v| (*v as i32).to_be_bytes()).collect::<Vec<_>>());
522+
let buffer = Bytes::from(input.iter().flat_map(|v| v.to_be_bytes()).collect::<Vec<_>>());
512523
let res = Bytes::from(expected.iter().flat_map(|v| (*v as i32).to_ne_bytes()).collect::<Vec<_>>());
513524
assert_eq!(p.rev_predict_fix_endianness(buffer, &predictor_info, x, y).unwrap(), res);
514525
assert_eq!(-1i32 as u64, u64::MAX);
@@ -520,57 +531,129 @@ mod test {
520531
}
521532
}
522533

523-
// #[rustfmt::skip]
534+
#[rustfmt::skip]
535+
#[test]
536+
fn test_predict_f16() {
537+
// take a 4-value image
538+
let expect_le = [1,0,3,2,5,4,7,6u8];
539+
let _expected = [0,1,2,3,4,5,6,7u8];
540+
// 0 1
541+
// 0 1
542+
// 0 1
543+
// 0 1
544+
let _shuffled = [0,2,4,6,1,3,5,7u8];
545+
let diffed = [0,2,2,2,251,2,2,2];
546+
let info = PredictorInfo {
547+
endianness: Endianness::LittleEndian,
548+
image_width: 4+4,
549+
image_height: 4+1,
550+
chunk_width: 4,
551+
chunk_height: 4,
552+
bits_per_sample: &[16],
553+
samples_per_pixel: 1,
554+
sample_format: &[SampleFormat::IEEEFP],
555+
planar_configuration: PlanarConfiguration::Chunky,
556+
};
557+
let input = Bytes::from_owner(diffed);
558+
assert_eq!(
559+
&RevFloatingPointPredictor.rev_predict_fix_endianness(input, &info, 1, 1).unwrap()[..],
560+
&expect_le[..]
561+
)
562+
}
563+
564+
#[rustfmt::skip]
565+
#[test]
566+
fn test_predict_f16_padding() {
567+
// take a 4-pixel image with 2 padding pixels
568+
let expect_le = [1,0,3,2u8]; // no padding
569+
let _expected = [0,1,2,3,0,0,0,0u8]; //padding added
570+
// 0 1
571+
// 0 1
572+
// 0 1
573+
// 0 1
574+
let _shuffled = [0,2,0,0,1,3,0,0u8];
575+
let diffed = [0,2,254,0,1,2,253,0];
576+
let info = PredictorInfo {
577+
endianness: Endianness::LittleEndian,
578+
image_width: 4+2,
579+
image_height: 4+1,
580+
chunk_width: 4,
581+
chunk_height: 4,
582+
bits_per_sample: &[16],
583+
samples_per_pixel: 1,
584+
sample_format: &[SampleFormat::IEEEFP],
585+
planar_configuration: PlanarConfiguration::Chunky,
586+
};
587+
let input = Bytes::from_owner(diffed);
588+
assert_eq!(
589+
&RevFloatingPointPredictor.rev_predict_fix_endianness(input, &info, 1, 1).unwrap()[..],
590+
&expect_le[..]
591+
)
592+
}
593+
594+
#[rustfmt::skip]
524595
#[test]
525596
fn test_fpredict_f32() {
597+
// let's take this 2-value image where we only look at bytes
598+
let expect_le = [3,2, 1,0, 7,6, 5,4];
599+
let _expected = [0,1, 2,3, 4,5, 6,7u8];
600+
// 0 1 2 3 \_ de-shuffling indices
601+
// 0 1 2 3 / (the one the function uses)
602+
let _shuffled = [0,4, 1,5, 2,6, 3,7u8];
603+
let diffed = [0,4,253,4,253,4,253,4u8];
604+
println!("expected: {expect_le:?}");
605+
let mut info = PredictorInfo {
606+
endianness: Endianness::LittleEndian,
607+
image_width: 2,
608+
image_height: 2 + 1,
609+
chunk_width: 2,
610+
chunk_height: 2,
611+
bits_per_sample: &[32],
612+
samples_per_pixel: 1,
613+
sample_format: &[SampleFormat::IEEEFP],
614+
planar_configuration: PlanarConfiguration::Chunky,
615+
};
616+
let input = Bytes::from_owner(diffed);
617+
assert_eq!(
618+
&RevFloatingPointPredictor
619+
.rev_predict_fix_endianness(input.clone(), &info, 0, 1).unwrap()[..],
620+
&expect_le
621+
);
622+
info.endianness = Endianness::BigEndian;
623+
assert_eq!(
624+
&RevFloatingPointPredictor.rev_predict_fix_endianness(input, &info, 0, 1).unwrap()[..],
625+
&expect_le
626+
)
627+
}
628+
629+
#[rustfmt::skip]
630+
#[test]
631+
fn test_fpredict_f64() {
632+
assert_eq!(f64::from_le_bytes([7,6,5,4,3,2,1,0]), f64::from_bits(0x00_01_02_03_04_05_06_07));
526633
// let's take this 2-value image
527-
let expected: Vec<u8> = [42.0f32, 43.0]
528-
.iter()
529-
.flat_map(|f| f.to_le_bytes())
530-
.collect();
531-
assert_eq!(expected, vec![0x0, 0x0, 0x28, 0x42, 0x0, 0x0, 0x2c, 0x42]);
634+
let expect_be = [7,6,5,4,3, 2,1, 0,15,14,13,12,11,10,9,8];
635+
let _expected = [0,1,2,3,4, 5,6, 7,8, 9,10,11,12,13,14,15u8];
636+
// 0 1 2 3 4 5 6 7
637+
// 0 1 2 3 4 5 6 7
638+
let _shuffled = [0,8,1,9,2,10,3,11,4,12, 5,13, 6,14, 7,15u8];
639+
let diffed = [0,8,249,8,249,8,249,8,249,8,249,8,249,8,249,8u8];
532640
let info = PredictorInfo {
533641
endianness: Endianness::LittleEndian,
534642
image_width: 2,
535643
image_height: 2 + 1,
536644
chunk_width: 2,
537645
chunk_height: 2,
538-
bits_per_sample: &[32],
646+
bits_per_sample: &[64],
539647
samples_per_pixel: 1,
540648
sample_format: &[SampleFormat::IEEEFP],
541649
planar_configuration: PlanarConfiguration::Chunky,
542650
};
543-
let input = Bytes::from_static(&[0x42u8, 0, 230, 4, 212, 0, 0, 0]);
651+
let input = Bytes::from_owner(diffed);
544652
assert_eq!(
545-
RevFloatingPointPredictor
653+
&RevFloatingPointPredictor
546654
.rev_predict_fix_endianness(input, &info, 0, 1)
547-
.unwrap(),
548-
expected
655+
.unwrap()[..],
656+
&expect_be[..]
549657
);
550658
}
551-
552-
// #[test]
553-
// fn test_fpredict_f64() {
554-
// // let's take this 2-value image
555-
// let expected: Vec<u8> = [42.0f64, 43.0].iter().flat_map(|f| f.to_le_bytes()).collect();
556-
// assert_eq!(expected, vec![0,0,0,0,0,0,69,64,0,0,0,0,0,128,69,64]);
557-
// let info = PredictorInfo {
558-
// endianness: Endianness::LittleEndian,
559-
// image_width: 2,
560-
// image_height: 2 + 1,
561-
// chunk_width: 2,
562-
// chunk_height: 2,
563-
// bits_per_sample: &[64],
564-
// samples_per_pixel: 1,
565-
// sample_format: &[SampleFormat::IEEEFP],
566-
// planar_configuration: PlanarConfiguration::Chunky,
567-
// };
568-
// let input = Bytes::from_static(&[0x42u8, 0, 230, 4, 212, 0, 0, 0]);
569-
// assert_eq!(
570-
// RevFloatingPointPredictor
571-
// .rev_predict_fix_endianness(input, &info, 0, 1)
572-
// .unwrap(),
573-
// expected
574-
// );
575-
// }
576659
}

0 commit comments

Comments
 (0)