pub mod detector; pub mod readsolomon; use std::collections::HashMap; use crate::{ Binarizer, Binarizer, FormatException, LuminanceSource, NotFoundException, NotFoundException, ResultPoint, }; // ECIInput.java /** * Interface to navigate a sequence of ECIs and bytes. * * @author Alex Geller */ pub trait ECIInput { /** * Returns the length of this input. The length is the number * of {@code byte}s in or ECIs in the sequence. * * @return the number of {@code char}s in this sequence */ fn length(&self) -> i32; /** * Returns the {@code byte} value at the specified index. An index ranges from zero * to {@code length() - 1}. The first {@code byte} value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing. * * @param index the index of the {@code byte} value to be returned * * @return the specified {@code byte} value as character or the FNC1 character * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} * @throws IllegalArgumentException * if the value at the {@code index} argument is an ECI (@see #isECI) */ fn char_at(&self, index: i32) -> char; /** * Returns a {@code CharSequence} that is a subsequence of this sequence. * The subsequence starts with the {@code char} value at the specified index and * ends with the {@code char} value at index {@code end - 1}. The length * (in {@code char}s) of the * returned sequence is {@code end - start}, so if {@code start == end} * then an empty sequence is returned. * * @param start the start index, inclusive * @param end the end index, exclusive * * @return the specified subsequence * * @throws IndexOutOfBoundsException * if {@code start} or {@code end} are negative, * if {@code end} is greater than {@code length()}, * or if {@code start} is greater than {@code end} * @throws IllegalArgumentException * if a value in the range {@code start}-{@code end} is an ECI (@see #isECI) */ fn sub_sequence(&self, start: i32, end: i32) -> CharSequence; /** * Determines if a value is an ECI * * @param index the index of the value * * @return true if the value at position {@code index} is an ECI * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} */ fn is_e_c_i(&self, index: i32) -> bool; /** * Returns the {@code int} ECI value at the specified index. An index ranges from zero * to {@code length() - 1}. The first {@code byte} value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing. * * @param index the index of the {@code int} value to be returned * * @return the specified {@code int} ECI value. * The ECI specified the encoding of all bytes with a higher index until the * next ECI or until the end of the input if no other ECI follows. * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} * @throws IllegalArgumentException * if the value at the {@code index} argument is not an ECI (@see #isECI) */ fn get_e_c_i_value(&self, index: i32) -> i32; fn have_n_characters(&self, index: i32, n: i32) -> bool; } // GridSampler.java /** * Implementations of this class can, given locations of finder patterns for a QR code in an * image, sample the right points in the image to reconstruct the QR code, accounting for * perspective distortion. It is abstracted since it is relatively expensive and should be allowed * to take advantage of platform-specific optimized implementations, like Sun's Java Advanced * Imaging library, but which may not be available in other environments such as J2ME, and vice * versa. * * The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)} * with an instance of a class which implements this interface. * * @author Sean Owen */ //let grid_sampler: dyn GridSampler = DefaultGridSampler::new(); pub struct GridSampler { grid_sampler: dyn GridSampler, } impl GridSampler { pub fn new() -> Self { Self { grid_sampler: DefaultGridSampler::new(), } } /** * Sets the implementation of GridSampler used by the library. One global * instance is stored, which may sound problematic. But, the implementation provided * ought to be appropriate for the entire platform, and all uses of this library * in the whole lifetime of the JVM. For instance, an Android activity can swap in * an implementation that takes advantage of native platform libraries. * * @param newGridSampler The platform-specific object to install. */ pub fn set_grid_sampler(new_grid_sampler: &GridSampler) { grid_sampler = new_grid_sampler; } /** * @return the current implementation of GridSampler */ pub fn get_instance() -> GridSampler { return grid_sampler; } /** * Samples an image for a rectangular matrix of bits of the given dimension. The sampling * transformation is determined by the coordinates of 4 points, in the original and transformed * image space. * * @param image image to sample * @param dimensionX width of {@link BitMatrix} to sample from image * @param dimensionY height of {@link BitMatrix} to sample from image * @param p1ToX point 1 preimage X * @param p1ToY point 1 preimage Y * @param p2ToX point 2 preimage X * @param p2ToY point 2 preimage Y * @param p3ToX point 3 preimage X * @param p3ToY point 3 preimage Y * @param p4ToX point 4 preimage X * @param p4ToY point 4 preimage Y * @param p1FromX point 1 image X * @param p1FromY point 1 image Y * @param p2FromX point 2 image X * @param p2FromY point 2 image Y * @param p3FromX point 3 image X * @param p3FromY point 3 image Y * @param p4FromX point 4 image X * @param p4FromY point 4 image Y * @return {@link BitMatrix} representing a grid of points sampled from the image within a region * defined by the "from" parameters * @throws NotFoundException if image can't be sampled, for example, if the transformation defined * by the given points is invalid or results in sampling outside the image boundaries */ pub fn sample_grid( &self, image: &BitMatrix, dimension_x: i32, dimension_y: i32, p1_to_x: f32, p1_to_y: f32, p2_to_x: f32, p2_to_y: f32, p3_to_x: f32, p3_to_y: f32, p4_to_x: f32, p4_to_y: f32, p1_from_x: f32, p1_from_y: f32, p2_from_x: f32, p2_from_y: f32, p3_from_x: f32, p3_from_y: f32, p4_from_x: f32, p4_from_y: f32, ) -> Result; pub fn sample_grid( &self, image: &BitMatrix, dimension_x: i32, dimension_y: i32, transform: &PerspectiveTransform, ) -> Result; /** *

Checks a set of points that have been transformed to sample points on an image against * the image's dimensions to see if the point are even within the image.

* *

This method will actually "nudge" the endpoints back onto the image if they are found to be * barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder * patterns in an image where the QR Code runs all the way to the image border.

* *

For efficiency, the method will check points from either end of the line until one is found * to be within the image. Because the set of points are assumed to be linear, this is valid.

* * @param image image into which the points should map * @param points actual points in x1,y1,...,xn,yn form * @throws NotFoundException if an endpoint is lies outside the image boundaries */ pub fn check_and_nudge_points( image: &BitMatrix, points: &Vec, ) -> Result<(), NotFoundException> { let width: i32 = image.get_width(); let height: i32 = image.get_height(); // Check and nudge points from start until we see some that are OK: let mut nudged: bool = true; // points.length must be even let max_offset: i32 = points.len() - 1; { let mut offset: i32 = 0; while offset < max_offset && nudged { { let x: i32 = points[offset] as i32; let y: i32 = points[offset + 1] as i32; if x < -1 || x > width || y < -1 || y > height { return Err(NotFoundException::get_not_found_instance()); } nudged = false; if x == -1 { points[offset] = 0.0f32; nudged = true; } else if x == width { points[offset] = width - 1.0; nudged = true; } if y == -1 { points[offset + 1] = 0.0f32; nudged = true; } else if y == height { points[offset + 1] = height - 1.0; nudged = true; } } offset += 2; } } // Check and nudge points from end: nudged = true; { let mut offset: i32 = points.len() - 2; while offset >= 0 && nudged { { let x: i32 = points[offset] as i32; let y: i32 = points[offset + 1] as i32; if x < -1 || x > width || y < -1 || y > height { return Err(NotFoundException::get_not_found_instance()); } nudged = false; if x == -1 { points[offset] = 0.0f32; nudged = true; } else if x == width { points[offset] = width - 1.0; nudged = true; } if y == -1 { points[offset + 1] = 0.0f32; nudged = true; } else if y == height { points[offset + 1] = height - 1.0; nudged = true; } } offset -= 2; } } Ok(()) } } // GlobalHistogramBinarizer.java /** * This Binarizer implementation uses the old ZXing global histogram approach. It is suitable * for low-end mobile devices which don't have enough CPU or memory to use a local thresholding * algorithm. However, because it picks a global black point, it cannot handle difficult shadows * and gradients. * * Faster mobile devices and all desktop applications should probably use HybridBinarizer instead. * * @author dswitkin@google.com (Daniel Switkin) * @author Sean Owen */ const LUMINANCE_BITS: i32 = 5; const LUMINANCE_SHIFT: i32 = 8 - LUMINANCE_BITS; const LUMINANCE_BUCKETS: i32 = 1 << LUMINANCE_BITS; const EMPTY: [i8; 0] = [0; 0]; pub struct GlobalHistogramBinarizer { //super: Binarizer; luminances: Vec, buckets: Vec, } impl Binarizer for GlobalHistogramBinarizer { // Applies simple sharpening to the row data to improve performance of the 1D Readers. fn get_black_row(&self, y: i32, row: &BitArray) -> Result { let source: LuminanceSource = get_luminance_source(); let width: i32 = source.get_width(); if row == null || row.get_size() < width { row = &BitArray::new(None, Some(width)); } else { row.clear(); } self.init_arrays(width); let local_luminances: Vec = source.get_row(y, &self.luminances); let local_buckets: Vec = self.buckets; { let mut x: i32 = 0; while x < width { { local_buckets[(local_luminances[x] & 0xff) >> LUMINANCE_SHIFT] += 1; } x += 1; } } let black_point: i32 = ::estimate_black_point(&local_buckets); if width < 3 { // Special case for very small images { let mut x: i32 = 0; while x < width { { if (local_luminances[x] & 0xff) < black_point { row.set(x); } } x += 1; } } } else { let mut left: i32 = local_luminances[0] & 0xff; let mut center: i32 = local_luminances[1] & 0xff; { let mut x: i32 = 1; while x < width - 1 { { let right: i32 = local_luminances[x + 1] & 0xff; // A simple -1 4 -1 box filter with a weight of 2. if ((center * 4) - left - right) / 2 < black_point { row.set(x); } left = center; center = right; } x += 1; } } } return Ok(row); } // Does not sharpen the data, as this call is intended to only be used by 2D Readers. fn get_black_matrix(&self) -> Result> { let source: LuminanceSource = get_luminance_source(); let width: i32 = source.get_width(); let height: i32 = source.get_height(); let matrix: BitMatrix = BitMatrix::new(width, height, None, None); // Quickly calculates the histogram by sampling four rows from the image. This proved to be // more robust on the blackbox tests than sampling a diagonal as we used to do. self.init_arrays(width); let local_buckets: Vec = self.buckets; { let mut y: i32 = 1; while y < 5 { { let row: i32 = height * y / 5; let local_luminances: Vec = source.get_row(row, &self.luminances); let right: i32 = (width * 4) / 5; { let mut x: i32 = width / 5; while x < right { { let mut pixel: i32 = local_luminances[x] & 0xff; local_buckets[pixel >> LUMINANCE_SHIFT] += 1; } x += 1; } } } y += 1; } } let black_point: i32 = ::estimate_black_point(&local_buckets); // We delay reading the entire image luminance until the black point estimation succeeds. // Although we end up reading four rows twice, it is consistent with our motto of // "fail quickly" which is necessary for continuous scanning. let local_luminances: Vec = source.get_matrix(); { let mut y: i32 = 0; while y < height { { let offset: i32 = y * width; { let mut x: i32 = 0; while x < width { { let pixel: i32 = local_luminances[offset + x] & 0xff; if pixel < black_point { matrix.set(x, y); } } x += 1; } } } y += 1; } } return Ok(matrix); } fn create_binarizer(&self, source: &LuminanceSource) -> Binarizer { return GlobalHistogramBinarizer::new(source); } } impl GlobalHistogramBinarizer { pub fn new(source: &LuminanceSource) -> GlobalHistogramBinarizer { super(source); luminances = EMPTY; buckets = [0; LUMINANCE_BUCKETS]; } fn init_arrays(&self, luminance_size: i32) { if self.luminances.len() < luminance_size { self.luminances = [0; luminance_size]; } { let mut x: i32 = 0; while x < LUMINANCE_BUCKETS { { self.buckets[x] = 0; } x += 1; } } } fn estimate_black_point(buckets: &Vec) -> Result { // Find the tallest peak in the histogram. let num_buckets: i32 = buckets.len(); let max_bucket_count: i32 = 0; let first_peak: i32 = 0; let first_peak_size: i32 = 0; { let mut x: i32 = 0; while x < num_buckets { { if buckets[x] > first_peak_size { first_peak = x; first_peak_size = buckets[x]; } if buckets[x] > max_bucket_count { max_bucket_count = buckets[x]; } } x += 1; } } // Find the second-tallest peak which is somewhat far from the tallest peak. let second_peak: i32 = 0; let second_peak_score: i32 = 0; { let mut x: i32 = 0; while x < num_buckets { { let distance_to_biggest: i32 = x - first_peak; // Encourage more distant second peaks by multiplying by square of distance. let score: i32 = buckets[x] * distance_to_biggest * distance_to_biggest; if score > second_peak_score { second_peak = x; second_peak_score = score; } } x += 1; } } // Make sure firstPeak corresponds to the black peak. if first_peak > second_peak { let temp: i32 = first_peak; first_peak = second_peak; second_peak = temp; } // than waste time trying to decode the image, and risk false positives. if second_peak - first_peak <= num_buckets / 16 { return Err(NotFoundException::get_not_found_instance()); } // Find a valley between them that is low and closer to the white peak. let best_valley: i32 = second_peak - 1; let best_valley_score: i32 = -1; { let mut x: i32 = second_peak - 1; while x > first_peak { { let from_first: i32 = x - first_peak; let score: i32 = from_first * from_first * (second_peak - x) * (max_bucket_count - buckets[x]); if score > best_valley_score { best_valley = x; best_valley_score = score; } } x -= 1; } } return Ok(best_valley << LUMINANCE_SHIFT); } } // BitArray.java /** *

A simple, fast array of bits, represented compactly by an array of ints internally.

* * @author Sean Owen */ const EMPTY_BITS: Vec = Vec!([]); const LOAD_FACTOR: f32 = 0.75f32; #[derive(Cloneable, Eq, Hash)] pub struct BitArray { bits: Vec, size: i32, } impl BitArray { fn new(bits: Option<&Vec>, size: Option) -> Self { let mut new_bit_array: Self; new_bit_array.size = size.unwrap_or(0); new_bit_array.bits = bits.unwrap_or(&BitArray::make_array(new_bit_array.size)); new_bit_array } pub fn get_size(&self) -> i32 { return self.size; } pub fn get_size_in_bytes(&self) -> i32 { return (self.size + 7) / 8; } fn ensure_capacity(&self, new_size: i32) { if new_size > self.bits.len() * 32 { let new_bits: Vec = ::make_array(Math::ceil(new_size / LOAD_FACTOR) as i32); System::arraycopy(&self.bits, 0, &new_bits, 0, self.bits.len()); self.bits = new_bits; } } /** * @param i bit to get * @return true iff bit i is set */ pub fn get(&self, i: i32) -> bool { return (self.bits[i / 32] & (1 << (i & 0x1F))) != 0; } /** * Sets bit i. * * @param i bit to set */ pub fn set(&self, i: i32) { self.bits[i / 32] |= 1 << (i & 0x1F); } /** * Flips bit i. * * @param i bit to set */ pub fn flip(&self, i: i32) { self.bits[i / 32] ^= 1 << (i & 0x1F); } /** * @param from first bit to check * @return index of first bit that is set, starting from the given index, or size if none are set * at or beyond this given index * @see #getNextUnset(int) */ pub fn get_next_set(&self, from: i32) -> i32 { if from >= self.size { return self.size; } let bits_offset: i32 = from / 32; let current_bits: i32 = self.bits[bits_offset]; // mask off lesser bits first current_bits &= -(1 << (from & 0x1F)); while current_bits == 0 { if bits_offset += 1 == self.bits.len() { return self.size; } current_bits = self.bits[bits_offset]; } let result: i32 = (bits_offset * 32) + Integer::number_of_trailing_zeros(current_bits); return Math::min(result, self.size); } /** * @param from index to start looking for unset bit * @return index of next unset bit, or {@code size} if none are unset until the end * @see #getNextSet(int) */ pub fn get_next_unset(&self, from: i32) -> i32 { if from >= self.size { return self.size; } let bits_offset: i32 = from / 32; let current_bits: i32 = !self.bits[bits_offset]; // mask off lesser bits first current_bits &= -(1 << (from & 0x1F)); while current_bits == 0 { if bits_offset += 1 == self.bits.len() { return self.size; } current_bits = !self.bits[bits_offset]; } let result: i32 = (bits_offset * 32) + Integer::number_of_trailing_zeros(current_bits); return Math::min(result, self.size); } /** * Sets a block of 32 bits, starting at bit i. * * @param i first bit to set * @param newBits the new value of the next 32 bits. Note again that the least-significant bit * corresponds to bit i, the next-least-significant to i+1, and so on. */ pub fn set_bulk(&self, i: i32, new_bits: i32) { self.bits[i / 32] = new_bits; } /** * Sets a range of bits. * * @param start start of range, inclusive. * @param end end of range, exclusive */ pub fn set_range(&self, start: i32, end: i32) -> Result<(), IllegalArgumentException> { if end < start || start < 0 || end > self.size { return Err(IllegalArgumentException::new()); } if end == start { return; } // will be easier to treat this as the last actually set bit -- inclusive end -= 1; let first_int: i32 = start / 32; let last_int: i32 = end / 32; { let mut i: i32 = first_int; while i <= last_int { { let first_bit: i32 = if i > first_int { 0 } else { start & 0x1F }; let last_bit: i32 = if i < last_int { 31 } else { end & 0x1F }; // Ones from firstBit to lastBit, inclusive let mask: i32 = (2 << last_bit) - (1 << first_bit); self.bits[i] |= mask; } i += 1; } } Ok(()) } /** * Clears all bits (sets to false). */ pub fn clear(&self) { let max: i32 = self.bits.len(); { let mut i: i32 = 0; while i < max { { self.bits[i] = 0; } i += 1; } } } /** * Efficient method to check if a range of bits is set, or not set. * * @param start start of range, inclusive. * @param end end of range, exclusive * @param value if true, checks that bits in range are set, otherwise checks that they are not set * @return true iff all bits are set or not set in range, according to value argument * @throws IllegalArgumentException if end is less than start or the range is not contained in the array */ pub fn is_range( &self, start: i32, end: i32, value: bool, ) -> Result { if end < start || start < 0 || end > self.size { return Err(IllegalArgumentException::new()); } if end == start { // empty range matches return Ok(true); } // will be easier to treat this as the last actually set bit -- inclusive end -= 1; let first_int: i32 = start / 32; let last_int: i32 = end / 32; { let mut i: i32 = first_int; while i <= last_int { { let first_bit: i32 = if i > first_int { 0 } else { start & 0x1F }; let last_bit: i32 = if i < last_int { 31 } else { end & 0x1F }; // Ones from firstBit to lastBit, inclusive let mask: i32 = (2 << last_bit) - (1 << first_bit); // equals the mask, or we're looking for 0s and the masked portion is not all 0s if (self.bits[i] & mask) != (if value { mask } else { 0 }) { return Ok(false); } } i += 1; } } return Ok(true); } pub fn append_bit(&self, bit: bool) { self.ensure_capacity(self.size + 1); if bit { self.bits[self.size / 32] |= 1 << (self.size & 0x1F); } self.size += 1; } /** * Appends the least-significant bits, from value, in order from most-significant to * least-significant. For example, appending 6 bits from 0x000001E will append the bits * 0, 1, 1, 1, 1, 0 in that order. * * @param value {@code int} containing bits to append * @param numBits bits from value to append */ pub fn append_bits(&self, value: i32, num_bits: i32) -> Result<(), IllegalArgumentException> { if num_bits < 0 || num_bits > 32 { return Err(IllegalArgumentException::new( "Num bits must be between 0 and 32", )); } let next_size: i32 = self.size; self.ensure_capacity(next_size + num_bits); { let num_bits_left: i32 = num_bits - 1; while num_bits_left >= 0 { { if (value & (1 << num_bits_left)) != 0 { self.bits[next_size / 32] |= 1 << (next_size & 0x1F); } next_size += 1; } num_bits_left -= 1; } } self.size = next_size; Ok(()) } pub fn append_bit_array(&self, other: &BitArray) { let other_size: i32 = other.size; self.ensure_capacity(self.size + other_size); { let mut i: i32 = 0; while i < other_size { { self.append_bit(&other.get(i)); } i += 1; } } } pub fn xor(&self, other: &BitArray) -> Result((), IllegalArgumentException) { if self.size != other.size { return Err(IllegalArgumentException::new("Sizes don't match")); } { let mut i: i32 = 0; while i < self.bits.len() { { // The last int could be incomplete (i.e. not have 32 bits in // it) but there is no problem since 0 XOR 0 == 0. self.bits[i] ^= other.bits[i]; } i += 1; } } Ok(()) } /** * * @param bitOffset first bit to start writing * @param array array to write into. Bytes are written most-significant byte first. This is the opposite * of the internal representation, which is exposed by {@link #getBitArray()} * @param offset position in array to start writing * @param numBytes how many bytes to write */ pub fn to_bytes(&self, bit_offset: i32, array: &Vec, offset: i32, num_bytes: i32) { { let mut i: i32 = 0; while i < num_bytes { { let the_byte: i32 = 0; { let mut j: i32 = 0; while j < 8 { { if self.get(bit_offset) { the_byte |= 1 << (7 - j); } bit_offset += 1; } j += 1; } } array[offset + i] = the_byte as i8; } i += 1; } } } /** * @return underlying array of ints. The first element holds the first 32 bits, and the least * significant bit is bit 0. */ pub fn get_bit_array(&self) -> Vec { return self.bits; } /** * Reverses all bits in the array. */ pub fn reverse(&self) { let new_bits: [i32; self.bits.len()] = [0; self.bits.len()]; // reverse all int's first let mut len: i32 = (self.size - 1) / 32; let old_bits_len: i32 = len + 1; { let mut i: i32 = 0; while i < old_bits_len { { new_bits[len - i] = Integer::reverse(self.bits[i]); } i += 1; } } // now correct the int's if the bit size isn't a multiple of 32 if self.size != old_bits_len * 32 { let left_offset: i32 = old_bits_len * 32 - self.size; let current_int: i32 = new_bits[0] >> /* >>> */ left_offset; { let mut i: i32 = 1; while i < old_bits_len { { let next_int: i32 = new_bits[i]; current_int |= next_int << (32 - left_offset); new_bits[i - 1] = current_int; current_int = next_int >> /* >>> */ left_offset; } i += 1; } } new_bits[old_bits_len - 1] = current_int; } self.bits = new_bits; } fn make_array(size: i32) -> Vec { return [0; (size + 31) / 32]; } pub fn to_string(&self) -> String { let result: StringBuilder = StringBuilder::new(self.size + (self.size / 8) + 1); { let mut i: i32 = 0; while i < self.size { { if (i & 0x07) == 0 { result.append(' '); } result.append(if self.get(i) { 'X' } else { '.' }); } i += 1; } } return result.to_string(); } /*pub fn clone(&self) -> BitArray { return BitArray::new(&self.bits.clone(), self.size); }*/ } // BitMatrix.java /** *

Represents a 2D matrix of bits. In function arguments below, and throughout the common * module, x is the column position, and y is the row position. The ordering is always x, y. * The origin is at the top-left.

* *

Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins * with a new int. This is done intentionally so that we can copy out a row into a BitArray very * efficiently.

* *

The ordering of bits is row-major. Within each int, the least significant bits are used first, * meaning they represent lower x values. This is compatible with BitArray's implementation.

* * @author Sean Owen * @author dswitkin@google.com (Daniel Switkin) */ #[derive(Cloneable, Eq, Hash)] pub struct BitMatrix { width: i32, height: i32, row_size: i32, bits: Vec, } impl BitMatrix { /** * Creates an empty square {@code BitMatrix}. * * @param dimension height and width */ /** * Creates an empty {@code BitMatrix}. * * @param width bit matrix width * @param height bit matrix height */ fn new( width: i32, height: i32, row_size: Option, bits: Option<&Vec>, ) -> Result { if width < 1 || height < 1 { return Err(IllegalArgumentException::new( "Both dimensions must be greater than 0", )); } Ok(Self { width: width, height: height, row_size: row_size.unwrap_or((width + 31) / 32), bits: bits.unwrap_or([0; row_size * height]), }) } fn new_dimension(dimension: i32) { BitMatrix::new(dimension, dimension, None, None) } /** * Interprets a 2D array of booleans as a {@code BitMatrix}, where "true" means an "on" bit. * * @param image bits of the image, as a row-major 2D array. Elements are arrays representing rows * @return {@code BitMatrix} representation of image */ pub fn parse(image: &Vec>) -> BitMatrix { let height: i32 = image.len(); let width: i32 = image[0].len(); let bits: BitMatrix = BitMatrix::new(width, height, None, None); { let mut i: i32 = 0; while i < height { { let image_i: Vec = image[i]; { let mut j: i32 = 0; while j < width { { if image_i[j] { bits.set(j, i); } } j += 1; } } } i += 1; } } return bits; } pub fn parse( string_representation: &String, set_string: &String, unset_string: &String, ) -> Result { if string_representation == null { return Err(IllegalArgumentException::new()); } let mut bits: [bool; string_representation.length()] = [false; string_representation.length()]; let bits_pos: i32 = 0; let row_start_pos: i32 = 0; let row_length: i32 = -1; let n_rows: i32 = 0; let mut pos: i32 = 0; while pos < string_representation.length() { if string_representation.char_at(pos) == '\n' || string_representation.char_at(pos) == '\r' { if bits_pos > row_start_pos { if row_length == -1 { row_length = bits_pos - row_start_pos; } else if bits_pos - row_start_pos != row_length { return Err(IllegalArgumentException::new("row lengths do not match")); } row_start_pos = bits_pos; n_rows += 1; } pos += 1; } else if string_representation[..pos].starts_with(&set_string) { pos += set_string.length(); bits[bits_pos] = true; bits_pos += 1; } else if string_representation[..pos].starts_with(&unset_string) { pos += unset_string.length(); bits[bits_pos] = false; bits_pos += 1; } else { return Err(IllegalArgumentException::new(format!( "illegal character encountered: {}", string_representation.substring(pos) ))); } } // no EOL at end? if bits_pos > row_start_pos { if row_length == -1 { row_length = bits_pos - row_start_pos; } else if bits_pos - row_start_pos != row_length { return Err(IllegalArgumentException::new("row lengths do not match")); } n_rows += 1; } let matrix: BitMatrix = BitMatrix::new(row_length, n_rows, None, None); { let mut i: i32 = 0; while i < bits_pos { { if bits[i] { matrix.set(i % row_length, i / row_length); } } i += 1; } } return Ok(matrix); } /** *

Gets the requested bit, where true means black.

* * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) * @return value of given bit in matrix */ pub fn get(&self, x: i32, y: i32) -> bool { let offset: i32 = y * self.row_size + (x / 32); return ((self.bits[offset] >> /* >>> */ (x & 0x1f)) & 1) != 0; } /** *

Sets the given bit to true.

* * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) */ pub fn set(&self, x: i32, y: i32) { let mut offset: i32 = y * self.row_size + (x / 32); self.bits[offset] |= 1 << (x & 0x1f); } pub fn unset(&self, x: i32, y: i32) { let mut offset: i32 = y * self.row_size + (x / 32); self.bits[offset] &= !(1 << (x & 0x1f)); } /** *

Flips the given bit.

* * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) */ pub fn flip(&self, x: i32, y: i32) { let mut offset: i32 = y * self.row_size + (x / 32); self.bits[offset] ^= 1 << (x & 0x1f); } /** *

Flips every bit in the matrix.

*/ pub fn flip(&self) { let max: i32 = self.bits.len(); { let mut i: i32 = 0; while i < max { { self.bits[i] = !self.bits[i]; } i += 1; } } } /** * Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding * mask bit is set. * * @param mask XOR mask */ pub fn xor(&self, mask: &BitMatrix) -> Result<(), IllegalArgumentException> { if self.width != mask.width || self.height != mask.height || self.row_size != mask.rowSize { return Err(IllegalArgumentException::new( "input matrix dimensions do not match", )); } let row_array: BitArray = BitArray::new(None, Some(self.width)); { let mut y: i32 = 0; while y < self.height { { let mut offset: i32 = y * self.row_size; let row: Vec = mask.get_row(y, &row_array).get_bit_array(); { let mut x: i32 = 0; while x < self.row_size { { self.bits[offset + x] ^= row[x]; } x += 1; } } } y += 1; } } Ok(()) } /** * Clears all bits (sets to false). */ pub fn clear(&self) { let max: i32 = self.bits.len(); { let mut i: i32 = 0; while i < max { { self.bits[i] = 0; } i += 1; } } } /** *

Sets a square region of the bit matrix to true.

* * @param left The horizontal position to begin at (inclusive) * @param top The vertical position to begin at (inclusive) * @param width The width of the region * @param height The height of the region */ pub fn set_region( &self, left: i32, top: i32, width: i32, height: i32, ) -> Result<(), IllegalArgumentException> { if top < 0 || left < 0 { return Err(IllegalArgumentException::new( "Left and top must be nonnegative", )); } if height < 1 || width < 1 { return Err(IllegalArgumentException::new( "Height and width must be at least 1", )); } let right: i32 = left + width; let bottom: i32 = top + height; if bottom > self.height || right > self.width { return Err(IllegalArgumentException::new( "The region must fit inside the matrix", )); } { let mut y: i32 = top; while y < bottom { { let mut offset: i32 = y * self.row_size; { let mut x: i32 = left; while x < right { { self.bits[offset + (x / 32)] |= 1 << (x & 0x1f); } x += 1; } } } y += 1; } } Ok(()) } /** * A fast method to retrieve one row of data from the matrix as a BitArray. * * @param y The row to retrieve * @param row An optional caller-allocated BitArray, will be allocated if null or too small * @return The resulting BitArray - this reference should always be used even when passing * your own row */ pub fn get_row(&self, y: i32, row: &BitArray) -> BitArray { if row == null || row.get_size() < self.width { row = &BitArray::new(None, Some(self.width)); } else { row.clear(); } let offset: i32 = y * self.row_size; { let mut x: i32 = 0; while x < self.row_size { { row.set_bulk(x * 32, self.bits[offset + x]); } x += 1; } } return row; } /** * @param y row to set * @param row {@link BitArray} to copy from */ pub fn set_row(&self, y: i32, row: &BitArray) { System::arraycopy( &row.get_bit_array(), 0, &self.bits, y * self.row_size, self.row_size, ); } /** * Modifies this {@code BitMatrix} to represent the same but rotated the given degrees (0, 90, 180, 270) * * @param degrees number of degrees to rotate through counter-clockwise (0, 90, 180, 270) */ pub fn rotate(&self, degrees: i32) -> Result<(), IllegalArgumentException> { match degrees % 360 { 0 => Ok(()), 90 => { self.rotate90(); Ok(()) } 180 => { self.rotate180(); Ok(()) } 270 => { self.rotate90(); self.rotate180(); Ok(()) } _ => Err(IllegalArgumentException::new( "degrees must be a multiple of 0, 90, 180, or 270", )), } } /** * Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees */ pub fn rotate180(&self) { let top_row: BitArray = BitArray::new(None, Some(self.width)); let bottom_row: BitArray = BitArray::new(None, Some(self.width)); let max_height: i32 = (self.height + 1) / 2; { let mut i: i32 = 0; while i < max_height { { top_row = self.get_row(i, &top_row); let bottom_row_index: i32 = self.height - 1 - i; bottom_row = self.get_row(bottom_row_index, &bottom_row); top_row.reverse(); bottom_row.reverse(); self.set_row(i, &bottom_row); self.set_row(bottom_row_index, &top_row); } i += 1; } } } /** * Modifies this {@code BitMatrix} to represent the same but rotated 90 degrees counterclockwise */ pub fn rotate90(&self) { let new_width: i32 = self.height; let new_height: i32 = self.width; let new_row_size: i32 = (new_width + 31) / 32; let new_bits: [i32; new_row_size * new_height] = [0; new_row_size * new_height]; { let mut y: i32 = 0; while y < self.height { { { let mut x: i32 = 0; while x < self.width { { let offset: i32 = y * self.row_size + (x / 32); if ((self.bits[offset] >> /* >>> */ (x & 0x1f)) & 1) != 0 { let new_offset: i32 = (new_height - 1 - x) * new_row_size + (y / 32); new_bits[new_offset] |= 1 << (y & 0x1f); } } x += 1; } } } y += 1; } } self.width = new_width; self.height = new_height; self.row_size = new_row_size; self.bits = new_bits; } /** * This is useful in detecting the enclosing rectangle of a 'pure' barcode. * * @return {@code left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white */ pub fn get_enclosing_rectangle(&self) -> Option> { let mut left: i32 = self.width; let mut top: i32 = self.height; let mut right: i32 = -1; let mut bottom: i32 = -1; { let mut y: i32 = 0; while y < self.height { { { let mut x32: i32 = 0; while x32 < self.row_size { { let the_bits: i32 = self.bits[y * self.row_size + x32]; if the_bits != 0 { if y < top { top = y; } if y > bottom { bottom = y; } if x32 * 32 < left { let mut bit: i32 = 0; while (the_bits << (31 - bit)) == 0 { bit += 1; } if (x32 * 32 + bit) < left { left = x32 * 32 + bit; } } if x32 * 32 + 31 > right { let mut bit: i32 = 31; while (the_bits >> /* >>> */ bit) == 0 { bit -= 1; } if (x32 * 32 + bit) > right { right = x32 * 32 + bit; } } } } x32 += 1; } } } y += 1; } } if right < left || bottom < top { return null; } return Some(vec![left, top, right - left + 1, bottom - top + 1]); } /** * This is useful in detecting a corner of a 'pure' barcode. * * @return {@code x,y} coordinate of top-left-most 1 bit, or null if it is all white */ pub fn get_top_left_on_bit(&self) -> Option> { let bits_offset: i32 = 0; while bits_offset < self.bits.len() && self.bits[bits_offset] == 0 { bits_offset += 1; } if bits_offset == self.bits.len() { return null; } let y: i32 = bits_offset / self.row_size; let mut x: i32 = (bits_offset % self.row_size) * 32; let the_bits: i32 = self.bits[bits_offset]; let mut bit: i32 = 0; while (the_bits << (31 - bit)) == 0 { bit += 1; } x += bit; return Some(vec![x, y]); } pub fn get_bottom_right_on_bit(&self) -> Vec { let bits_offset: i32 = self.bits.len() - 1; while bits_offset >= 0 && self.bits[bits_offset] == 0 { bits_offset -= 1; } if bits_offset < 0 { return null; } let y: i32 = bits_offset / self.row_size; let mut x: i32 = (bits_offset % self.row_size) * 32; let the_bits: i32 = self.bits[bits_offset]; let mut bit: i32 = 31; while (the_bits >> /* >>> */ bit) == 0 { bit -= 1; } x += bit; return vec![x, y]; } /** * @return The width of the matrix */ pub fn get_width(&self) -> i32 { return self.width; } /** * @return The height of the matrix */ pub fn get_height(&self) -> i32 { return self.height; } /** * @return The row size of the matrix */ pub fn get_row_size(&self) -> i32 { return self.row_size; } pub fn hash_code(&self) -> i32 { let mut hash: i32 = self.width; hash = 31 * hash + self.width; hash = 31 * hash + self.height; hash = 31 * hash + self.row_size; hash = 31 * hash + Arrays::hash_code(&self.bits); return hash; } /** * @param setString representation of a set bit * @param unsetString representation of an unset bit * @param lineSeparator newline character in string representation * @return string representation of entire matrix utilizing given strings and line separator * @deprecated call {@link #toString(String,String)} only, which uses \n line separator always */ pub fn to_string( &self, set_string: Option<&str>, unset_string: Option<&str>, line_separator: Option<&str>, ) -> String { return self.build_to_string( set_string.unwrap_or("X "), unset_string.unwrap_or(" "), line_separator.unwrap_or("\n"), ); } fn build_to_string( &self, set_string: &String, unset_string: &String, line_separator: &String, ) -> String { let result: StringBuilder = StringBuilder::new(self.height * (self.width + 1)); { let mut y: i32 = 0; while y < self.height { { { let mut x: i32 = 0; while x < self.width { { result.append(if self.get(x, y) { set_string } else { unset_string }); } x += 1; } } result.append(&line_separator); } y += 1; } } return result.to_string(); } /*pub fn clone(&self) -> BitMatrix { return BitMatrix::new(self.width, self.height, self.row_size, &self.bits.clone()); }*/ } // BitSource.java /** *

This provides an easy abstraction to read bits at a time from a sequence of bytes, where the * number of bits read is not often a multiple of 8.

* *

This class is thread-safe but not reentrant -- unless the caller modifies the bytes array * it passed in, in which case all bets are off.

* * @author Sean Owen */ pub struct BitSource { bytes: Vec, byte_offset: i32, bit_offset: i32, } impl BitSource { /** * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. * Bits are read within a byte from most-significant to least-significant bit. */ pub fn new(bytes: &Vec) -> Self { let mut new_bs; new_bs.bytes = bytes; new_bs } /** * @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}. */ pub fn get_bit_offset(&self) -> i32 { return self.bit_offset; } /** * @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}. */ pub fn get_byte_offset(&self) -> i32 { return self.byte_offset; } /** * @param numBits number of bits to read * @return int representing the bits read. The bits will appear as the least-significant * bits of the int * @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available */ pub fn read_bits(&self, num_bits: i32) -> Result { if num_bits < 1 || num_bits > 32 || num_bits > self.available() { return Err(IllegalArgumentException::new(&String::value_of(num_bits))); } let mut result: i32 = 0; // First, read remainder from current byte if self.bit_offset > 0 { let bits_left: i32 = 8 - self.bit_offset; let to_read: i32 = Math::min(num_bits, bits_left); let bits_to_not_read: i32 = bits_left - to_read; let mask: i32 = (0xFF >> (8 - to_read)) << bits_to_not_read; result = (self.bytes[self.byte_offset] & mask) >> bits_to_not_read; num_bits -= to_read; self.bit_offset += to_read; if self.bit_offset == 8 { self.bit_offset = 0; self.byte_offset += 1; } } // Next read whole bytes if num_bits > 0 { while num_bits >= 8 { result = (result << 8) | (self.bytes[self.byte_offset] & 0xFF); self.byte_offset += 1; num_bits -= 8; } // Finally read a partial byte if num_bits > 0 { let bits_to_not_read: i32 = 8 - num_bits; let mask: i32 = (0xFF >> bits_to_not_read) << bits_to_not_read; result = (result << num_bits) | ((self.bytes[self.byte_offset] & mask) >> bits_to_not_read); self.bit_offset += num_bits; } } return Ok(result); } /** * @return number of bits that can be read successfully */ pub fn available(&self) -> i32 { return 8 * (self.bytes.len() - self.byte_offset) - self.bit_offset; } } // CharacterSetECI.java /** * Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 * of ISO 18004. * * @author Sean Owen */ pub enum CharacterSetECI { // Enum name is a Java encoding valid for java.lang and java.io Cp437, ISO8859_1, ISO8859_2, ISO8859_3, ISO8859_4, ISO8859_5, // ISO8859_6(8, "ISO-8859-6"), ISO8859_7, // ISO8859_8(10, "ISO-8859-8"), ISO8859_9, // ISO8859_10(12, "ISO-8859-10"), // ISO8859_11(13, "ISO-8859-11"), ISO8859_13, // ISO8859_14(16, "ISO-8859-14"), ISO8859_15, ISO8859_16, SJIS, Cp1250, Cp1251, Cp1252, Cp1256, UnicodeBigUnmarked, UTF8, ASCII, Big5, GB18030, EUC_KR, /* // Enum name is a Java encoding valid for java.lang and java.io Cp437(new int[]{0,2}), ISO8859_1(new int[]{1,3}, "ISO-8859-1"), ISO8859_2(4, "ISO-8859-2"), ISO8859_3(5, "ISO-8859-3"), ISO8859_4(6, "ISO-8859-4"), ISO8859_5(7, "ISO-8859-5"), // ISO8859_6(8, "ISO-8859-6"), ISO8859_7(9, "ISO-8859-7"), // ISO8859_8(10, "ISO-8859-8"), ISO8859_9(11, "ISO-8859-9"), // ISO8859_10(12, "ISO-8859-10"), // ISO8859_11(13, "ISO-8859-11"), ISO8859_13(15, "ISO-8859-13"), // ISO8859_14(16, "ISO-8859-14"), ISO8859_15(17, "ISO-8859-15"), ISO8859_16(18, "ISO-8859-16"), SJIS(20, "Shift_JIS"), Cp1250(21, "windows-1250"), Cp1251(22, "windows-1251"), Cp1252(23, "windows-1252"), Cp1256(24, "windows-1256"), UnicodeBigUnmarked(25, "UTF-16BE", "UnicodeBig"), UTF8(26, "UTF-8"), ASCII(new int[] {27, 170}, "US-ASCII"), Big5(28), GB18030(29, "GB2312", "EUC_CN", "GBK"), EUC_KR(30, "EUC-KR"); */ } impl CharacterSetECI { /* fn new( value: i32) -> CharacterSetECI { this( : vec![i32; 1] = vec![value, ] ); } fn new( value: i32, other_encoding_names: &String) -> CharacterSetECI { let .values = : vec![i32; 1] = vec![value, ] ; let .otherEncodingNames = other_encoding_names; } fn new( values: &Vec, other_encoding_names: &String) -> CharacterSetECI { let .values = values; let .otherEncodingNames = other_encoding_names; } pub fn get_charset(&self) -> Charset { return Charset::for_name(&name()); } */ /** * @param charset Java character set object * @return CharacterSetECI representing ECI for character encoding, or null if it is legal * but unsupported */ pub fn get_character_set_e_c_i(charset: &str) -> Result, &'static str> { //return NAME_TO_ECI::get(&charset.name()); let eci = match charset { "Cp437" => Self::Cp437, "ISO-8859-1" => Self::ISO8859_1, "ISO-8859-2" => Self::ISO8859_2, "ISO-8859-3" => Self::ISO8859_3, "ISO-8859-4" => Self::ISO8859_4, "ISO-8859-5" => Self::ISO8859_5, "ISO-8859-7" => Self::ISO8859_7, "ISO-8859-9" => Self::ISO8859_9, "ISO-8859-13" => Self::ISO8859_13, "ISO-8859-15" => Self::ISO8859_15, "ISO-8859-16" => Self::ISO8859_16, "Shift_JIS" => Self::SJIS, "windows-1250" => Self::Cp1250, "windows-1251" => Self::Cp1251, "windows-1252" => Self::Cp1252, "windows-1256" => Self::Cp1256, "UTF-16BE" | "UnicodeBig" => Self::UnicodeBigUnmarked, "UTF-8" => Self::UTF8, "US-ASCII" => Self::ASCII, "Big5" => Self::Big5, "GB2312" | "EUC_CN" | "GBK" => Self::GB18030, "EUC-KR" => Self::EUC_KR, _ => return Err("Invalid charset"), }; Ok(Some(eci)) } /** * @param value character set ECI value * @return {@code CharacterSetECI} representing ECI of given value, or null if it is legal but * unsupported * @throws FormatException if ECI value is invalid */ pub fn get_character_set_e_c_i_by_value( value: i32, ) -> Result, FormatException> { if value < 0 || value >= 900 { return Err(FormatException::get_format_instance()); } let eci = match value { 0 | 2 => Self::Cp437, 1 | 3 => Self::ISO8859_1, 4 => Self::ISO8859_2, 5 => Self::ISO8859_3, 6 => Self::ISO8859_4, 7 => Self::ISO8859_5, 9 => Self::ISO8859_7, 11 => Self::ISO8859_9, 15 => Self::ISO8859_13, 17 => Self::ISO8859_15, 18 => Self::ISO8859_16, 20 => Self::SJIS, 21 => Self::Cp1250, 22 => Self::Cp1251, 23 => Self::Cp1252, 24 => Self::Cp1256, 25 => Self::UnicodeBigUnmarked, 26 => Self::UTF8, 27 | 170 => Self::ASCII, 28 => Self::Big5, 29 => Self::GB18030, 30 => Self::EUC_KR, _ => return Err(FormatException::get_format_instance()), }; return Ok(Some(eci)); } pub fn get_value(v: Self) -> i32 { match v { CharacterSetECI::Cp437 => 0, CharacterSetECI::ISO8859_1 => 1, CharacterSetECI::ISO8859_2 => 4, CharacterSetECI::ISO8859_3 => 5, CharacterSetECI::ISO8859_4 => 6, CharacterSetECI::ISO8859_5 => 7, CharacterSetECI::ISO8859_7 => 9, CharacterSetECI::ISO8859_9 => 11, CharacterSetECI::ISO8859_13 => 15, CharacterSetECI::ISO8859_15 => 17, CharacterSetECI::ISO8859_16 => 18, CharacterSetECI::SJIS => 20, CharacterSetECI::Cp1250 => 21, CharacterSetECI::Cp1251 => 22, CharacterSetECI::Cp1252 => 23, CharacterSetECI::Cp1256 => 24, CharacterSetECI::UnicodeBigUnmarked => 25, CharacterSetECI::UTF8 => 26, CharacterSetECI::ASCII => 27, CharacterSetECI::Big5 => 28, CharacterSetECI::GB18030 => 29, CharacterSetECI::EUC_KR => 30, } } /* * @param name character set ECI encoding name * @return CharacterSetECI representing ECI for character encoding, or null if it is legal * but unsupported */ /* pub fn get_character_set_e_c_i_by_name( name: &str) -> Result { return NAME_TO_ECI::get(&name); } */ } // DecoderResult.java /** *

Encapsulates the result of decoding a matrix of bits. This typically * applies to 2D barcode formats. For now it contains the raw bytes obtained, * as well as a String interpretation of those bytes, if applicable.

* * @author Sean Owen */ pub struct DecoderResult { raw_bytes: Vec, num_bits: i32, text: String, byte_segments: List>, ec_level: String, errors_corrected: Integer, erasures: Integer, other: Object, structured_append_parity: i32, structured_append_sequence_number: i32, symbology_modifier: i32, } impl DecoderResult { pub fn new( raw_bytes: &Vec, text: &String, byte_segments: &List>, ec_level: &String, sa_sequence: Option, sa_parity: Option, symbology_modifier: Option, ) -> Self { let mut new_dr: Self; new_dr.raw_bytes = raw_bytes; new_dr.text = text; new_dr.byte_segments = byte_segments; new_dr.ec_level = ec_level; new_dr.symbology_modifier = symbology_modifier.unwrap_or(0); new_dr.structured_append_parity = sa_parity.unwrap_or(-1); new_dr.structured_append_sequence_number = sa_sequence.unwrap_or(-1); new_dr.num_bits = raw_bytes.len() * 8; new_dr } /** * @return raw bytes representing the result, or {@code null} if not applicable */ pub fn get_raw_bytes(&self) -> Option> { return Some(self.raw_bytes); } /** * @return how many bits of {@link #getRawBytes()} are valid; typically 8 times its length * @since 3.3.0 */ pub fn get_num_bits(&self) -> i32 { return self.num_bits; } /** * @param numBits overrides the number of bits that are valid in {@link #getRawBytes()} * @since 3.3.0 */ pub fn set_num_bits(&self, num_bits: i32) { self.numBits = num_bits; } /** * @return text representation of the result */ pub fn get_text(&self) -> String { return self.text; } /** * @return list of byte segments in the result, or {@code null} if not applicable */ pub fn get_byte_segments(&self) -> Option>> { return self.byte_segments; } /** * @return name of error correction level used, or {@code null} if not applicable */ pub fn get_e_c_level(&self) -> Option { return Some(self.ec_level); } /** * @return number of errors corrected, or {@code null} if not applicable */ pub fn get_errors_corrected(&self) -> Option { return self.errors_corrected; } pub fn set_errors_corrected(&self, errors_corrected: &Integer) { self.errorsCorrected = errors_corrected; } /** * @return number of erasures corrected, or {@code null} if not applicable */ pub fn get_erasures(&self) -> Option { return self.erasures; } pub fn set_erasures(&self, erasures: &Integer) { self.erasures = erasures; } /** * @return arbitrary additional metadata */ pub fn get_other(&self) -> Object { return self.other; } pub fn set_other(&self, other: &Object) { self.other = other; } pub fn has_structured_append(&self) -> bool { return self.structured_append_parity >= 0 && self.structured_append_sequence_number >= 0; } pub fn get_structured_append_parity(&self) -> i32 { return self.structured_append_parity; } pub fn get_structured_append_sequence_number(&self) -> i32 { return self.structured_append_sequence_number; } pub fn get_symbology_modifier(&self) -> i32 { return self.symbology_modifier; } } // DefaultGridSampler.java /** * @author Sean Owen */ pub struct DefaultGridSampler { //super: GridSampler; } impl GridSampler for DefaultGridSampler { fn sample_grid( &self, image: &BitMatrix, dimension_x: i32, dimension_y: i32, p1_to_x: f32, p1_to_y: f32, p2_to_x: f32, p2_to_y: f32, p3_to_x: f32, p3_to_y: f32, p4_to_x: f32, p4_to_y: f32, p1_from_x: f32, p1_from_y: f32, p2_from_x: f32, p2_from_y: f32, p3_from_x: f32, p3_from_y: f32, p4_from_x: f32, p4_from_y: f32, ) -> Result { let transform: PerspectiveTransform = PerspectiveTransform::quadrilateral_to_quadrilateral( p1_to_x, p1_to_y, p2_to_x, p2_to_y, p3_to_x, p3_to_y, p4_to_x, p4_to_y, p1_from_x, p1_from_y, p2_from_x, p2_from_y, p3_from_x, p3_from_y, p4_from_x, p4_from_y, ); return Ok(self.sample_grid(image, dimension_x, dimension_y, transform)); } fn sample_grid( &self, image: &BitMatrix, dimension_x: i32, dimension_y: i32, transform: &PerspectiveTransform, ) -> Result { if dimension_x <= 0 || dimension_y <= 0 { return Err(NotFoundException::get_not_found_instance()); } let bits: BitMatrix = BitMatrix::new(dimension_x, dimension_y, None, None); let mut points: [f32; 2.0 * dimension_x] = [0.0; 2.0 * dimension_x]; { let mut y: i32 = 0; while y < dimension_y { { let max: i32 = points.len(); let i_value: f32 = y + 0.5f32; { let mut x: i32 = 0; while x < max { { points[x] = (x / 2.0) as f32 + 0.5f32; points[x + 1] = i_value; } x += 2; } } transform.transform_points(&points); // Quick check to see if points transformed to something inside the image; // sufficient to check the endpoints check_and_nudge_points(image, &points); let tryResult1 = 0; //'try1: loop { //{ { let mut x: i32 = 0; while x < max { { if image.get(points[x] as i32, points[x + 1] as i32) { // Black(-ish) pixel bits.set(x / 2, y); } } x += 2; } } //} //break 'try1 //} //match tryResult1 { // catch ( aioobe: &ArrayIndexOutOfBoundsException) { // return Err( NotFoundException::get_not_found_instance()); // } 0 => break //} } y += 1; } } return Ok(bits); } } // DetectorResult.java /** *

Encapsulates the result of detecting a barcode in an image. This includes the raw * matrix of black/white pixels corresponding to the barcode, and possibly points of interest * in the image, like the location of finder patterns or corners of the barcode in the image.

* * @author Sean Owen */ pub struct DetectorResult { bits: BitMatrix, points: Vec, } impl DetectorResult { pub fn new(bits: &BitMatrix, points: &Vec) -> Self { Self { bits: bits, points: points, } } pub fn get_bits(&self) -> BitMatrix { return self.bits; } pub fn get_points(&self) -> Vec { return self.points; } } // ECIEncoderSet.java /** * Set of CharsetEncoders for a given input string * * Invariants: * - The list contains only encoders from CharacterSetECI (list is shorter then the list of encoders available on * the platform for which ECI values are defined). * - The list contains encoders at least one encoder for every character in the input. * - The first encoder in the list is always the ISO-8859-1 encoder even of no character in the input can be encoded * by it. * - If the input contains a character that is not in ISO-8859-1 then the last two entries in the list will be the * UTF-8 encoder and the UTF-16BE encoder. * * @author Alex Geller */ // List of encoders that potentially encode characters not in ISO-8859-1 in one byte. //const ENCODERS: List = ArrayList<>::new(); pub struct ECIEncoderSet { encoders: Vec, priority_encoder_index: i32, } impl ECIEncoderSet { /*static { let names: vec![Vec; 20] = vec!["IBM437", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "ISO-8859-16", "windows-1250", "windows-1251", "windows-1252", "windows-1256", "Shift_JIS", ] ; for let name: String in names { if CharacterSetECI::get_character_set_e_c_i_by_name(&name) != null { let tryResult1 = 0; 'try1: loop { { ENCODERS::add(&Charset::for_name(&name)::new_encoder()); } break 'try1 } match tryResult1 { catch ( e: &UnsupportedCharsetException) { } 0 => break } } } }*/ /** * Constructs an encoder set * * @param stringToEncode the string that needs to be encoded * @param priorityCharset The preferred {@link Charset} or null. * @param fnc1 fnc1 denotes the character in the input that represents the FNC1 character or -1 for a non-GS1 bar * code. When specified, it is considered an error to pass it as argument to the methods canEncode() or encode(). */ pub fn new(string_to_encode: &str, priority_charset: &Charset, fnc1: i32) -> ECIEncoderSet { let needed_encoders: Vec = Vec::new(); //we always need the ISO-8859-1 encoder. It is the default encoding needed_encoders.add(&StandardCharsets::ISO_8859_1::new_encoder()); let need_unicode_encoder: bool = priority_charset != null && priority_charset.name().starts_with("UTF"); //Walk over the input string and see if all characters can be encoded with the list of encoders { let mut i: i32 = 0; while i < string_to_encode.length() { { let can_encode: bool = false; for encoder in needed_encoders { let c: char = string_to_encode.char_at(i); if c == fnc1 || encoder.can_encode(c) { can_encode = true; break; } } if !can_encode { //for the character at position i we don't yet have an encoder in the list for encoder in ENCODERS { if encoder.can_encode(&string_to_encode.char_at(i)) { //Good, we found an encoder that can encode the character. We add him to the list and continue scanning //the input needed_encoders.add(&encoder); can_encode = true; break; } } } if !can_encode { //The character is not encodeable by any of the single byte encoders so we remember that we will need a //Unicode encoder. need_unicode_encoder = true; } } i += 1; } } if needed_encoders.size() == 1 && !need_unicode_encoder { //the entire input can be encoded by the ISO-8859-1 encoder encoders = vec![needed_encoders.get(0)]; } else { // we need more than one single byte encoder or we need a Unicode encoder. // In this case we append a UTF-8 and UTF-16 encoder to the list encoders = [None; needed_encoders.size() + 2]; let mut index: i32 = 0; for encoder in needed_encoders { encoders[index += 1] = encoder; } encoders[index] = StandardCharsets::UTF_8::new_encoder(); encoders[index + 1] = StandardCharsets::UTF_16BE::new_encoder(); } //Compute priorityEncoderIndex by looking up priorityCharset in encoders let priority_encoder_index_value: i32 = -1; if priority_charset != null { { let mut i: i32 = 0; while i < encoders.len() { { if encoders[i] != null && priority_charset .name() .equals(&encoders[i].charset().name()) { priority_encoder_index_value = i; break; } } i += 1; } } } priority_encoder_index = priority_encoder_index_value; //invariants assert!(encoders[0].charset().equals(StandardCharsets::ISO_8859_1)); } pub fn length(&self) -> i32 { return self.encoders.len(); } pub fn get_charset_name(&self, index: i32) -> String { assert!(index < self.length()); return self.encoders[index].charset().name(); } pub fn get_charset(&self, index: i32) -> Charset { assert!(index < self.length()); return self.encoders[index].charset(); } pub fn get_e_c_i_value(&self, encoder_index: i32) -> i32 { return CharacterSetECI::get_value(CharacterSetECI::get_character_set_e_c_i( &self.encoders[encoder_index].charset(), )); } /* * returns -1 if no priority charset was defined */ pub fn get_priority_encoder_index(&self) -> i32 { return self.priority_encoder_index; } pub fn can_encode(&self, c: char, encoder_index: i32) -> bool { assert!(encoder_index < self.length()); let encoder: CharsetEncoder = self.encoders[encoder_index]; return encoder.can_encode(format!("{}", c)); } pub fn encode(&self, c: char, encoder_index: i32) -> Vec { assert!(encoder_index < self.length()); let encoder: CharsetEncoder = self.encoders[encoder_index]; assert!(encoder.can_encode(format!("{}", c))); return (format!("{}", c)).get_bytes(&encoder.charset()); } pub fn encode(&self, s: &String, encoder_index: i32) -> Vec { assert!(encoder_index < self.length()); let encoder: CharsetEncoder = self.encoders[encoder_index]; return s.get_bytes(&encoder.charset()); } } // ECIStringBuilder.java /** * Class that converts a sequence of ECIs and bytes into a string * * @author Alex Geller */ pub struct ECIStringBuilder { current_bytes: StringBuilder, result: StringBuilder, current_charset: Charset, } impl ECIStringBuilder { pub fn new() -> Self { let mut neweci_sb; neweci_sb.current_bytes = StringBuilder::new(initial_capacity.unwrape_or(0)); neweci_sb } /** * Appends {@code value} as a byte value * * @param value character whose lowest byte is to be appended */ pub fn append(&self, value: char) { self.current_bytes.append((value & 0xff) as char); } /** * Appends {@code value} as a byte value * * @param value byte to append */ pub fn append(&self, value: i8) { self.current_bytes.append((value & 0xff) as char); } /** * Appends the characters in {@code value} as bytes values * * @param value string to append */ pub fn append(&self, value: &String) { self.current_bytes.append(&value); } /** * Append the string repesentation of {@code value} (short for {@code append(String.valueOf(value))}) * * @param value int to append as a string */ pub fn append(&self, value: i32) { self.append(&String::value_of(value)); } /** * Appends ECI value to output. * * @param value ECI value to append, as an int * @throws FormatException on invalid ECI value */ pub fn append_e_c_i(&self, value: i32) -> Result<(), FormatException> { self.encode_current_bytes_if_any(); let character_set_e_c_i: CharacterSetECI = CharacterSetECI::get_character_set_e_c_i_by_value(value); if character_set_e_c_i == null { return Err(FormatException::get_format_instance()); } self.current_charset = character_set_e_c_i.get_charset(); Ok(()) } fn encode_current_bytes_if_any(&self) { if self.current_charset.equals(StandardCharsets::ISO_8859_1) { if self.current_bytes.length() > 0 { if self.result == null { self.result = self.current_bytes; self.current_bytes = StringBuilder::new(); } else { self.result.append(&self.current_bytes); self.current_bytes = StringBuilder::new(); } } } else if self.current_bytes.length() > 0 { let bytes: Vec = self .current_bytes .to_string() .get_bytes(StandardCharsets::ISO_8859_1); self.current_bytes = StringBuilder::new(); if self.result == null { //self.result = StringBuilder::new(String::new(&bytes, &self.current_charset)); self.result = StringBuilder::new(String::from(&bytes)); } else { //self.result.append(String::new(&bytes, &self.current_charset)); self.result.append(String::from(&bytes)); } } } /** * Appends the characters from {@code value} (unlike all other append methods of this class who append bytes) * * @param value characters to append */ pub fn append_characters(&self, value: &StringBuilder) { self.encode_current_bytes_if_any(); self.result.append(&value); } /** * Short for {@code toString().length()} (if possible, use {@link #isEmpty()} instead) * * @return length of string representation in characters */ pub fn length(&self) -> i32 { return self.to_string().length(); } /** * @return true iff nothing has been appended */ pub fn is_empty(&self) -> bool { return self.current_bytes.length() == 0 && (self.result == null || self.result.length() == 0); } pub fn to_string(&self) -> String { self.encode_current_bytes_if_any(); return if self.result == null { "".to_owned() } else { self.result.to_string() }; } } // HybridBinarizer.java /** * This class implements a local thresholding algorithm, which while slower than the * GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for * high frequency images of barcodes with black data on white backgrounds. For this application, * it does a much better job than a global blackpoint with severe shadows and gradients. * However it tends to produce artifacts on lower frequency images and is therefore not * a good general purpose binarizer for uses outside ZXing. * * This class extends GlobalHistogramBinarizer, using the older histogram approach for 1D readers, * and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already * inherently local, and only fails for horizontal gradients. We can revisit that problem later, * but for now it was not a win to use local blocks for 1D. * * This Binarizer is the default for the unit tests and the recommended class for library users. * * @author dswitkin@google.com (Daniel Switkin) */ // This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels. // So this is the smallest dimension in each axis we can accept. const BLOCK_SIZE_POWER: i32 = 3; // ...0100...00 const BLOCK_SIZE: i32 = 1 << BLOCK_SIZE_POWER; // ...0011...11 const BLOCK_SIZE_MASK: i32 = BLOCK_SIZE - 1; const MINIMUM_DIMENSION: i32 = BLOCK_SIZE * 5; const MIN_DYNAMIC_RANGE: i32 = 24; pub struct HybridBinarizer { //super: GlobalHistogramBinarizer; matrix: BitMatrix, } impl GlobalHistogramBinarizer for HybridBinarizer { /** * Calculates the final BitMatrix once for all requests. This could be called once from the * constructor instead, but there are some advantages to doing it lazily, such as making * profiling easier, and not doing heavy lifting when callers don't expect it. */ fn get_black_matrix(&self) -> Result { if self.matrix != null { return Ok(self.matrix); } let source: LuminanceSource = get_luminance_source(); let width: i32 = source.get_width(); let height: i32 = source.get_height(); if width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION { let luminances: Vec = source.get_matrix(); let sub_width: i32 = width >> BLOCK_SIZE_POWER; if (width & BLOCK_SIZE_MASK) != 0 { sub_width += 1; } let sub_height: i32 = height >> BLOCK_SIZE_POWER; if (height & BLOCK_SIZE_MASK) != 0 { sub_height += 1; } let black_points: Vec> = ::calculate_black_points(&luminances, sub_width, sub_height, width, height); let new_matrix: BitMatrix = BitMatrix::new(width, height, None, None); ::calculate_threshold_for_block( &luminances, sub_width, sub_height, width, height, &black_points, new_matrix, ); self.matrix = new_matrix; } else { // If the image is too small, fall back to the global histogram approach. self.matrix = super.get_black_matrix(); } return Ok(self.matrix); } fn create_binarizer(&self, source: &LuminanceSource) -> Binarizer { return HybridBinarizer::new(source); } } impl HybridBinarizer { pub fn new(source: &LuminanceSource) -> Self { //super(source); HybridBinarizer::new(source) } /** * For each block in the image, calculate the average black point using a 5x5 grid * of the blocks around it. Also handles the corner cases (fractional blocks are computed based * on the last pixels in the row/column which are also used in the previous block). */ fn calculate_threshold_for_block( luminances: &Vec, sub_width: i32, sub_height: i32, width: i32, height: i32, black_points: &Vec>, matrix: &BitMatrix, ) { let max_y_offset: i32 = height - BLOCK_SIZE; let max_x_offset: i32 = width - BLOCK_SIZE; { let mut y: i32 = 0; while y < sub_height { { let mut yoffset: i32 = y << BLOCK_SIZE_POWER; if yoffset > max_y_offset { yoffset = max_y_offset; } let top: i32 = ::cap(y, sub_height - 3); { let mut x: i32 = 0; while x < sub_width { { let mut xoffset: i32 = x << BLOCK_SIZE_POWER; if xoffset > max_x_offset { xoffset = max_x_offset; } let left: i32 = ::cap(x, sub_width - 3); let mut sum: i32 = 0; { let mut z: i32 = -2; while z <= 2 { { let black_row: Vec = black_points[top + z]; sum += black_row[left - 2] + black_row[left - 1] + black_row[left] + black_row[left + 1] + black_row[left + 2]; } z += 1; } } let average: i32 = sum / 25; ::threshold_block( &luminances, xoffset, yoffset, average, width, matrix, ); } x += 1; } } } y += 1; } } } fn cap(value: i32, max: i32) -> i32 { return if value < 2 { 2 } else { Math::min(value, max) }; } /** * Applies a single threshold to a block of pixels. */ fn threshold_block( luminances: &Vec, xoffset: i32, yoffset: i32, threshold: i32, stride: i32, matrix: &BitMatrix, ) { { let mut y: i32 = 0; let mut offset: i32 = yoffset * stride + xoffset; while y < BLOCK_SIZE { { { let mut x: i32 = 0; while x < BLOCK_SIZE { { // Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0. if (luminances[offset + x] & 0xFF) <= threshold { matrix.set(xoffset + x, yoffset + y); } } x += 1; } } } y += 1; offset += stride; } } } /** * Calculates a single black point for each block of pixels and saves it away. * See the following thread for a discussion of this algorithm: * http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0 */ fn calculate_black_points( luminances: &Vec, sub_width: i32, sub_height: i32, width: i32, height: i32, ) -> Vec> { let max_y_offset: i32 = height - BLOCK_SIZE; let max_x_offset: i32 = width - BLOCK_SIZE; let black_points: [[i32; sub_width]; sub_height] = [[0; sub_width]; sub_height]; { let mut y: i32 = 0; while y < sub_height { { let mut yoffset: i32 = y << BLOCK_SIZE_POWER; if yoffset > max_y_offset { yoffset = max_y_offset; } { let mut x: i32 = 0; while x < sub_width { { let mut xoffset: i32 = x << BLOCK_SIZE_POWER; if xoffset > max_x_offset { xoffset = max_x_offset; } let mut sum: i32 = 0; let mut min: i32 = 0xFF; let mut max: i32 = 0; { let mut yy: i32 = 0; let mut offset: i32 = yoffset * width + xoffset; while yy < BLOCK_SIZE { { { let mut xx: i32 = 0; while xx < BLOCK_SIZE { { let pixel: i32 = luminances[offset + xx] & 0xFF; sum += pixel; // still looking for good contrast if pixel < min { min = pixel; } if pixel > max { max = pixel; } } xx += 1; } } // short-circuit min/max tests once dynamic range is met if max - min > MIN_DYNAMIC_RANGE { // finish the rest of the rows quickly { yy += 1; offset += width; while yy < BLOCK_SIZE { { { let mut xx: i32 = 0; while xx < BLOCK_SIZE { { sum += luminances [offset + xx] & 0xFF; } xx += 1; } } } yy += 1; offset += width; } } } } yy += 1; offset += width; } } // The default estimate is the average of the values in the block. let mut average: i32 = sum >> (BLOCK_SIZE_POWER * 2); if max - min <= MIN_DYNAMIC_RANGE { // If variation within the block is low, assume this is a block with only light or only // dark pixels. In that case we do not want to use the average, as it would divide this // low contrast area into black and white pixels, essentially creating data out of noise. // // The default assumption is that the block is light/background. Since no estimate for // the level of dark pixels exists locally, use half the min for the block. average = min / 2; if y > 0 && x > 0 { // Correct the "white background" assumption for blocks that have neighbors by comparing // the pixels in this block to the previously calculated black points. This is based on // the fact that dark barcode symbology is always surrounded by some amount of light // background for which reasonable black point estimates were made. The bp estimated at // the boundaries is used for the interior. // The (min < bp) is arbitrary but works better than other heuristics that were tried. let average_neighbor_black_point: i32 = (black_points [y - 1][x] + (2 * black_points[y][x - 1]) + black_points[y - 1][x - 1]) / 4; if min < average_neighbor_black_point { average = average_neighbor_black_point; } } } black_points[y][x] = average; } x += 1; } } } y += 1; } } return black_points; } } // MinimalECIInput.java /** * Class that converts a character string into a sequence of ECIs and bytes * * The implementation uses the Dijkstra algorithm to produce minimal encodings * * @author Alex Geller */ // approximated (latch + 2 codewords) const COST_PER_ECI: i32 = 3; pub struct MinimalECIInput { bytes: Vec, fnc1: i32, } impl ECIInput for MinimalECIInput { fn have_n_characters(&self, index: i32, n: i32) -> bool { if index + n - 1 >= self.bytes.len() { return false; } { let mut i: i32 = 0; while i < n { { if self.is_e_c_i(index + i) { return false; } } i += 1; } } return true; } /** * Returns the {@code int} ECI value at the specified index. An index ranges from zero * to {@code length() - 1}. The first {@code byte} value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing. * * @param index the index of the {@code int} value to be returned * * @return the specified {@code int} ECI value. * The ECI specified the encoding of all bytes with a higher index until the * next ECI or until the end of the input if no other ECI follows. * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} * @throws IllegalArgumentException * if the value at the {@code index} argument is not an ECI (@see #isECI) */ fn get_e_c_i_value( &self, index: i32, ) -> Result { if index < 0 || index >= self.length() { return Err(IndexOutOfBoundsException::new(format!("{}", index))); } if !self.is_e_c_i(index) { return Err(IllegalArgumentException::new(format!( "value at {} is not an ECI but a character", index ))); } return self.bytes[index] - 256; } /** * Determines if a value is an ECI * * @param index the index of the value * * @return true if the value at position {@code index} is an ECI * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} */ fn is_e_c_i(&self, index: i32) -> Result { if index < 0 || index >= self.length() { return Err(IndexOutOfBoundsException::new(format!("{}", index))); } return Ok(self.bytes[index] > 255 && self.bytes[index] <= 999); } /** * Returns a {@code CharSequence} that is a subsequence of this sequence. * The subsequence starts with the {@code char} value at the specified index and * ends with the {@code char} value at index {@code end - 1}. The length * (in {@code char}s) of the * returned sequence is {@code end - start}, so if {@code start == end} * then an empty sequence is returned. * * @param start the start index, inclusive * @param end the end index, exclusive * * @return the specified subsequence * * @throws IndexOutOfBoundsException * if {@code start} or {@code end} are negative, * if {@code end} is greater than {@code length()}, * or if {@code start} is greater than {@code end} * @throws IllegalArgumentException * if a value in the range {@code start}-{@code end} is an ECI (@see #isECI) */ fn sub_sequence( &self, start: i32, end: i32, ) -> Result { if start < 0 || start > end || end > self.length() { return Err(IndexOutOfBoundsException::new(format!("{}", start))); } let result: StringBuilder = StringBuilder::new(); { let mut i: i32 = start; while i < end { { if self.is_e_c_i(i) { return Err(IllegalArgumentException::new(format!( "value at {} is not a character but an ECI", i ))); } result.append(&self.char_at(i)); } i += 1; } } return result; } /** * Returns the {@code byte} value at the specified index. An index ranges from zero * to {@code length() - 1}. The first {@code byte} value of the sequence is at * index zero, the next at index one, and so on, as for array * indexing. * * @param index the index of the {@code byte} value to be returned * * @return the specified {@code byte} value as character or the FNC1 character * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} * @throws IllegalArgumentException * if the value at the {@code index} argument is an ECI (@see #isECI) */ fn char_at( &self, index: i32, ) -> Result { if index < 0 || index >= self.length() { return Err(IndexOutOfBoundsException::new(format!("{}", index))); } if self.is_e_c_i(index) { return Err(IllegalArgumentException::new(format!( "value at {} is not a character but an ECI", index ))); } return if self.is_f_n_c1(index) { Ok(self.fnc1 as char) } else { Ok(self.bytes[index] as char) }; } /** * Returns the length of this input. The length is the number * of {@code byte}s, FNC1 characters or ECIs in the sequence. * * @return the number of {@code char}s in this sequence */ fn length(&self) -> i32 { return self.bytes.len(); } } impl MinimalECIInput { /** * Constructs a minimal input * * @param stringToEncode the character string to encode * @param priorityCharset The preferred {@link Charset}. When the value of the argument is null, the algorithm * chooses charsets that leads to a minimal representation. Otherwise the algorithm will use the priority * charset to encode any character in the input that can be encoded by it if the charset is among the * supported charsets. * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not GS1 * input. */ pub fn new(string_to_encode: &String, priority_charset: &Charset, fnc1: i32) -> Self { let mut new_mecii: Self; new_mecii.fnc1 = fnc1; let encoder_set: ECIEncoderSet = ECIEncoderSet::new(&string_to_encode, &priority_charset, fnc1); if encoder_set.length() == 1 { //optimization for the case when all can be encoded without ECI in ISO-8859-1 bytes = [0; string_to_encode.length()]; { let mut i: i32 = 0; while i < bytes.len() { { let c: char = string_to_encode.char_at(i); bytes[i] = if c == fnc1 { 1000 } else { c as i32 }; } i += 1; } } } else { bytes = ::encode_minimally(&string_to_encode, encoder_set, fnc1); } } pub fn get_f_n_c1_character(&self) -> i32 { return self.fnc1; } /** * Determines if a value is the FNC1 character * * @param index the index of the value * * @return true if the value at position {@code index} is the FNC1 character * * @throws IndexOutOfBoundsException * if the {@code index} argument is negative or not less than * {@code length()} */ pub fn is_f_n_c1(&self, index: i32) -> Result { if index < 0 || index >= self.length() { return Err(IndexOutOfBoundsException::new(format!("{}", index))); } return Ok(self.bytes[index] == 1000); } pub fn to_string(&self) -> String { let result: StringBuilder = StringBuilder::new(); { let mut i: i32 = 0; while i < self.length() { { if i > 0 { result.append(", "); } if self.is_e_c_i(i) { result.append("ECI("); result.append(&self.get_e_c_i_value(i)); result.append(')'); } else if self.char_at(i) < 128 { result.append('\''); result.append(&self.char_at(i)); result.append('\''); } else { result.append(self.char_at(i) as i32); } } i += 1; } } return result.to_string(); } fn add_edge(edges: &Vec>, to: i32, edge: &InputEdge) { if edges[to][edge.encoderIndex] == null || edges[to][edge.encoderIndex].cachedTotalSize > edge.cachedTotalSize { edges[to][edge.encoderIndex] = edge; } } fn add_edges( string_to_encode: &String, encoder_set: &ECIEncoderSet, edges: &Vec>, from: i32, previous: &InputEdge, fnc1: i32, ) { let ch: char = string_to_encode.char_at(from); let mut start: i32 = 0; let mut end: i32 = encoder_set.length(); if encoder_set.get_priority_encoder_index() >= 0 && (ch == fnc1 || encoder_set.can_encode(ch, &encoder_set.get_priority_encoder_index())) { start = encoder_set.get_priority_encoder_index(); end = start + 1; } { let mut i: i32 = start; while i < end { { if ch == fnc1 || encoder_set.can_encode(ch, i) { ::add_edge( edges, from + 1, InputEdge::new(ch, encoder_set, i, previous, fnc1), ); } } i += 1; } } } fn encode_minimally( string_to_encode: &String, encoder_set: &ECIEncoderSet, fnc1: i32, ) -> Result, RuntimeException> { let input_length: i32 = string_to_encode.length(); // Array that represents vertices. There is a vertex for every character and encoding. let mut edges: [[Option; encoder_set.length()]; input_length + 1] = [[None; encoder_set.length()]; input_length + 1]; ::add_edges(&string_to_encode, encoder_set, edges, 0, null, fnc1); { let mut i: i32 = 1; while i <= input_length { { { let mut j: i32 = 0; while j < encoder_set.length() { { if edges[i][j] != null && i < input_length { ::add_edges( &string_to_encode, encoder_set, edges, i, edges[i][j], fnc1, ); } } j += 1; } } //optimize memory by removing edges that have been passed. { let mut j: i32 = 0; while j < encoder_set.length() { { edges[i - 1][j] = null; } j += 1; } } } i += 1; } } let minimal_j: i32 = -1; let minimal_size: i32 = Integer::MAX_VALUE; { let mut j: i32 = 0; while j < encoder_set.length() { { if edges[input_length][j] != null { let edge: InputEdge = edges[input_length][j]; if edge.cachedTotalSize < minimal_size { minimal_size = edge.cachedTotalSize; minimal_j = j; } } } j += 1; } } if minimal_j < 0 { return Err(RuntimeException::new(format!( "Internal error: failed to encode \"{}\"", string_to_encode ))); } let ints_a_l: List = Vec::new(); let mut current: InputEdge = edges[input_length][minimal_j]; while current != null { if current.is_f_n_c1() { ints_a_l.add(0, 1000); } else { let bytes: Vec = encoder_set.encode(current.c, current.encoderIndex); { let mut i: i32 = bytes.len() - 1; while i >= 0 { { ints_a_l.add(0, (bytes[i] & 0xFF)); } i -= 1; } } } let previous_encoder_index: i32 = if current.previous == null { 0 } else { current.previous.encoderIndex }; if previous_encoder_index != current.encoderIndex { ints_a_l.add(0, 256 + encoder_set.get_e_c_i_value(current.encoderIndex)); } current = current.previous; } let mut ints: [i32; ints_a_l.size()] = [0; ints_a_l.size()]; { let mut i: i32 = 0; while i < ints.len() { { ints[i] = ints_a_l.get(i); } i += 1; } } return ints; } } struct InputEdge { c: char, //the encoding of this edge encoder_index: i32, previous: InputEdge, cached_total_size: i32, } impl InputEdge { fn new( c: char, encoder_set: &ECIEncoderSet, encoder_index: i32, previous: &InputEdge, fnc1: i32, ) -> Self { let mut new_ie: Self; new_ie.c = if c == fnc1 { 1000 } else { c }; new_ie.encoderIndex = encoder_index; new_ie.previous = previous; let mut size: i32 = if new_ie.c == 1000 { 1 } else { encoder_set.encode(c, encoder_index).len() }; let previous_encoder_index: i32 = if previous == null { 0 } else { previous.encoderIndex }; if previous_encoder_index != encoder_index { size += COST_PER_ECI; } if previous != null { size += previous.cachedTotalSize; } new_ie.cachedTotalSize = size; new_ie } fn is_f_n_c1(&self) -> bool { return self.c == 1000; } } // PerspectiveTransform.java /** *

This class implements a perspective transform in two dimensions. Given four source and four * destination points, it will compute the transformation implied between them. The code is based * directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.

* * @author Sean Owen */ pub struct PerspectiveTransform { a11: f32, a12: f32, a13: f32, a21: f32, a22: f32, a23: f32, a31: f32, a32: f32, a33: f32, } impl PerspectiveTransform { fn new( a11: f32, a21: f32, a31: f32, a12: f32, a22: f32, a32: f32, a13: f32, a23: f32, a33: f32, ) -> Self { Self { a11: a11, a12: a12, a13: a13, a21: a21, a22: a22, a23: a23, a31: a31, a32: a32, a33: a33, } } pub fn quadrilateral_to_quadrilateral( x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32, x0p: f32, y0p: f32, x1p: f32, y1p: f32, x2p: f32, y2p: f32, x3p: f32, y3p: f32, ) -> PerspectiveTransform { let q_to_s: PerspectiveTransform = ::quadrilateral_to_square(x0, y0, x1, y1, x2, y2, x3, y3); let s_to_q: PerspectiveTransform = ::square_to_quadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); return s_to_q.times(&q_to_s); } pub fn transform_points(&self, points: &Vec) { let a11: f32 = self.a11; let a12: f32 = self.a12; let a13: f32 = self.a13; let a21: f32 = self.a21; let a22: f32 = self.a22; let a23: f32 = self.a23; let a31: f32 = self.a31; let a32: f32 = self.a32; let a33: f32 = self.a33; // points.length must be even let max_i: i32 = points.len() - 1; { let mut i: i32 = 0; while i < max_i { { let x: f32 = points[i]; let y: f32 = points[i + 1]; let denominator: f32 = a13 * x + a23 * y + a33; points[i] = (a11 * x + a21 * y + a31) / denominator; points[i + 1] = (a12 * x + a22 * y + a32) / denominator; } i += 2; } } } pub fn transform_points(&self, x_values: &Vec, y_values: &Vec) { let n: i32 = x_values.len(); { let mut i: i32 = 0; while i < n { { let x: f32 = x_values[i]; let y: f32 = y_values[i]; let denominator: f32 = self.a13 * x + self.a23 * y + self.a33; x_values[i] = (self.a11 * x + self.a21 * y + self.a31) / denominator; y_values[i] = (self.a12 * x + self.a22 * y + self.a32) / denominator; } i += 1; } } } pub fn square_to_quadrilateral( x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32, ) -> PerspectiveTransform { let dx3: f32 = x0 - x1 + x2 - x3; let dy3: f32 = y0 - y1 + y2 - y3; if dx3 == 0.0f32 && dy3 == 0.0f32 { // Affine return PerspectiveTransform::new( x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f32, 0.0f32, 1.0f32, ); } else { let dx1: f32 = x1 - x2; let dx2: f32 = x3 - x2; let dy1: f32 = y1 - y2; let dy2: f32 = y3 - y2; let denominator: f32 = dx1 * dy2 - dx2 * dy1; let a13: f32 = (dx3 * dy2 - dx2 * dy3) / denominator; let a23: f32 = (dx1 * dy3 - dx3 * dy1) / denominator; return PerspectiveTransform::new( x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0f32, ); } } pub fn quadrilateral_to_square( x0: f32, y0: f32, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32, ) -> PerspectiveTransform { // Here, the adjoint serves as the inverse: return ::square_to_quadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).build_adjoint(); } fn build_adjoint(&self) -> PerspectiveTransform { // Adjoint is the transpose of the cofactor matrix: return PerspectiveTransform::new( self.a22 * self.a33 - self.a23 * self.a32, self.a23 * self.a31 - self.a21 * self.a33, self.a21 * self.a32 - self.a22 * self.a31, self.a13 * self.a32 - self.a12 * self.a33, self.a11 * self.a33 - self.a13 * self.a31, self.a12 * self.a31 - self.a11 * self.a32, self.a12 * self.a23 - self.a13 * self.a22, self.a13 * self.a21 - self.a11 * self.a23, self.a11 * self.a22 - self.a12 * self.a21, ); } fn times(&self, other: &PerspectiveTransform) -> PerspectiveTransform { return PerspectiveTransform::new( self.a11 * other.a11 + self.a21 * other.a12 + self.a31 * other.a13, self.a11 * other.a21 + self.a21 * other.a22 + self.a31 * other.a23, self.a11 * other.a31 + self.a21 * other.a32 + self.a31 * other.a33, self.a12 * other.a11 + self.a22 * other.a12 + self.a32 * other.a13, self.a12 * other.a21 + self.a22 * other.a22 + self.a32 * other.a23, self.a12 * other.a31 + self.a22 * other.a32 + self.a32 * other.a33, self.a13 * other.a11 + self.a23 * other.a12 + self.a33 * other.a13, self.a13 * other.a21 + self.a23 * other.a22 + self.a33 * other.a23, self.a13 * other.a31 + self.a23 * other.a32 + self.a33 * other.a33, ); } } // StringUtils.java /** * Common string-related functions. * * @author Sean Owen * @author Alex Dupre */ const PLATFORM_DEFAULT_ENCODING: Charset = Charset::default_charset(); const SHIFT_JIS_CHARSET: Charset = Charset::for_name("SJIS"); const GB2312_CHARSET: Charset = Charset::for_name("GB2312"); const EUC_JP: Charset = Charset::for_name("EUC_JP"); const ASSUME_SHIFT_JIS: bool = SHIFT_JIS_CHARSET::equals(&PLATFORM_DEFAULT_ENCODING) || EUC_JP::equals(&PLATFORM_DEFAULT_ENCODING); // Retained for ABI compatibility with earlier versions const SHIFT_JIS: &'static str = "SJIS"; const GB2312: &'static str = "GB2312"; pub struct StringUtils {} impl StringUtils { fn new() -> StringUtils {} /** * @param bytes bytes encoding a string, whose encoding should be guessed * @param hints decode hints if applicable * @return name of guessed encoding; at the moment will only guess one of: * "SJIS", "UTF8", "ISO8859_1", or the platform default encoding if none * of these can possibly be correct */ pub fn guess_encoding(bytes: &Vec, hints: &HashMap) -> &str { let c: Charset = ::guess_charset(&bytes, &hints); if c == SHIFT_JIS_CHARSET { return "SJIS"; } else if c == StandardCharsets::UTF_8 { return "UTF8"; } else if c == StandardCharsets::ISO_8859_1 { return "ISO8859_1"; } return c.name(); } /** * @param bytes bytes encoding a string, whose encoding should be guessed * @param hints decode hints if applicable * @return Charset of guessed encoding; at the moment will only guess one of: * {@link #SHIFT_JIS_CHARSET}, {@link StandardCharsets#UTF_8}, * {@link StandardCharsets#ISO_8859_1}, {@link StandardCharsets#UTF_16}, * or the platform default encoding if * none of these can possibly be correct */ pub fn guess_charset(bytes: &Vec, hints: &HashMap) -> Charset { if hints != null && hints.contains_key(DecodeHintType::CHARACTER_SET) { return Charset::for_name(&hints.get(DecodeHintType::CHARACTER_SET).to_string()); } // First try UTF-16, assuming anything with its BOM is UTF-16 if bytes.len() > 2 && ((bytes[0] == 0xFE as i8 && bytes[1] == 0xFF as i8) || (bytes[0] == 0xFF as i8 && bytes[1] == 0xFE as i8)) { return StandardCharsets::UTF_16; } // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, // which should be by far the most common encodings. let length: i32 = bytes.len(); let can_be_i_s_o88591: bool = true; let can_be_shift_j_i_s: bool = true; let can_be_u_t_f8: bool = true; let utf8_bytes_left: i32 = 0; let utf2_bytes_chars: i32 = 0; let utf3_bytes_chars: i32 = 0; let utf4_bytes_chars: i32 = 0; let sjis_bytes_left: i32 = 0; let sjis_katakana_chars: i32 = 0; let sjis_cur_katakana_word_length: i32 = 0; let sjis_cur_double_bytes_word_length: i32 = 0; let sjis_max_katakana_word_length: i32 = 0; let sjis_max_double_bytes_word_length: i32 = 0; let iso_high_other: i32 = 0; let utf8bom: bool = bytes.len() > 3 && bytes[0] == 0xEF as i8 && bytes[1] == 0xBB as i8 && bytes[2] == 0xBF as i8; { let mut i: i32 = 0; while i < length && (can_be_i_s_o88591 || can_be_shift_j_i_s || can_be_u_t_f8) { { let value: i32 = bytes[i] & 0xFF; // UTF-8 stuff if can_be_u_t_f8 { if utf8_bytes_left > 0 { if (value & 0x80) == 0 { can_be_u_t_f8 = false; } else { utf8_bytes_left -= 1; } } else if (value & 0x80) != 0 { if (value & 0x40) == 0 { can_be_u_t_f8 = false; } else { utf8_bytes_left += 1; if (value & 0x20) == 0 { utf2_bytes_chars += 1; } else { utf8_bytes_left += 1; if (value & 0x10) == 0 { utf3_bytes_chars += 1; } else { utf8_bytes_left += 1; if (value & 0x08) == 0 { utf4_bytes_chars += 1; } else { can_be_u_t_f8 = false; } } } } } } // ISO-8859-1 stuff if can_be_i_s_o88591 { if value > 0x7F && value < 0xA0 { can_be_i_s_o88591 = false; } else if value > 0x9F && (value < 0xC0 || value == 0xD7 || value == 0xF7) { iso_high_other += 1; } } // Shift_JIS stuff if can_be_shift_j_i_s { if sjis_bytes_left > 0 { if value < 0x40 || value == 0x7F || value > 0xFC { can_be_shift_j_i_s = false; } else { sjis_bytes_left -= 1; } } else if value == 0x80 || value == 0xA0 || value > 0xEF { can_be_shift_j_i_s = false; } else if value > 0xA0 && value < 0xE0 { sjis_katakana_chars += 1; sjis_cur_double_bytes_word_length = 0; sjis_cur_katakana_word_length += 1; if sjis_cur_katakana_word_length > sjis_max_katakana_word_length { sjis_max_katakana_word_length = sjis_cur_katakana_word_length; } } else if value > 0x7F { sjis_bytes_left += 1; //sjisDoubleBytesChars++; sjis_cur_katakana_word_length = 0; sjis_cur_double_bytes_word_length += 1; if sjis_cur_double_bytes_word_length > sjis_max_double_bytes_word_length { sjis_max_double_bytes_word_length = sjis_cur_double_bytes_word_length; } } else { //sjisLowChars++; sjis_cur_katakana_word_length = 0; sjis_cur_double_bytes_word_length = 0; } } } i += 1; } } if can_be_u_t_f8 && utf8_bytes_left > 0 { can_be_u_t_f8 = false; } if can_be_shift_j_i_s && sjis_bytes_left > 0 { can_be_shift_j_i_s = false; } // Easy -- if there is BOM or at least 1 valid not-single byte character (and no evidence it can't be UTF-8), done if can_be_u_t_f8 && (utf8bom || utf2_bytes_chars + utf3_bytes_chars + utf4_bytes_chars > 0) { return StandardCharsets::UTF_8; } // Easy -- if assuming Shift_JIS or >= 3 valid consecutive not-ascii characters (and no evidence it can't be), done if can_be_shift_j_i_s && (ASSUME_SHIFT_JIS || sjis_max_katakana_word_length >= 3 || sjis_max_double_bytes_word_length >= 3) { return SHIFT_JIS_CHARSET; } // - then we conclude Shift_JIS, else ISO-8859-1 if can_be_i_s_o88591 && can_be_shift_j_i_s { return if (sjis_max_katakana_word_length == 2 && sjis_katakana_chars == 2) || iso_high_other * 10 >= length { SHIFT_JIS_CHARSET } else { StandardCharsets::ISO_8859_1 }; } // Otherwise, try in order ISO-8859-1, Shift JIS, UTF-8 and fall back to default platform encoding if can_be_i_s_o88591 { return StandardCharsets::ISO_8859_1; } if can_be_shift_j_i_s { return SHIFT_JIS_CHARSET; } if can_be_u_t_f8 { return StandardCharsets::UTF_8; } // Otherwise, we take a wild guess with platform encoding return PLATFORM_DEFAULT_ENCODING; } }