Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

standardize on u32 vs i32 for jpeg coordinates/width etc to support large JPEGs #126

Merged
merged 3 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/enabled_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ pub struct EnabledFeatures {
pub reject_dqts_with_zeros: bool,

/// maximum jpeg width
pub max_jpeg_width: i32,
pub max_jpeg_width: u32,

// maximum jpeg height
pub max_jpeg_height: i32,
pub max_jpeg_height: u32,

/// Sadly C++ version has a bug where it uses 16 bit math in the SIMD path and 32 bit math in the scalar path
pub use_16bit_dc_estimate: bool,
Expand Down Expand Up @@ -53,8 +53,8 @@ impl EnabledFeatures {
Self {
progressive: true,
reject_dqts_with_zeros: false,
max_jpeg_height: i32::MAX,
max_jpeg_width: i32::MAX,
max_jpeg_height: u32::MAX,
max_jpeg_width: u32::MAX,
use_16bit_dc_estimate: false,
use_16bit_adv_predict: false,
accept_invalid_dht: true,
Expand All @@ -70,8 +70,8 @@ impl EnabledFeatures {
Self {
progressive: true,
reject_dqts_with_zeros: false,
max_jpeg_height: i32::MAX,
max_jpeg_width: i32::MAX,
max_jpeg_height: u32::MAX,
max_jpeg_width: u32::MAX,
use_16bit_dc_estimate: true,
use_16bit_adv_predict: true,
accept_invalid_dht: true,
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ Options:
override_if(
&mut pargs,
"--max-width",
parse_i32,
parse_u32,
&mut enabled_features.max_jpeg_width,
)?;

override_if(
&mut pargs,
"--max-height",
parse_i32,
parse_u32,
&mut enabled_features.max_jpeg_height,
)?;

Expand Down
8 changes: 4 additions & 4 deletions src/structs/bit_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ pub struct BitReader<R> {
}

impl<R: BufRead + Seek> BitReader<R> {
pub fn get_stream_position(&mut self) -> i32 {
pub fn get_stream_position(&mut self) -> u32 {
self.undo_read_ahead();

let pos: i32 = (self.inner.stream_position().unwrap() - self.start_offset)
let pos: u32 = (self.inner.stream_position().unwrap() - self.start_offset)
.try_into()
.unwrap();

Expand Down Expand Up @@ -299,7 +299,7 @@ use std::io::Cursor;
// test reading a simple bit pattern with an escaped 0xff inside it.
#[test]
fn read_simple() {
let arr = [0x12 as u8, 0x34, 0x45, 0x67, 0x89, 0xff, 00, 0xee];
let arr = [0x12u8, 0x34, 0x45, 0x67, 0x89, 0xff, 00, 0xee];

let mut b = BitReader::new(Cursor::new(&arr));

Expand Down Expand Up @@ -338,7 +338,7 @@ fn read_simple() {
// what happens when a file has 0xff as the last character (assume that it is an escaped 0xff)
#[test]
fn read_truncate_ff() {
let arr = [0x12 as u8, 0xff];
let arr = [0x12u8, 0xff];

let mut b = BitReader::new(Cursor::new(&arr));

Expand Down
4 changes: 2 additions & 2 deletions src/structs/bit_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ use crate::structs::bit_reader::BitReader;
// write a test pattern with an escape and see if it matches
#[test]
fn write_simple() {
let arr = [0x12 as u8, 0x34, 0x45, 0x67, 0x89, 0xff, 00, 0xee];
let arr = [0x12, 0x34, 0x45, 0x67, 0x89, 0xff, 00, 0xee];

let mut b = BitWriter::new(1024);

Expand All @@ -178,7 +178,7 @@ fn roundtrip_bits() {
{
let mut b = BitWriter::new(1024);
for i in 1..2048 {
b.write(i, u32_bit_length(i as u32) as u32);
b.write(i, u32_bit_length(i) as u32);
}

b.pad(0xff);
Expand Down
42 changes: 21 additions & 21 deletions src/structs/block_based_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ use crate::structs::jpeg_header::JPegHeader;
/// the image may only hold a subset of the components (specified by dpos_offset),
/// but they can be merged
pub struct BlockBasedImage {
block_width: i32,
block_width: u32,

original_height: i32,
original_height: u32,

dpos_offset: i32,
dpos_offset: u32,

image: Vec<AlignedBlock>,
}
Expand All @@ -32,22 +32,22 @@ impl BlockBasedImage {
pub fn new(
jpeg_header: &JPegHeader,
component: usize,
luma_y_start: i32,
luma_y_end: i32,
luma_y_start: u32,
luma_y_end: u32,
) -> Self {
let block_width = jpeg_header.cmp_info[component].bch;
let original_height = jpeg_header.cmp_info[component].bcv;
let max_size = block_width * original_height;

let image_capcity = usize::try_from(
(i64::from(max_size) * i64::from(luma_y_end - luma_y_start)
+ i64::from(jpeg_header.cmp_info[0].bcv - 1 /* round up */))
/ i64::from(jpeg_header.cmp_info[0].bcv),
(u64::from(max_size) * u64::from(luma_y_end - luma_y_start)
+ u64::from(jpeg_header.cmp_info[0].bcv - 1 /* round up */))
/ u64::from(jpeg_header.cmp_info[0].bcv),
)
.unwrap();

let dpos_offset = i32::try_from(
i64::from(max_size) * i64::from(luma_y_start) / i64::from(jpeg_header.cmp_info[0].bcv),
let dpos_offset = u32::try_from(
u64::from(max_size) * u64::from(luma_y_start) / u64::from(jpeg_header.cmp_info[0].bcv),
)
.unwrap();

Expand All @@ -70,7 +70,7 @@ impl BlockBasedImage {

for v in images {
assert!(
v[index].dpos_offset == contents.len() as i32,
v[index].dpos_offset == contents.len() as u32,
"previous content should match new content"
);

Expand Down Expand Up @@ -111,20 +111,20 @@ impl BlockBasedImage {
}

// blocks above the first line are never dereferenced
pub fn off_y(&self, y: i32) -> BlockContext {
pub fn off_y(&self, y: u32) -> BlockContext {
return BlockContext::new(
self.block_width * y,
self.block_width * (y - 1),
if y > 0 { self.block_width * (y - 1) } else { 0 },
if (y & 1) != 0 { self.block_width } else { 0 },
if (y & 1) != 0 { 0 } else { self.block_width },
);
}

pub fn get_block_width(&self) -> i32 {
pub fn get_block_width(&self) -> u32 {
self.block_width
}

pub fn get_original_height(&self) -> i32 {
pub fn get_original_height(&self) -> u32 {
self.original_height
}

Expand All @@ -133,7 +133,7 @@ impl BlockBasedImage {
#[inline(always)]
pub fn fill_up_to_dpos(
&mut self,
dpos: i32,
dpos: u32,
block_to_write: Option<AlignedBlock>,
) -> &mut AlignedBlock {
// ensure that dpos_offset got set to the right value when we start writing
Expand All @@ -149,7 +149,7 @@ impl BlockBasedImage {
if relative_offset < self.image.len() {
// rewrite already written block
if let Some(b) = block_to_write {
self.image[relative_offset as usize] = b;
self.image[relative_offset] = b;
}
} else {
// need to extend the image length and add any necessary
Expand All @@ -166,14 +166,14 @@ impl BlockBasedImage {
self.image.push(block_to_write.unwrap_or_default());
}

return &mut self.image[relative_offset as usize];
return &mut self.image[relative_offset];
}

pub fn set_block_data(&mut self, dpos: i32, block_data: AlignedBlock) {
pub fn set_block_data(&mut self, dpos: u32, block_data: AlignedBlock) {
self.fill_up_to_dpos(dpos, Some(block_data));
}

pub fn get_block(&self, dpos: i32) -> &AlignedBlock {
pub fn get_block(&self, dpos: u32) -> &AlignedBlock {
if (dpos - self.dpos_offset) as usize >= self.image.len() {
return &EMPTY;
} else {
Expand All @@ -191,7 +191,7 @@ impl BlockBasedImage {
}

#[inline(always)]
pub fn get_block_mut(&mut self, dpos: i32) -> &mut AlignedBlock {
pub fn get_block_mut(&mut self, dpos: u32) -> &mut AlignedBlock {
self.fill_up_to_dpos(dpos, None)
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/structs/block_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ use crate::structs::block_based_image::{AlignedBlock, BlockBasedImage, EMPTY_BLO
use crate::structs::neighbor_summary::{NeighborSummary, NEIGHBOR_DATA_EMPTY};
use crate::structs::probability_tables::ProbabilityTables;
pub struct BlockContext {
cur_block_index: i32,
above_block_index: i32,
cur_block_index: u32,
above_block_index: u32,

cur_neighbor_summary_index: i32,
above_neighbor_summary_index: i32,
cur_neighbor_summary_index: u32,
above_neighbor_summary_index: u32,
}
pub struct NeighborData<'a> {
pub above: &'a AlignedBlock,
Expand All @@ -25,13 +25,13 @@ pub struct NeighborData<'a> {
impl BlockContext {
// for debugging
#[allow(dead_code)]
pub fn get_here_index(&self) -> i32 {
pub fn get_here_index(&self) -> u32 {
self.cur_block_index
}

// as each new line BlockContext is set by `off_y`, no edge cases with dereferencing
// out of bounds indices is possilbe, therefore no special treatment is needed
pub fn next(&mut self) -> i32 {
pub fn next(&mut self) -> u32 {
self.cur_block_index += 1;
self.above_block_index += 1;
self.cur_neighbor_summary_index += 1;
Expand All @@ -41,10 +41,10 @@ impl BlockContext {
}

pub fn new(
cur_block_index: i32,
above_block_index: i32,
cur_neighbor_summary_index: i32,
above_neighbor_summary_index: i32,
cur_block_index: u32,
above_block_index: u32,
cur_neighbor_summary_index: u32,
above_neighbor_summary_index: u32,
) -> Self {
return BlockContext {
cur_block_index,
Expand Down
2 changes: 1 addition & 1 deletion src/structs/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ fn test_all_probabilities() {
continue;
}

let mut new_f = Branch { counts: i as u16 };
let mut new_f = Branch { counts: i };

for _k in 0..10 {
old_f.record_obs_and_update(false);
Expand Down
40 changes: 20 additions & 20 deletions src/structs/component_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,34 @@ pub struct ComponentInfo {
pub huff_ac: u8,

/// sample factor vertical
pub sfv: i32,
pub sfv: u32,

/// sample factor horizontal
pub sfh: i32,
pub sfh: u32,

/// blocks in mcu
pub mbs: i32,
pub mbs: u32,

/// block count vertical (interleaved)
pub bcv: i32,
pub bcv: u32,

/// block count horizontal (interleaved)
pub bch: i32,
pub bch: u32,

/// block count (all) (interleaved)
pub bc: i32,
pub bc: u32,

/// block count vertical (non interleaved)
pub ncv: i32,
pub ncv: u32,

/// block count horizontal (non interleaved)
pub nch: i32,
pub nch: u32,

/// block count (all) (non interleaved)
pub nc: i32,
pub nc: u32,

/// statistical identity
pub sid: i32,
pub sid: u32,

/// jpeg internal id
pub jid: u8,
Expand All @@ -53,16 +53,16 @@ impl Default for ComponentInfo {
fn default() -> ComponentInfo {
return ComponentInfo {
q_table_index: 0xff,
sfv: -1,
sfh: -1,
mbs: -1,
bcv: -1,
bch: -1,
bc: -1,
ncv: -1,
nch: -1,
nc: -1,
sid: -1,
sfv: u32::MAX,
sfh: u32::MAX,
mbs: u32::MAX,
bcv: u32::MAX,
bch: u32::MAX,
bc: u32::MAX,
ncv: u32::MAX,
nch: u32::MAX,
nc: u32::MAX,
sid: u32::MAX,
jid: 0xff,
huff_dc: 0xff,
huff_ac: 0xff,
Expand Down
Loading