From 31c24ca22a1dec41df0ec01ad8f1c06702b091f2 Mon Sep 17 00:00:00 2001 From: Victor Derks Date: Wed, 4 Oct 2023 22:38:19 +0200 Subject: [PATCH 1/2] initial read_header_from_buffer_preceded_with_fill_bytes unit test --- src/jpeg_stream_reader.rs | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/jpeg_stream_reader.rs b/src/jpeg_stream_reader.rs index 84eeeeb..c65a29f 100644 --- a/src/jpeg_stream_reader.rs +++ b/src/jpeg_stream_reader.rs @@ -113,4 +113,59 @@ mod tests { let mut reader = JpegStreamReader::new(buffer.as_slice()); assert!(reader.read_header().is_err()); } + + #[test] + fn read_header_from_buffer_preceded_with_fill_bytes() { + let mut buffer = Vec::new(); + + write_byte(&mut buffer, 0xFF); + write_start_of_image(&mut buffer); + + // writer.write_byte(extra_start_byte); + // writer.write_start_of_frame_segment(1, 1, 2, 1); + // + // writer.write_byte(extra_start_byte); + // writer.write_start_of_scan_segment(0, 1, 1, interleave_mode::none); + + let mut reader = JpegStreamReader::new(buffer.as_slice()); + assert!(reader.read_header().is_ok()); + } + + fn write_byte(buffer: &mut Vec, value: u8) { + buffer.write_all(&[value]).unwrap(); + } + + fn write_start_of_image(buffer: &mut Vec) { + buffer.write_all(&[0xFF, 0xD8]).unwrap(); + } + + fn write_start_of_frame_segment(buffer: &mut Vec, width: u16, height: u16, bits_per_sample: u8, + component_count: u16) { + // Create a Frame Header as defined in T.87, C.2.2 and T.81, B.2.2 + let mut segment = Vec::new(); + + write_byte(&mut segment, bits_per_sample); // P = Sample precision + // push_back(segment, static_cast(height)); // Y = Number of lines + // push_back(segment, static_cast(width)); // X = Number of samples per line + // + // // Components + // segment.push_back(static_cast(component_count)); // Nf = Number of image components in frame + // for (int component_id{}; component_id < component_count; ++component_id) + // { + // // Component Specification parameters + // if (componentIdOverride == 0) + // { + // segment.push_back(static_cast(component_id)); // Ci = Component identifier + // } + // else + // { + // segment.push_back(static_cast(componentIdOverride)); // Ci = Component identifier + // } + // segment.push_back(std::byte{0x11}); // Hi + Vi = Horizontal sampling factor + Vertical sampling factor + // segment.push_back( + // std::byte{0}); // Tqi = Quantization table destination selector (reserved for JPEG-LS, should be set to 0) + // } + // + // write_segment(jpeg_marker_code::start_of_frame_jpegls, segment.data(), segment.size()); + } } From fdb26e3467528f4bc437485857a9b5ee8c912f81 Mon Sep 17 00:00:00 2001 From: Victor Derks Date: Fri, 6 Oct 2023 21:08:15 +0200 Subject: [PATCH 2/2] add read_header_from_buffer_preceded_with_fill_bytes --- src/jpeg_stream_reader.rs | 104 ++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 37 deletions(-) diff --git a/src/jpeg_stream_reader.rs b/src/jpeg_stream_reader.rs index c65a29f..9c7652f 100644 --- a/src/jpeg_stream_reader.rs +++ b/src/jpeg_stream_reader.rs @@ -10,10 +10,10 @@ use crate::decoding_error::DecodingError; #[derive(Clone, Debug)] pub struct FrameInfo { - width: u32, - height: u32, + width: u32, + height: u32, bits_per_sample: u8, - component_count: u8 + component_count: u8, } @@ -27,7 +27,7 @@ enum ReaderState FrameSection, ScanSection, BitStreamSection, - AfterEndOfImage + AfterEndOfImage, } @@ -35,7 +35,7 @@ enum ReaderState pub struct JpegStreamReader { reader: R, frame_info: FrameInfo, - state: ReaderState + state: ReaderState, } @@ -52,9 +52,9 @@ impl JpegStreamReader { width, height, bits_per_sample, - component_count + component_count, }, - state: ReaderState::BeforeStartOfImage + state: ReaderState::BeforeStartOfImage, } } @@ -74,7 +74,7 @@ impl JpegStreamReader { return Err(DecodingError::StartOfImageMarkerNotFound); } - return Ok(r.unwrap()) + return Ok(r.unwrap()); } pub fn read_header(&mut self) -> Result<(), DecodingError> { @@ -116,16 +116,17 @@ mod tests { #[test] fn read_header_from_buffer_preceded_with_fill_bytes() { + let extra_start_byte = 0xFFu8; let mut buffer = Vec::new(); - write_byte(&mut buffer, 0xFF); + write_byte(&mut buffer, extra_start_byte); write_start_of_image(&mut buffer); - // writer.write_byte(extra_start_byte); - // writer.write_start_of_frame_segment(1, 1, 2, 1); - // - // writer.write_byte(extra_start_byte); - // writer.write_start_of_scan_segment(0, 1, 1, interleave_mode::none); + write_byte(&mut buffer, extra_start_byte); + write_start_of_frame_segment(&mut buffer, 1, 1, 2, 1); + + write_byte(&mut buffer, extra_start_byte); + write_start_of_scan_segment(&mut buffer, 0, 1, 1, 0); let mut reader = JpegStreamReader::new(buffer.as_slice()); assert!(reader.read_header().is_ok()); @@ -135,37 +136,66 @@ mod tests { buffer.write_all(&[value]).unwrap(); } + fn write_u16(buffer: &mut Vec, value: u16) { + buffer.write_all(&value.to_be_bytes()).unwrap(); + } + + fn write_marker(buffer: &mut Vec, marker_code: JpegMarkerCode) + { + write_byte(buffer, 0xFF); + write_byte(buffer, marker_code as u8); + } + fn write_start_of_image(buffer: &mut Vec) { buffer.write_all(&[0xFF, 0xD8]).unwrap(); } fn write_start_of_frame_segment(buffer: &mut Vec, width: u16, height: u16, bits_per_sample: u8, - component_count: u16) { + component_count: u16) { // Create a Frame Header as defined in T.87, C.2.2 and T.81, B.2.2 let mut segment = Vec::new(); write_byte(&mut segment, bits_per_sample); // P = Sample precision - // push_back(segment, static_cast(height)); // Y = Number of lines - // push_back(segment, static_cast(width)); // X = Number of samples per line - // - // // Components - // segment.push_back(static_cast(component_count)); // Nf = Number of image components in frame - // for (int component_id{}; component_id < component_count; ++component_id) - // { - // // Component Specification parameters - // if (componentIdOverride == 0) - // { - // segment.push_back(static_cast(component_id)); // Ci = Component identifier - // } - // else - // { - // segment.push_back(static_cast(componentIdOverride)); // Ci = Component identifier - // } - // segment.push_back(std::byte{0x11}); // Hi + Vi = Horizontal sampling factor + Vertical sampling factor - // segment.push_back( - // std::byte{0}); // Tqi = Quantization table destination selector (reserved for JPEG-LS, should be set to 0) - // } - // - // write_segment(jpeg_marker_code::start_of_frame_jpegls, segment.data(), segment.size()); + write_u16(&mut segment, height); // Y = Number of lines + write_u16(&mut segment, width); // X = Number of samples per line + + // Components + write_byte(&mut segment, component_count as u8); // Nf = Number of image components in frame + + for component_id in 0..component_count as u8 { + // Component Specification parameters + write_byte(&mut segment, component_id); // Ci = Component identifier + write_byte(&mut segment, 0x11); // Hi + Vi = Horizontal sampling factor + Vertical sampling factor + write_byte(&mut segment, 0); // Tqi = Quantization table destination selector (reserved for JPEG-LS, should be set to 0) + } + + write_segment(buffer, JpegMarkerCode::StartOfFrameJpegls, &segment); + } + + fn write_start_of_scan_segment(buffer: &mut Vec, component_id: u8, component_count: u8, near_lossless: u8, + interleave_mode: u8) { + // Create a Scan Header as defined in T.87, C.2.3 and T.81, B.2.3 + let mut segment = Vec::new(); + + write_byte(&mut segment, component_count); + for component_id in 0..component_count { + write_byte(&mut segment, component_id); + write_byte(&mut segment, 0); // Mapping table selector (0 = no table) + } + + write_byte(&mut segment, near_lossless); // NEAR parameter + write_byte(&mut segment, interleave_mode); // ILV parameter + write_byte(&mut segment, 0); // transformation + + write_segment(buffer, JpegMarkerCode::StartOfScan, &segment); + } + + fn write_segment(buffer: &mut Vec, marker_code: JpegMarkerCode, segment_data: &Vec) + { + buffer.write_all(&[0xFF, 0xD8]).unwrap(); + + write_marker(buffer, marker_code); + write_u16(buffer, (segment_data.len() + 2) as u16); + buffer.write_all(segment_data).unwrap(); } }