From c77f0af6f610bbf4ce99aa7c5d7b6f3fb98d62a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Fri, 17 Feb 2023 16:12:23 +0000 Subject: [PATCH 1/6] remove unnecessary number suffixes --- src/aztec/decoder.rs | 2 +- src/aztec/detector.rs | 26 +++++++++---------- src/aztec/encoder/aztec_encoder.rs | 2 +- src/aztec/encoder/high_level_encoder.rs | 2 +- src/client/result/CalendarParsedResult.rs | 16 ++++++------ .../result/CalendarParsedResultTestCase.rs | 2 +- src/common/PerspectiveTransformTestCase.rs | 4 +-- src/common/bit_array.rs | 2 +- .../detector/white_rectangle_detector.rs | 2 +- src/common/global_histogram_binarizer.rs | 2 +- src/common/hybrid_binarizer.rs | 4 +-- src/common/perspective_transform.rs | 16 +++--------- src/common/reedsolomon/ReedSolomonTestCase.rs | 4 +-- src/datamatrix/decoder/datamatrix_decoder.rs | 2 +- src/datamatrix/encoder/minimal_encoder.rs | 2 +- .../decoder/decoded_bit_stream_parser.rs | 2 +- src/maxicode/decoder/maxicode_decoder.rs | 2 +- src/oned/coda_bar_reader.rs | 4 +-- .../decoder/FormatInformationTestCase.rs | 2 +- .../decoder/decoded_bit_stream_parser.rs | 4 +-- src/qrcode/encoder/bit_vector_testcase.rs | 2 +- 21 files changed, 46 insertions(+), 58 deletions(-) diff --git a/src/aztec/decoder.rs b/src/aztec/decoder.rs index 52b217b..0dc0be6 100644 --- a/src/aztec/decoder.rs +++ b/src/aztec/decoder.rs @@ -342,7 +342,7 @@ fn correct_bits( } let mut offset = rawbits.len() % codeword_size; - let mut data_words = vec![0i32; num_codewords]; + let mut data_words = vec![0; num_codewords]; for word in data_words.iter_mut().take(num_codewords) { // for i in 0..num_codewords { // for (int i = 0; i < numCodewords; i++, offset += codewordSize) { diff --git a/src/aztec/detector.rs b/src/aztec/detector.rs index 4cbae88..32255ca 100644 --- a/src/aztec/detector.rs +++ b/src/aztec/detector.rs @@ -142,7 +142,7 @@ impl<'a> Detector<'_> { self.shift = Self::get_rotation(&sides, length)?; // Flatten the parameter bits into a single 28- or 40-bit long - let mut parameter_data = 0u64; + let mut parameter_data: u64 = 0; for i in 0..4 { // for (int i = 0; i < 4; i++) { let side = sides[(self.shift + i) as usize % 4]; @@ -230,7 +230,7 @@ impl<'a> Detector<'_> { } let num_eccodewords = num_codewords - num_data_codewords; - let mut parameterWords = vec![0i32; num_codewords as usize]; + let mut parameterWords = vec![0; num_codewords as usize]; for i in (0..num_codewords).rev() { // for (int i = numCodewords - 1; i >= 0; --i) { parameterWords[i as usize] = (parameter_data & 0xF) as i32; @@ -245,7 +245,7 @@ impl<'a> Detector<'_> { //throw NotFoundException.getNotFoundInstance(); //} // Toss the error correction. Just return the data as an integer - let mut result = 0u32; + let mut result: u32 = 0; for i in 0..num_data_codewords { // for (int i = 0; i < numDataCodewords; i++) { result = (result << 4) + parameterWords[i as usize] as u32; @@ -321,10 +321,10 @@ impl<'a> Detector<'_> { // Expand the square by .5 pixel in each direction so that we're on the border // between the white square and the black square - let pinax = point(pina.get_x() as f32 + 0.5f32, pina.get_y() as f32 - 0.5f32); - let pinbx = point(pinb.get_x() as f32 + 0.5f32, pinb.get_y() as f32 + 0.5f32); - let pincx = point(pinc.get_x() as f32 - 0.5f32, pinc.get_y() as f32 + 0.5f32); - let pindx = point(pind.get_x() as f32 - 0.5f32, pind.get_y() as f32 - 0.5f32); + let pinax = point(pina.get_x() as f32 + 0.5, pina.get_y() as f32 - 0.5); + let pinbx = point(pinb.get_x() as f32 + 0.5, pinb.get_y() as f32 + 0.5); + let pincx = point(pinc.get_x() as f32 - 0.5, pinc.get_y() as f32 + 0.5); + let pindx = point(pind.get_x() as f32 - 0.5, pind.get_y() as f32 - 0.5); // Expand the square so that its corners are the centers of the points // just outside the bull's eye. @@ -483,8 +483,8 @@ impl<'a> Detector<'_> { let sampler = DefaultGridSampler::default(); let dimension = self.get_dimension(); - let low = dimension as f32 / 2.0f32 - self.nb_center_layers as f32; - let high = dimension as f32 / 2.0f32 + self.nb_center_layers as f32; + let low = dimension as f32 / 2.0 - self.nb_center_layers as f32; + let high = dimension as f32 / 2.0 + self.nb_center_layers as f32; sampler.sample_grid_detailed( image, @@ -601,7 +601,7 @@ impl<'a> Detector<'_> { */ fn get_color(&self, p1: AztecPoint, p2: AztecPoint) -> i32 { let d = Self::distance_points(p1, p2); - if d == 0.0f32 { + if d == 0.0 { return 0; } let dx = (p2.get_x() - p1.get_x()) as f32 / d; @@ -626,11 +626,11 @@ impl<'a> Detector<'_> { let err_ratio = error as f32 / d; - if err_ratio > 0.1f32 && err_ratio < 0.9f32 { + if err_ratio > 0.1 && err_ratio < 0.9 { return 0; } - if (err_ratio <= 0.1f32) == color_model { + if (err_ratio <= 0.1) == color_model { 1 } else { -1 @@ -674,7 +674,7 @@ impl<'a> Detector<'_> { * @return the corners of the expanded square */ fn expand_square(corner_points: &[Point], old_side: u32, new_side: u32) -> [Point; 4] { - let ratio = new_side as f32 / (2.0f32 * old_side as f32); + let ratio = new_side as f32 / (2.0 * old_side as f32); let d = corner_points[0] - corner_points[2]; let middle = corner_points[0].middle(corner_points[2]); diff --git a/src/aztec/encoder/aztec_encoder.rs b/src/aztec/encoder/aztec_encoder.rs index e8b8544..1ec75c8 100644 --- a/src/aztec/encoder/aztec_encoder.rs +++ b/src/aztec/encoder/aztec_encoder.rs @@ -446,7 +446,7 @@ fn generateCheckWords(bitArray: &BitArray, totalBits: usize, wordSize: usize) -> } fn bitsToWords(stuffedBits: &BitArray, wordSize: usize, totalWords: usize) -> Vec { - let mut message = vec![0i32; totalWords]; + let mut message = vec![0; totalWords]; let mut i = 0; let n = stuffedBits.getSize() / wordSize; while i < n { diff --git a/src/aztec/encoder/high_level_encoder.rs b/src/aztec/encoder/high_level_encoder.rs index 3c4dde2..8bc999b 100644 --- a/src/aztec/encoder/high_level_encoder.rs +++ b/src/aztec/encoder/high_level_encoder.rs @@ -196,7 +196,7 @@ impl HighLevelEncoder { // shown pub const SHIFT_TABLE: [[i32; 6]; 6] = { // mode shift codes, per table - let mut shift_table = [[-1i32; 6]; 6]; + let mut shift_table = [[-1; 6]; 6]; shift_table[Self::MODE_UPPER][Self::MODE_PUNCT] = 0; diff --git a/src/client/result/CalendarParsedResult.rs b/src/client/result/CalendarParsedResult.rs index ece40fd..b2def9e 100644 --- a/src/client/result/CalendarParsedResult.rs +++ b/src/client/result/CalendarParsedResult.rs @@ -40,11 +40,11 @@ use super::{maybe_append_multiple, maybe_append_string, ParsedRXingResult, Parse // const RFC2445_DURATION: &'static str = // "P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?"; const RFC2445_DURATION_FIELD_UNITS: [i64; 5] = [ - 7 * 24 * 60 * 60 * 1000i64, // 1 week - 24 * 60 * 60 * 1000i64, // 1 day - 60 * 60 * 1000i64, // 1 hour - 60 * 1000i64, // 1 minute - 1000i64, // 1 second + 7 * 24 * 60 * 60 * 1000, // 1 week + 24 * 60 * 60 * 1000, // 1 day + 60 * 60 * 1000, // 1 hour + 60 * 1000, // 1 minute + 1000, // 1 second ]; static DATE_TIME: Lazy = Lazy::new(|| Regex::new("[0-9]{8}(T[0-9]{6}Z?)?").unwrap()); @@ -114,8 +114,8 @@ impl CalendarParsedRXingResult { let start = Self::parseDate(startString.clone())?; let end = if endString.is_empty() { let durationMS = Self::parseDurationMS(&durationString)?; - if durationMS < 0i64 { - -1i64 + if durationMS < 0 { + -1 } else { start + (durationMS / 1000) } @@ -240,7 +240,7 @@ impl CalendarParsedRXingResult { } // let regex = Regex::new(RFC2445_DURATION).unwrap(); if let Some(m) = RFC2445_DURATION.captures(durationString) { - let mut durationMS = 0i64; + let mut durationMS: i64 = 0; for (i, unit) in RFC2445_DURATION_FIELD_UNITS.iter().enumerate() { // for i in 0..RFC2445_DURATION_FIELD_UNITS.len() { // for (int i = 0; i < RFC2445_DURATION_FIELD_UNITS.length; i++) { diff --git a/src/client/result/CalendarParsedResultTestCase.rs b/src/client/result/CalendarParsedResultTestCase.rs index e2e2609..45a2abd 100644 --- a/src/client/result/CalendarParsedResultTestCase.rs +++ b/src/client/result/CalendarParsedResultTestCase.rs @@ -224,7 +224,7 @@ fn doTest( ); assert_eq!( endString, - if calRXingResult.getEndTimestamp() < 0i64 { + if calRXingResult.getEndTimestamp() < 0 { String::default() } else { format_date_string(calRXingResult.getEndTimestamp(), dateFormat) diff --git a/src/common/PerspectiveTransformTestCase.rs b/src/common/PerspectiveTransformTestCase.rs index d30452f..8d875ae 100644 --- a/src/common/PerspectiveTransformTestCase.rs +++ b/src/common/PerspectiveTransformTestCase.rs @@ -29,9 +29,7 @@ static EPSILON: f32 = 1.0E-4f32; #[test] fn test_square_to_quadrilateral() { - let pt = PerspectiveTransform::squareToQuadrilateral( - 2.0f32, 3.0f32, 10.0, 4.0, 16.0, 15.0, 4.0, 9.0, - ); + let pt = PerspectiveTransform::squareToQuadrilateral(2.0, 3.0, 10.0, 4.0, 16.0, 15.0, 4.0, 9.0); assert_point_equals(2.0, 3.0, 0.0, 0.0, &pt); assert_point_equals(10.0, 4.0, 1.0, 0.0, &pt); assert_point_equals(4.0, 9.0, 0.0, 1.0, &pt); diff --git a/src/common/bit_array.rs b/src/common/bit_array.rs index 471c4a8..9e64c24 100644 --- a/src/common/bit_array.rs +++ b/src/common/bit_array.rs @@ -23,7 +23,7 @@ use std::{cmp, fmt}; use crate::common::Result; use crate::Exceptions; -static LOAD_FACTOR: f32 = 0.75f32; +static LOAD_FACTOR: f32 = 0.75; /** *

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

diff --git a/src/common/detector/white_rectangle_detector.rs b/src/common/detector/white_rectangle_detector.rs index bb53065..04c4c3f 100644 --- a/src/common/detector/white_rectangle_detector.rs +++ b/src/common/detector/white_rectangle_detector.rs @@ -335,7 +335,7 @@ impl<'a> WhiteRectangleDetector<'_> { let ti = t.x; let tj = t.y; - if yi < self.width as f32 / 2.0f32 { + if yi < self.width as f32 / 2.0 { [ point(ti - CORR as f32, tj + CORR as f32), point(zi + CORR as f32, zj + CORR as f32), diff --git a/src/common/global_histogram_binarizer.rs b/src/common/global_histogram_binarizer.rs index 82f2091..4c7c1dc 100644 --- a/src/common/global_histogram_binarizer.rs +++ b/src/common/global_histogram_binarizer.rs @@ -241,7 +241,7 @@ impl GlobalHistogramBinarizer { // Find a valley between them that is low and closer to the white peak. let mut bestValley = secondPeak - 1; - let mut bestValleyScore = -1i32; + let mut bestValleyScore = -1; let mut x = secondPeak; while x > firstPeak { // for (int x = secondPeak - 1; x > firstPeak; x--) { diff --git a/src/common/hybrid_binarizer.rs b/src/common/hybrid_binarizer.rs index 48f62e3..3bf3004 100644 --- a/src/common/hybrid_binarizer.rs +++ b/src/common/hybrid_binarizer.rs @@ -179,7 +179,7 @@ impl HybridBinarizer { } let left = Self::cap(x, sub_width - 3); let mut sum = 0; - for z in -2i32..=2 { + for z in -2..=2 { // for (int z = -2; z <= 2; z++) { let blackRow = &black_points[(top as i32 + z) as usize]; sum += blackRow[(left - 2) as usize] @@ -255,7 +255,7 @@ impl HybridBinarizer { if xoffset > maxXOffset as u32 { xoffset = maxXOffset as u32; } - let mut sum = 0u32; + let mut sum: u32 = 0; let mut min = 0xff; let mut max = 0; diff --git a/src/common/perspective_transform.rs b/src/common/perspective_transform.rs index e6201c1..2c49565 100644 --- a/src/common/perspective_transform.rs +++ b/src/common/perspective_transform.rs @@ -133,19 +133,9 @@ impl PerspectiveTransform { ) -> Self { let dx3 = x0 - x1 + x2 - x3; let dy3 = y0 - y1 + y2 - y3; - if dx3 == 0.0f32 && dy3 == 0.0f32 { + if dx3 == 0.0 && dy3 == 0.0 { // Affine - PerspectiveTransform::new( - x1 - x0, - x2 - x1, - x0, - y1 - y0, - y2 - y1, - y0, - 0.0f32, - 0.0f32, - 1.0f32, - ) + PerspectiveTransform::new(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0, 0.0, 1.0) } else { let dx1 = x1 - x2; let dx2 = x3 - x2; @@ -163,7 +153,7 @@ impl PerspectiveTransform { y0, a13, a23, - 1.0f32, + 1.0, ) } } diff --git a/src/common/reedsolomon/ReedSolomonTestCase.rs b/src/common/reedsolomon/ReedSolomonTestCase.rs index b62b31e..efc9250 100644 --- a/src/common/reedsolomon/ReedSolomonTestCase.rs +++ b/src/common/reedsolomon/ReedSolomonTestCase.rs @@ -348,7 +348,7 @@ pub(crate) fn corrupt( ) { let mut corrupted = vec![false; received.len()]; //BitSet corrupted = new BitSet(received.length); - let mut j = 0isize; + let mut j: isize = 0; while j < howMany as isize { // for (int j = 0; j < howMany; j++) { let location: usize = random.gen_range(0..received.len()); @@ -477,7 +477,7 @@ fn test_decoder(field: GenericGFRef, dataWords: &Vec, ecWords: &Vec) { }; for _j in 0..iterations { //for (int j = 0; j < iterations; j++) { - let mut i = 0isize; + let mut i: isize = 0; while i < ecWords.len() as isize { //for (int i = 0; i < ecWords.length; i++) { if i > 10 && i < ecWords.len() as isize / 2 - 10 { diff --git a/src/datamatrix/decoder/datamatrix_decoder.rs b/src/datamatrix/decoder/datamatrix_decoder.rs index 584fd2a..b087ae9 100644 --- a/src/datamatrix/decoder/datamatrix_decoder.rs +++ b/src/datamatrix/decoder/datamatrix_decoder.rs @@ -153,7 +153,7 @@ impl Decoder { fn correctErrors(&self, codewordBytes: &mut [u8], numDataCodewords: u32) -> Result<()> { let _numCodewords = codewordBytes.len(); // First read into an array of ints - // let codewordsInts = vec![0i32;numCodewords]; + // let codewordsInts = vec![0;numCodewords]; // for i in 0..numCodewords { // // for (int i = 0; i < numCodewords; i++) { // codewordsInts[i] = codewordBytes[i]; diff --git a/src/datamatrix/encoder/minimal_encoder.rs b/src/datamatrix/encoder/minimal_encoder.rs index 248a670..df50667 100755 --- a/src/datamatrix/encoder/minimal_encoder.rs +++ b/src/datamatrix/encoder/minimal_encoder.rs @@ -375,7 +375,7 @@ fn addEdges( //We create 4 EDF edges, with 1, 2 3 or 4 characters length. The fourth normally doesn't have a latch to ASCII //unless it is 2 characters away from the end of the input. - let mut i = 0u32; + let mut i: u32 = 0; while i < 3 { // for (i = 0; i < 3; i++) { let pos = from + i; diff --git a/src/maxicode/decoder/decoded_bit_stream_parser.rs b/src/maxicode/decoder/decoded_bit_stream_parser.rs index 14c1d18..1ac3958 100644 --- a/src/maxicode/decoder/decoded_bit_stream_parser.rs +++ b/src/maxicode/decoder/decoded_bit_stream_parser.rs @@ -136,7 +136,7 @@ fn getBit(bit: u8, bytes: &[u8]) -> u8 { } fn getInt(bytes: &[u8], x: &[u8]) -> u32 { - let mut val = 0u32; + let mut val: u32 = 0; for i in 0..x.len() { // for (int i = 0; i < x.length; i++) { val += (getBit(x[i], bytes) as u32) << ((x.len() - i - 1) as u32); diff --git a/src/maxicode/decoder/maxicode_decoder.rs b/src/maxicode/decoder/maxicode_decoder.rs index 95bbf41..1afa6cc 100644 --- a/src/maxicode/decoder/maxicode_decoder.rs +++ b/src/maxicode/decoder/maxicode_decoder.rs @@ -95,7 +95,7 @@ fn correctErrors( let divisor = if mode == ALL { 1 } else { 2 }; // First read into an array of ints - let mut codewordsInts = vec![0i32; (codewords / divisor) as usize]; + let mut codewordsInts = vec![0; (codewords / divisor) as usize]; for i in 0..codewords { if (mode == ALL) || (i % 2 == (mode - 1)) { codewordsInts[(i / divisor) as usize] = codewordBytes[(i + start) as usize] as i32; diff --git a/src/oned/coda_bar_reader.rs b/src/oned/coda_bar_reader.rs index c16a0d1..961b1bf 100644 --- a/src/oned/coda_bar_reader.rs +++ b/src/oned/coda_bar_reader.rs @@ -91,7 +91,7 @@ impl OneDReader for CodaBarReader { // Look for whitespace after pattern: let trailingWhitespace = self.counters[nextStart - 1]; let mut lastPatternSize = 0; - for i in -8isize..-1 { + for i in -8..-1 { lastPatternSize += self.counters[(nextStart as isize + i) as usize]; } @@ -283,7 +283,7 @@ impl CodaBarReader { .nth(i) .ok_or(Exceptions::indexOutOfBounds)? as usize]; - for j in (0usize..=6).rev() { + for j in (0..=6).rev() { // Even j = bars, while odd j = spaces. Categories 2 and 3 are for // long stripes, while 0 and 1 are for short stripes. let category = (j & 1) + ((pattern as usize) & 1) * 2; diff --git a/src/qrcode/decoder/FormatInformationTestCase.rs b/src/qrcode/decoder/FormatInformationTestCase.rs index 4562c5c..1d361c4 100644 --- a/src/qrcode/decoder/FormatInformationTestCase.rs +++ b/src/qrcode/decoder/FormatInformationTestCase.rs @@ -28,7 +28,7 @@ fn testBitsDiffering() { assert_eq!(0, FormatInformation::numBitsDiffering(1, 1)); assert_eq!(1, FormatInformation::numBitsDiffering(0, 2)); assert_eq!(2, FormatInformation::numBitsDiffering(1, 2)); - assert_eq!(32, FormatInformation::numBitsDiffering(-1i32 as u32, 0)); + assert_eq!(32, FormatInformation::numBitsDiffering(u32::MAX, 0)); } #[test] diff --git a/src/qrcode/decoder/decoded_bit_stream_parser.rs b/src/qrcode/decoder/decoded_bit_stream_parser.rs index 1e5302e..dbed991 100644 --- a/src/qrcode/decoder/decoded_bit_stream_parser.rs +++ b/src/qrcode/decoder/decoded_bit_stream_parser.rs @@ -48,8 +48,8 @@ pub fn decode( let mut bits = BitSource::new(bytes.to_owned()); let mut result = String::with_capacity(50); let mut byteSegments = vec![vec![0u8; 0]; 0]; - let mut symbolSequence = -1i32; - let mut parityData = -1i32; + let mut symbolSequence = -1; + let mut parityData = -1; let mut currentCharacterSetECI = None; let mut fc1InEffect = false; diff --git a/src/qrcode/encoder/bit_vector_testcase.rs b/src/qrcode/encoder/bit_vector_testcase.rs index 20056d5..5517f9e 100644 --- a/src/qrcode/encoder/bit_vector_testcase.rs +++ b/src/qrcode/encoder/bit_vector_testcase.rs @@ -22,7 +22,7 @@ use crate::common::BitArray; */ fn getUnsignedInt(v: &BitArray) -> u64 { - let mut result = 0u64; + let mut result: u64 = 0; const OFFSET: usize = 0; for i in 0..32 { // for (int i = 0, offset = 0; i < 32; i++) { From 8fc0e1029cb71d7cd5ec4d9fff0cfd507d7209e1 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Sun, 26 Feb 2023 12:22:52 -0600 Subject: [PATCH 2/6] initial move of one-d-proc-macros --- Cargo.toml | 10 +- crates/one-d-proc-derive/.gitignore | 10 ++ crates/one-d-proc-derive/Cargo.toml | 16 +++ crates/one-d-proc-derive/LICENSE | 201 ++++++++++++++++++++++++++++ crates/one-d-proc-derive/README.md | 2 + crates/one-d-proc-derive/src/lib.rs | 181 +++++++++++++++++++++++++ 6 files changed, 417 insertions(+), 3 deletions(-) create mode 100644 crates/one-d-proc-derive/.gitignore create mode 100644 crates/one-d-proc-derive/Cargo.toml create mode 100644 crates/one-d-proc-derive/LICENSE create mode 100644 crates/one-d-proc-derive/README.md create mode 100644 crates/one-d-proc-derive/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 844fb51..f79f94c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,7 @@ image = {version = "0.24", optional = true} imageproc = {version = "0.23", optional = true} unicode-segmentation = "1.10" codepage-437 = "0.1.0" -rxing-one-d-proc-derive = "0.3" -#rxing-one-d-proc-derive = {path ="../rxing-one-d-proc-derive"} +rxing-one-d-proc-derive = {version = "0.3", path ="./crates/one-d-proc-derive"} num = "0.4.0" svg = {version = "0.13", optional = true} resvg = {version = "0.28.0", optional = true, default-features=false} @@ -62,4 +61,9 @@ experimental_features = [] serde = ["dep:serde"] #/// Adds otsu binarizer support using imageproc -otsu_level = ["image"] \ No newline at end of file +otsu_level = ["image"] + +[workspace] +members = [ + "crates/one-d-proc-derive" +] \ No newline at end of file diff --git a/crates/one-d-proc-derive/.gitignore b/crates/one-d-proc-derive/.gitignore new file mode 100644 index 0000000..088ba6b --- /dev/null +++ b/crates/one-d-proc-derive/.gitignore @@ -0,0 +1,10 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk diff --git a/crates/one-d-proc-derive/Cargo.toml b/crates/one-d-proc-derive/Cargo.toml new file mode 100644 index 0000000..cb45247 --- /dev/null +++ b/crates/one-d-proc-derive/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rxing-one-d-proc-derive" +repository = "https://github.com/rxing-core/rxing/tree/main/crates/one-d-proc-derive" +version = "0.3.0" +edition = "2021" +description = "proc macros to simplify the development of one-d barcode symbologies in rxing (https://github.com/rxing-core/rxing)" +license = "Apache-2.0" + +[lib] +proc-macro = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +syn = "1.0" +quote = "1.0" diff --git a/crates/one-d-proc-derive/LICENSE b/crates/one-d-proc-derive/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/crates/one-d-proc-derive/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/crates/one-d-proc-derive/README.md b/crates/one-d-proc-derive/README.md new file mode 100644 index 0000000..ef378dd --- /dev/null +++ b/crates/one-d-proc-derive/README.md @@ -0,0 +1,2 @@ +# rxing-one-d-proc-derive +one dimensional barcode macros for rxing diff --git a/crates/one-d-proc-derive/src/lib.rs b/crates/one-d-proc-derive/src/lib.rs new file mode 100644 index 0000000..3cdfb88 --- /dev/null +++ b/crates/one-d-proc-derive/src/lib.rs @@ -0,0 +1,181 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn; + +#[proc_macro_derive(OneDReader)] +pub fn one_d_reader_derive(input: TokenStream) -> TokenStream { + // Construct a representation of Rust code as a syntax tree + // that we can manipulate + let ast = syn::parse(input).unwrap(); + + // Build the trait implementation + impl_one_d_reader_macro(&ast) +} + +fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + let gen = quote! { + use std::collections::HashMap; + use crate::result_point::ResultPoint; + use crate::DecodeHintType; + use crate::DecodingHintDictionary; + use crate::RXingResultMetadataType; + use crate::RXingResultMetadataValue; + use crate::RXingResultPoint; + use crate::Reader; + + impl Reader for #name { + fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result { + self.decode_with_hints(image, &HashMap::new()) + } + + // Note that we don't try rotation without the try harder flag, even if rotation was supported. + fn decode_with_hints( + &mut self, + image: &mut crate::BinaryBitmap, + hints: &DecodingHintDictionary, + ) -> Result { + if let Ok(res) = self.doDecode(image, hints) { + Ok(res) + }else { + let tryHarder = hints.contains_key(&DecodeHintType::TRY_HARDER); + if tryHarder && image.isRotateSupported() { + let mut rotatedImage = image.rotateCounterClockwise(); + let mut result = self.doDecode(&mut rotatedImage, hints)?; + // Record that we found it rotated 90 degrees CCW / 270 degrees CW + let metadata = result.getRXingResultMetadata(); + let mut orientation = 270; + if metadata.contains_key(&RXingResultMetadataType::ORIENTATION) { + // But if we found it reversed in doDecode(), add in that result here: + orientation = (orientation + + if let Some(crate::RXingResultMetadataValue::Orientation(or)) = metadata.get(&RXingResultMetadataType::ORIENTATION) { + *or + }else { + 0 + }) % 360; + } + result.putMetadata(RXingResultMetadataType::ORIENTATION, RXingResultMetadataValue::Orientation(orientation)); + // Update result points + // let points = result.getRXingResultPoints(); + // if points != null { + let height = rotatedImage.getHeight(); + // for point in result.getRXingResultPointsMut().iter_mut() { + let total_points = result.getRXingResultPoints().len(); + let points = result.getRXingResultPointsMut(); + for i in 0..total_points{ + // for (int i = 0; i < points.length; i++) { + points[i] = RXingResultPoint::new(height as f32- points[i].getY() - 1.0, points[i].getX()); + } + // } + + Ok(result) + } else { + return Err(Exceptions::NotFoundException(None)) + } + } + } + } + }; + gen.into() +} + +#[proc_macro_derive(EANReader)] +pub fn ean_reader_derive(input: TokenStream) -> TokenStream { + // Construct a representation of Rust code as a syntax tree + // that we can manipulate + let ast = syn::parse(input).unwrap(); + + // Build the trait implementation + impl_ean_reader_macro(&ast) +} + +fn impl_ean_reader_macro(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + let gen = quote! { + impl super::OneDReader for #name { + fn decodeRow( + &mut self, + rowNumber: u32, + row: &crate::common::BitArray, + hints: &crate::DecodingHintDictionary, + ) -> Result { + self.decodeRowWithGuardRange(rowNumber, row, &self.findStartGuardPattern(row)?, hints) + } + } + }; + gen.into() +} + +#[proc_macro_derive(OneDWriter)] +pub fn one_d_writer_derive(input: TokenStream) -> TokenStream { + // Construct a representation of Rust code as a syntax tree + // that we can manipulate + let ast = syn::parse(input).unwrap(); + + // Build the trait implementation + impl_one_d_writer_macro(&ast) +} + +fn impl_one_d_writer_macro(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + let gen = quote! { + use crate::{ + EncodeHintType, EncodeHintValue, Exceptions, Writer, + }; + use std::collections::HashMap; + impl Writer for #name { + fn encode( + &self, + contents: &str, + format: &crate::BarcodeFormat, + width: i32, + height: i32, + ) -> Result { + self.encode_with_hints(contents, format, width, height, &HashMap::new()) + } + + fn encode_with_hints( + &self, + contents: &str, + format: &crate::BarcodeFormat, + width: i32, + height: i32, + hints: &crate::EncodingHintDictionary, + ) -> Result { + if contents.is_empty() { + return Err(Exceptions::IllegalArgumentException( + Some("Found empty contents".to_owned()), + )); + } + + if width < 0 || height < 0 { + return Err(Exceptions::IllegalArgumentException(Some(format!( + "Negative size is not allowed. Input: {}x{}", + width, height + )))); + } + if let Some(supportedFormats) = self.getSupportedWriteFormats() { + if !supportedFormats.contains(format) { + return Err(Exceptions::IllegalArgumentException(Some(format!( + "Can only encode {:?}, but got {:?}", + supportedFormats, format + )))); + } + } + + let mut sidesMargin = self.getDefaultMargin(); + if let Some(EncodeHintValue::Margin(margin)) = hints.get(&EncodeHintType::MARGIN) { + sidesMargin = margin.parse::().unwrap(); + } + // if hints.contains_key(&EncodeHintType::MARGIN) { + // sidesMargin = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString()); + // } + + let code = self.encode_oned_with_hints(contents, hints)?; + + Self::renderRXingResult(&code, width, height, sidesMargin) + } + } + }; + gen.into() +} \ No newline at end of file From edc8e6768534f5f5fa1541ebc93b76b6db908bdf Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Wed, 1 Mar 2023 08:46:49 -0600 Subject: [PATCH 3/6] move cli utility into repository This commit also adds the `--workspace`` flag to the automated build and test scripts --- .github/workflows/rust.yml | 6 +- Cargo.toml | 3 +- crates/cli/.gitignore | 25 ++ crates/cli/Cargo.toml | 14 + crates/cli/LICENSE | 201 ++++++++++++ crates/cli/README.md | 19 ++ crates/cli/src/main.rs | 656 +++++++++++++++++++++++++++++++++++++ 7 files changed, 920 insertions(+), 4 deletions(-) create mode 100644 crates/cli/.gitignore create mode 100644 crates/cli/Cargo.toml create mode 100644 crates/cli/LICENSE create mode 100644 crates/cli/README.md create mode 100644 crates/cli/src/main.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 110bef0..b0a1756 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -17,8 +17,8 @@ jobs: steps: - uses: actions/checkout@v3 - name: Check - run: cargo check --release --verbose + run: cargo check --workspace --release --verbose - name: Build - run: cargo build --release --verbose + run: cargo build --workspace --release --verbose - name: Run tests - run: cargo test --release --verbose + run: cargo test --workspace --release --verbose diff --git a/Cargo.toml b/Cargo.toml index f79f94c..772c3d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,5 +65,6 @@ otsu_level = ["image"] [workspace] members = [ - "crates/one-d-proc-derive" + "crates/one-d-proc-derive", + "crates/cli" ] \ No newline at end of file diff --git a/crates/cli/.gitignore b/crates/cli/.gitignore new file mode 100644 index 0000000..ba1de84 --- /dev/null +++ b/crates/cli/.gitignore @@ -0,0 +1,25 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + + +# Added by cargo + +/target + +*.jpg +*.jpeg +*.png +*.tif +*.svg +*.webp +*.tiff +.DS_Store +/.vscode \ No newline at end of file diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml new file mode 100644 index 0000000..8cd3487 --- /dev/null +++ b/crates/cli/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rxing-cli" +version = "0.1.11" +edition = "2021" +description = "A command line interface for rxing supporting encoding and decoding of multiple barcode formats" +license="Apache-2.0" +repository="https://github.com/rxing-core/rxing/tree/main/crates/cli" +keywords = ["barcode", "2d_barcode", "1d_barcode", "barcode_reader", "barcode_writer"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.1.1", features = ["derive"] } +rxing = {path = "../../", version = "~0.3.1", features = ["image", "svg_read", "svg_write"] } diff --git a/crates/cli/LICENSE b/crates/cli/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/crates/cli/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/crates/cli/README.md b/crates/cli/README.md new file mode 100644 index 0000000..2b2a970 --- /dev/null +++ b/crates/cli/README.md @@ -0,0 +1,19 @@ +# rxing-cli +A command line interface for rxing supporting encoding and decoding of barcode data. + +## Full documentation +`rxing-cli help` +`rxing-cli help encode` +`rxing-cli help decode` + +## Instalation +`cargo install rxing-cli` + +## Example Encode +`rxing-cli test_image.jpg encode --width 500 --height 500 --data "Sample Data and TEST Data" qrcode` + +## Example Decode +`rxing-cli test_image.jpg decode` + +## Example Multi Barcode Decode +`rxing-cli test_image.jpg decode --decode-multi` \ No newline at end of file diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs new file mode 100644 index 0000000..345d77d --- /dev/null +++ b/crates/cli/src/main.rs @@ -0,0 +1,656 @@ +use std::{ + collections::{HashMap, HashSet}, + path::PathBuf, +}; + +use clap::{ArgGroup, Parser, Subcommand}; +use rxing::{BarcodeFormat, MultiFormatWriter, Writer}; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Args { + file_name: String, + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + #[command(group( + ArgGroup::new("advanced_display_group") + .required(false) + .args(["detailed_results","parsed_results","raw_bytes"]), + ))] + Decode { + /// Try much harder to detect barcodes. + #[arg(short, long)] + try_harder: bool, + + /// Search for multiple barcodes in an image instead of just one, this can be much slower. + #[arg(short, long)] + decode_multi: bool, + + /// Can be specified multiple times with different barcode formats, only listed formats are searched for. + #[arg(short, long, value_enum)] + barcode_types: Option>, + + /// Print detailed results data + #[arg(long)] + detailed_results: bool, + + /// Print parsed results (exclusive with --detailed-results and --raw-bytes) + #[arg(long)] + parsed_results: bool, + + /// Print raw bytes (exclusive with --detailed-results and --raw-bytes) + #[arg(long)] + raw_bytes: bool, + + /// Unspecified, application-specific hint. + #[arg(long)] + other: Option, + + /// Image is a pure monochrome image of a barcode. + #[arg(long)] + pure_barcode: Option, + + /// Specifies what character encoding to use when decoding, where applicable. + #[arg(long)] + character_set: Option, + + /// Allowed lengths of encoded data -- reject anything else.. + #[arg(long)] + allowed_lengths: Option>, + + /// Assume Code 39 codes employ a check digit. + #[arg(long)] + assume_code_39_check_digit: Option, + + /// Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed. + /// For example this affects FNC1 handling for Code 128 (aka GS1-128). + #[arg(long, verbatim_doc_comment)] + assume_gs1: Option, + + /// If true, return the start and end digits in a Codabar barcode instead of stripping them. They + /// are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them + /// to not be. + #[arg(long, verbatim_doc_comment)] + return_codabar_start_end: Option, + + /// Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this. + /// Maps to an {@code int[]} of the allowed extension lengths, for example [2], [5], or [2, 5]. + /// If it is optional to have an extension, do not set this hint. If this is set, + /// and a UPC or EAN barcode is found but an extension is not, then no result will be returned + /// at all. + #[arg(long, verbatim_doc_comment)] + allowed_ean_extensions: Option>, + + /// If true, also tries to decode as inverted image. All configured decoders are simply called a + /// second time with an inverted image. + #[arg(long, verbatim_doc_comment)] + also_inverted: Option, + }, + #[command(group( + ArgGroup::new("code_set_rules") + .required(false) + .args(["code_128_compact", "force_code_set"]), + ))] + #[command(group( + ArgGroup::new("data_source") + .required(true) + .args(["data", "data_file"]), + ))] + #[command(group( + ArgGroup::new("data_matrix_encoding") + .required(false) + .args(["data_matrix_compact","force_c40"]), + ))] + Encode { + barcode_type: BarcodeFormat, + #[arg(long)] + width: u32, + #[arg(long)] + height: u32, + + /// String input for the encoder. + #[arg(short, long)] + data: Option, + + /// A file containing the text to be encoded. + #[arg(long)] + data_file: Option, + + /// Specifies what degree of error correction to use, for example in QR Codes. + /// Type depends on the encoder. For example for QR codes it's (L,M,Q,H). + /// For Aztec it is of type u32, representing the minimal percentage of error correction words. + /// For PDF417 it is of type u8, valid values being 0 to 8. + /// Note: an Aztec symbol should have a minimum of 25% EC words. + #[arg(long, verbatim_doc_comment)] + error_correction: Option, + + /// Specifies what character encoding to use where applicable. + #[arg(long)] + character_set: Option, + + /// Specifies whether to use compact mode for Data Matrix. + /// The compact encoding mode also supports the encoding of characters that are not in the ISO-8859-1 + /// character set via ECIs. + /// Please note that in that case, the most compact character encoding is chosen for characters in + /// the input that are not in the ISO-8859-1 character set. Based on experience, some scanners do not + /// support encodings like cp-1256 (Arabic). In such cases the encoding can be forced to UTF-8 by + /// means of the #CHARACTER_SET encoding hint. + /// Compact encoding also provides GS1-FNC1 support when #GS1_FORMAT is selected. In this case + /// group-separator character (ASCII 29 decimal) can be used to encode the positions of FNC1 codewords + /// for the purpose of delimiting AIs. + #[arg(long, verbatim_doc_comment)] + data_matrix_compact: Option, + + /// Specifies margin, in pixels, to use when generating the barcode. + /// The meaning can vary + /// by format; for example it controls margin before and after the barcode horizontally for + /// most 1D formats. + #[arg(long, verbatim_doc_comment)] + margin: Option, + + /** + Specifies whether to use compact mode for PDF417. + */ + #[arg(long)] + pdf_417_compact: Option, + + /** + Specifies what compaction mode to use for PDF417 + AUTO = 0, + TEXT = 1, + BYTE = 2, + NUMERIC = 3 + */ + #[arg(long)] + pdf_417_compaction: Option, + + /// Specifies whether to automatically insert ECIs when encoding PDF417. + /// Please note that in that case, the most compact character encoding is chosen for characters in + /// the input that are not in the ISO-8859-1 character set. Based on experience, some scanners do not + /// support encodings like cp-1256 (Arabic). In such cases the encoding can be forced to UTF-8 by + /// means of the #CHARACTER_SET encoding hint. + #[arg(long, verbatim_doc_comment)] + pdf_417_auto_eci: Option, + + /// Specifies the required number of layers for an Aztec code. + /// A negative number (-1, -2, -3, -4) specifies a compact Aztec code. + /// 0 indicates to use the minimum number of layers (the default). + /// A positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code. + #[arg(long, verbatim_doc_comment)] + aztec_layers: Option, + + /** + Specifies the exact version of QR code to be encoded. + */ + #[arg(long)] + qr_version: Option, + + /// Specifies the QR code mask pattern to be used. Allowed values are + /// 0..8. By default the code will automatically select + /// the optimal mask pattern. + #[arg(long, verbatim_doc_comment)] + qr_mask_pattern: Option, + + /// Specifies whether to use compact mode for QR code. + /// Please note that when compaction is performed, the most compact character encoding is chosen + /// for characters in the input that are not in the ISO-8859-1 character set. Based on experience, + /// some scanners do not support encodings like cp-1256 (Arabic). In such cases the encoding can + /// be forced to UTF-8 by means of the #CHARACTER_SET encoding hint. + #[arg(long, verbatim_doc_comment)] + qr_compact: Option, + + /** + Specifies whether the data should be encoded to the GS1 standard/ + */ + #[arg(long)] + gs1_format: Option, + + /// Forces which encoding will be used. Currently only used for Code-128 code sets. + /// Valid values are "A", "B", "C". + #[arg(long, verbatim_doc_comment)] + force_code_set: Option, + + /** + Forces C40 encoding for data-matrix. This + */ + #[arg(long)] + force_c40: Option, + + /** + Specifies whether to use compact mode for Code-128 code. + This can yield slightly smaller bar codes. + */ + #[arg(long)] + code_128_compact: Option, + }, +} + +fn main() { + let cli = Args::parse(); + match &cli.command { + Commands::Decode { + try_harder, + decode_multi, + barcode_types, + other, + pure_barcode, + character_set, + allowed_lengths, + assume_code_39_check_digit, + assume_gs1, + return_codabar_start_end, + allowed_ean_extensions, + also_inverted, + detailed_results, + parsed_results, + raw_bytes, + } => decode_command( + &cli.file_name, + try_harder, + decode_multi, + barcode_types, + other, + pure_barcode, + character_set, + allowed_lengths, + assume_code_39_check_digit, + assume_gs1, + return_codabar_start_end, + allowed_ean_extensions, + also_inverted, + detailed_results, + parsed_results, + raw_bytes, + ), + Commands::Encode { + barcode_type, + width, + height, + data, + data_file, + error_correction, + character_set, + data_matrix_compact, + margin, + pdf_417_compact, + pdf_417_compaction, + pdf_417_auto_eci, + aztec_layers, + qr_version, + qr_mask_pattern, + qr_compact, + gs1_format, + force_code_set, + force_c40, + code_128_compact, + } => encode_command( + &cli.file_name, + barcode_type, + width, + height, + data, + data_file, + error_correction, + character_set, + data_matrix_compact, + margin, + pdf_417_compact, + pdf_417_compaction, + pdf_417_auto_eci, + aztec_layers, + qr_version, + qr_mask_pattern, + qr_compact, + gs1_format, + force_code_set, + force_c40, + code_128_compact, + ), + } +} + +fn decode_command( + file_name: &str, + try_harder: &bool, + decode_multi: &bool, + barcode_types: &Option>, + other: &Option, + pure_barcode: &Option, + character_set: &Option, + allowed_lengths: &Option>, + assume_code_39_check_digit: &Option, + assume_gs1: &Option, + return_codabar_start_end: &Option, + allowed_ean_extensions: &Option>, + also_inverted: &Option, + detailed_result: &bool, + parsed_bytes: &bool, + raw_bytes: &bool, +) { + let mut hints: rxing::DecodingHintDictionary = HashMap::new(); + if let Some(other) = other { + hints.insert( + rxing::DecodeHintType::OTHER, + rxing::DecodeHintValue::Other(other.to_owned()), + ); + } + if let Some(pure_barcode) = pure_barcode { + hints.insert( + rxing::DecodeHintType::PURE_BARCODE, + rxing::DecodeHintValue::PureBarcode(*pure_barcode), + ); + } + if let Some(character_set) = character_set { + hints.insert( + rxing::DecodeHintType::CHARACTER_SET, + rxing::DecodeHintValue::CharacterSet(character_set.to_owned()), + ); + } + if let Some(allowed_lengths) = allowed_lengths { + hints.insert( + rxing::DecodeHintType::ALLOWED_LENGTHS, + rxing::DecodeHintValue::AllowedLengths(allowed_lengths.to_vec()), + ); + } + if let Some(assume_code_39_check_digit) = assume_code_39_check_digit { + hints.insert( + rxing::DecodeHintType::ASSUME_CODE_39_CHECK_DIGIT, + rxing::DecodeHintValue::AssumeCode39CheckDigit(*assume_code_39_check_digit), + ); + } + if let Some(assume_gs1) = assume_gs1 { + hints.insert( + rxing::DecodeHintType::ASSUME_GS1, + rxing::DecodeHintValue::AssumeGs1(*assume_gs1), + ); + } + if let Some(return_codabar_start_end) = return_codabar_start_end { + hints.insert( + rxing::DecodeHintType::RETURN_CODABAR_START_END, + rxing::DecodeHintValue::ReturnCodabarStartEnd(*return_codabar_start_end), + ); + } + if let Some(allowed_ean_extensions) = allowed_ean_extensions { + hints.insert( + rxing::DecodeHintType::ALLOWED_EAN_EXTENSIONS, + rxing::DecodeHintValue::AllowedEanExtensions(allowed_ean_extensions.to_vec()), + ); + } + if let Some(also_inverted) = also_inverted { + hints.insert( + rxing::DecodeHintType::ALSO_INVERTED, + rxing::DecodeHintValue::AlsoInverted(*also_inverted), + ); + } + + // println!( + // "Decode '{}' with: try_harder: {}, decode_multi: {}, barcode_types: {:?}", + // file_name, try_harder, decode_multi, barcode_types + // ); + + if !try_harder { + hints.insert( + rxing::DecodeHintType::TRY_HARDER, + rxing::DecodeHintValue::TryHarder(false), + ); + } + if let Some(barcode_type) = barcode_types { + hints.insert( + rxing::DecodeHintType::POSSIBLE_FORMATS, + rxing::DecodeHintValue::PossibleFormats(HashSet::from_iter( + barcode_type.iter().copied(), + )), + ); + } + + let path = PathBuf::from(file_name); + let extension = if let Some(ext) = path.extension() { + ext.to_string_lossy().to_string() + } else { + String::default() + }; + + if *decode_multi { + let results = if extension == "svg" { + rxing::helpers::detect_multiple_in_svg_with_hints(file_name, &mut hints) + } else { + rxing::helpers::detect_multiple_in_file_with_hints(file_name, &mut hints) + }; + match results { + Ok(result_array) => { + println!("Found {} results", result_array.len()); + for (i, result) in result_array.into_iter().enumerate() { + println!( + "Result {}:\n{}", + i, + print_result(&result, *detailed_result, *raw_bytes, *parsed_bytes) + ); + } + } + Err(search_err) => { + println!( + "Error while attempting to locate multiple barcodes in '{file_name}': {search_err}" + ); + } + } + } else { + let result = if extension == "svg" { + rxing::helpers::detect_in_svg_with_hints(file_name, None, &mut hints) + } else { + rxing::helpers::detect_in_file_with_hints(file_name, None, &mut hints) + }; + match result { + Ok(result) => { + println!( + "Detection result: \n{}", + print_result(&result, *detailed_result, *raw_bytes, *parsed_bytes) + ); + } + Err(search_err) => { + println!( + "Error while attempting to locate barcode in '{file_name}': {search_err}" + ); + } + } + } +} + +fn encode_command( + file_name: &str, + barcode_type: &BarcodeFormat, + width: &u32, + height: &u32, + data: &Option, + data_file: &Option, + error_correction: &Option, + character_set: &Option, + data_matrix_compact: &Option, + margin: &Option, + pdf_417_compact: &Option, + pdf_417_compaction: &Option, + pdf_417_auto_eci: &Option, + aztec_layers: &Option, + qr_version: &Option, + qr_mask_pattern: &Option, + qr_compact: &Option, + gs1_format: &Option, + force_code_set: &Option, + force_c40: &Option, + code_128_compact: &Option, +) { + // if data.is_none() && data_file.is_none() { + // println!("must provide either data string or data file"); + // return; + // } + // if data.is_some() && data_file.is_some() { + // println!("provide only data string or data file"); + // return; + // } + + let input_data = if let Some(path_from) = data_file { + if path_from.exists() { + let Ok(fl) = std::fs::File::open(path_from) else { + println!("file cannot be opened"); + return; + }; + std::io::read_to_string(fl).expect("file should read") + } else { + println!("{} does not exist", path_from.to_string_lossy()); + return; + } + } else if let Some(ds) = data { + ds.to_owned() + } else { + println!("Unknown error getting data"); + return; + }; + + let mut hints: rxing::EncodingHintDictionary = HashMap::new(); + + if let Some(ec) = error_correction { + hints.insert( + rxing::EncodeHintType::ERROR_CORRECTION, + rxing::EncodeHintValue::ErrorCorrection(ec.to_owned()), + ); + } + + if let Some(character_set) = character_set { + hints.insert( + rxing::EncodeHintType::CHARACTER_SET, + rxing::EncodeHintValue::CharacterSet(character_set.to_owned()), + ); + } + + if let Some(data_matrix_compact) = data_matrix_compact { + hints.insert( + rxing::EncodeHintType::DATA_MATRIX_COMPACT, + rxing::EncodeHintValue::DataMatrixCompact(*data_matrix_compact), + ); + } + + if let Some(margin) = margin { + hints.insert( + rxing::EncodeHintType::MARGIN, + rxing::EncodeHintValue::Margin(margin.to_owned()), + ); + } + + if let Some(pdf_417_compact) = pdf_417_compact { + hints.insert( + rxing::EncodeHintType::PDF417_COMPACT, + rxing::EncodeHintValue::Pdf417Compact(pdf_417_compact.to_string()), + ); + } + + if let Some(pdf_417_compaction) = pdf_417_compaction { + hints.insert( + rxing::EncodeHintType::PDF417_COMPACTION, + rxing::EncodeHintValue::Pdf417Compaction(pdf_417_compaction.to_owned()), + ); + } + + if let Some(pdf_417_auto_eci) = pdf_417_auto_eci { + hints.insert( + rxing::EncodeHintType::PDF417_AUTO_ECI, + rxing::EncodeHintValue::Pdf417AutoEci(pdf_417_auto_eci.to_string()), + ); + } + + if let Some(aztec_layers) = aztec_layers { + hints.insert( + rxing::EncodeHintType::AZTEC_LAYERS, + rxing::EncodeHintValue::AztecLayers(*aztec_layers), + ); + } + + if let Some(qr_version) = qr_version { + hints.insert( + rxing::EncodeHintType::QR_VERSION, + rxing::EncodeHintValue::QrVersion(qr_version.to_owned()), + ); + } + + if let Some(qr_mask_pattern) = qr_mask_pattern { + hints.insert( + rxing::EncodeHintType::QR_MASK_PATTERN, + rxing::EncodeHintValue::QrMaskPattern(qr_mask_pattern.to_owned()), + ); + } + + if let Some(qr_compact) = qr_compact { + println!("Warning, QRCompact can generate unreadable barcodes"); + hints.insert( + rxing::EncodeHintType::QR_COMPACT, + rxing::EncodeHintValue::QrCompact(qr_compact.to_string()), + ); + } + + if let Some(gs1_format) = gs1_format { + hints.insert( + rxing::EncodeHintType::GS1_FORMAT, + rxing::EncodeHintValue::Gs1Format(*gs1_format), + ); + } + + if let Some(force_code_set) = force_code_set { + hints.insert( + rxing::EncodeHintType::FORCE_CODE_SET, + rxing::EncodeHintValue::ForceCodeSet(force_code_set.to_owned()), + ); + } + + if let Some(force_c40) = force_c40 { + hints.insert( + rxing::EncodeHintType::FORCE_C40, + rxing::EncodeHintValue::ForceC40(*force_c40), + ); + } + + if let Some(code_128_compact) = code_128_compact { + hints.insert( + rxing::EncodeHintType::CODE128_COMPACT, + rxing::EncodeHintValue::Code128Compact(*code_128_compact), + ); + } + + // println!("Encode: file_name: {}, barcode_type: {}, width: {:?}, height: {:?}, data: '{:?}', data_file: {:?}", file_name, barcode_type, width, height, data, data_file); + + let writer = MultiFormatWriter::default(); + match writer.encode_with_hints( + &input_data, + barcode_type, + *width as i32, + *height as i32, + &hints, + ) { + Ok(result) => { + println!("Encode successful, saving..."); + match rxing::helpers::save_file(file_name, &result) { + Ok(_) => println!("Saved to '{file_name}'"), + Err(error) => println!("Could not save '{file_name}': {error}"), + } + } + Err(encode_error) => println!("Couldn't encode: {encode_error}"), + } +} + +fn print_result(result: &rxing::RXingResult, detailed: bool, raw: bool, parsed: bool) -> String { + let result_data = result.getText().escape_default().collect::(); + if detailed { + format!("[Barcode Format] {}\n[Metadata] {:?}\n[Points] {:?}\n[Number of Bits] {}\n[Timestamp] {}\n[Data] {}", result.getBarcodeFormat(),result.getRXingResultMetadata(), result.getRXingResultPoints(), result.getNumBits(), result.getTimestamp(), result_data) + } else if raw { + result + .getRawBytes() + .iter() + .fold(String::from(""), |acc, b| acc + " " + &b.to_string()) + } else if parsed { + let parsed_data = rxing::client::result::parseRXingResult(result); + parsed_data.to_string() + } else { + format!("({}) {}", result.getBarcodeFormat(), result_data) + } +} From 24e35f42266a401e04e14d319c226306756e1f5e Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Wed, 1 Mar 2023 09:23:14 -0600 Subject: [PATCH 4/6] update versions --- Cargo.toml | 8 ++++---- crates/cli/Cargo.toml | 4 ++-- crates/one-d-proc-derive/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 772c3d4..aad71f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rxing" -version = "0.3.1" +version = "0.3.2" description="A rust port of the zxing barcode library." license="Apache-2.0" repository="https://github.com/rxing-core/rxing" @@ -13,9 +13,9 @@ exclude = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -regex = "1.7.0" -fancy-regex = "0.10" -once_cell = "1.17.0" +regex = "1.7.1" +fancy-regex = "0.11" +once_cell = "1.17.1" encoding = "0.2" urlencoding = "2.1.2" uriparse = "0.6.4" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 8cd3487..c3a098f 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rxing-cli" -version = "0.1.11" +version = "0.1.12" edition = "2021" description = "A command line interface for rxing supporting encoding and decoding of multiple barcode formats" license="Apache-2.0" @@ -11,4 +11,4 @@ keywords = ["barcode", "2d_barcode", "1d_barcode", "barcode_reader", "barcode_wr [dependencies] clap = { version = "4.1.1", features = ["derive"] } -rxing = {path = "../../", version = "~0.3.1", features = ["image", "svg_read", "svg_write"] } +rxing = {path = "../../", version = "~0.3.2", features = ["image", "svg_read", "svg_write"] } diff --git a/crates/one-d-proc-derive/Cargo.toml b/crates/one-d-proc-derive/Cargo.toml index cb45247..ae28a96 100644 --- a/crates/one-d-proc-derive/Cargo.toml +++ b/crates/one-d-proc-derive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rxing-one-d-proc-derive" repository = "https://github.com/rxing-core/rxing/tree/main/crates/one-d-proc-derive" -version = "0.3.0" +version = "0.3.1" edition = "2021" description = "proc macros to simplify the development of one-d barcode symbologies in rxing (https://github.com/rxing-core/rxing)" license = "Apache-2.0" From 42efbb397dd96679565df9ee1d6847fbc5ee0de9 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Wed, 1 Mar 2023 10:47:31 -0600 Subject: [PATCH 5/6] move maxicode detector to Point --- crates/cli/src/main.rs | 4 +- crates/one-d-proc-derive/src/lib.rs | 174 ++++++++++++++-------------- src/maxicode/detector.rs | 133 ++++++++++----------- 3 files changed, 152 insertions(+), 159 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 345d77d..5c84145 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -451,9 +451,7 @@ fn decode_command( ); } Err(search_err) => { - println!( - "Error while attempting to locate barcode in '{file_name}': {search_err}" - ); + println!("Error while attempting to locate barcode in '{file_name}': {search_err}"); } } } diff --git a/crates/one-d-proc-derive/src/lib.rs b/crates/one-d-proc-derive/src/lib.rs index 3cdfb88..3d26ec2 100644 --- a/crates/one-d-proc-derive/src/lib.rs +++ b/crates/one-d-proc-derive/src/lib.rs @@ -28,7 +28,7 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream { fn decode(&mut self, image: &mut crate::BinaryBitmap) -> Result { self.decode_with_hints(image, &HashMap::new()) } - + // Note that we don't try rotation without the try harder flag, even if rotation was supported. fn decode_with_hints( &mut self, @@ -67,7 +67,7 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream { points[i] = RXingResultPoint::new(height as f32- points[i].getY() - 1.0, points[i].getX()); } // } - + Ok(result) } else { return Err(Exceptions::NotFoundException(None)) @@ -81,101 +81,101 @@ fn impl_one_d_reader_macro(ast: &syn::DeriveInput) -> TokenStream { #[proc_macro_derive(EANReader)] pub fn ean_reader_derive(input: TokenStream) -> TokenStream { - // Construct a representation of Rust code as a syntax tree - // that we can manipulate - let ast = syn::parse(input).unwrap(); + // Construct a representation of Rust code as a syntax tree + // that we can manipulate + let ast = syn::parse(input).unwrap(); - // Build the trait implementation - impl_ean_reader_macro(&ast) + // Build the trait implementation + impl_ean_reader_macro(&ast) } fn impl_ean_reader_macro(ast: &syn::DeriveInput) -> TokenStream { - let name = &ast.ident; - let gen = quote! { - impl super::OneDReader for #name { - fn decodeRow( - &mut self, - rowNumber: u32, - row: &crate::common::BitArray, - hints: &crate::DecodingHintDictionary, - ) -> Result { - self.decodeRowWithGuardRange(rowNumber, row, &self.findStartGuardPattern(row)?, hints) + let name = &ast.ident; + let gen = quote! { + impl super::OneDReader for #name { + fn decodeRow( + &mut self, + rowNumber: u32, + row: &crate::common::BitArray, + hints: &crate::DecodingHintDictionary, + ) -> Result { + self.decodeRowWithGuardRange(rowNumber, row, &self.findStartGuardPattern(row)?, hints) + } } - } - }; - gen.into() + }; + gen.into() } #[proc_macro_derive(OneDWriter)] pub fn one_d_writer_derive(input: TokenStream) -> TokenStream { - // Construct a representation of Rust code as a syntax tree - // that we can manipulate - let ast = syn::parse(input).unwrap(); + // Construct a representation of Rust code as a syntax tree + // that we can manipulate + let ast = syn::parse(input).unwrap(); - // Build the trait implementation - impl_one_d_writer_macro(&ast) + // Build the trait implementation + impl_one_d_writer_macro(&ast) } fn impl_one_d_writer_macro(ast: &syn::DeriveInput) -> TokenStream { - let name = &ast.ident; - let gen = quote! { - use crate::{ - EncodeHintType, EncodeHintValue, Exceptions, Writer, - }; - use std::collections::HashMap; - impl Writer for #name { - fn encode( - &self, - contents: &str, - format: &crate::BarcodeFormat, - width: i32, - height: i32, - ) -> Result { - self.encode_with_hints(contents, format, width, height, &HashMap::new()) - } - - fn encode_with_hints( - &self, - contents: &str, - format: &crate::BarcodeFormat, - width: i32, - height: i32, - hints: &crate::EncodingHintDictionary, - ) -> Result { - if contents.is_empty() { - return Err(Exceptions::IllegalArgumentException( - Some("Found empty contents".to_owned()), - )); - } - - if width < 0 || height < 0 { - return Err(Exceptions::IllegalArgumentException(Some(format!( - "Negative size is not allowed. Input: {}x{}", - width, height - )))); - } - if let Some(supportedFormats) = self.getSupportedWriteFormats() { - if !supportedFormats.contains(format) { - return Err(Exceptions::IllegalArgumentException(Some(format!( - "Can only encode {:?}, but got {:?}", - supportedFormats, format - )))); - } - } - - let mut sidesMargin = self.getDefaultMargin(); - if let Some(EncodeHintValue::Margin(margin)) = hints.get(&EncodeHintType::MARGIN) { - sidesMargin = margin.parse::().unwrap(); - } - // if hints.contains_key(&EncodeHintType::MARGIN) { - // sidesMargin = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString()); - // } - - let code = self.encode_oned_with_hints(contents, hints)?; - - Self::renderRXingResult(&code, width, height, sidesMargin) - } - } - }; - gen.into() -} \ No newline at end of file + let name = &ast.ident; + let gen = quote! { + use crate::{ + EncodeHintType, EncodeHintValue, Exceptions, Writer, + }; + use std::collections::HashMap; + impl Writer for #name { + fn encode( + &self, + contents: &str, + format: &crate::BarcodeFormat, + width: i32, + height: i32, + ) -> Result { + self.encode_with_hints(contents, format, width, height, &HashMap::new()) + } + + fn encode_with_hints( + &self, + contents: &str, + format: &crate::BarcodeFormat, + width: i32, + height: i32, + hints: &crate::EncodingHintDictionary, + ) -> Result { + if contents.is_empty() { + return Err(Exceptions::IllegalArgumentException( + Some("Found empty contents".to_owned()), + )); + } + + if width < 0 || height < 0 { + return Err(Exceptions::IllegalArgumentException(Some(format!( + "Negative size is not allowed. Input: {}x{}", + width, height + )))); + } + if let Some(supportedFormats) = self.getSupportedWriteFormats() { + if !supportedFormats.contains(format) { + return Err(Exceptions::IllegalArgumentException(Some(format!( + "Can only encode {:?}, but got {:?}", + supportedFormats, format + )))); + } + } + + let mut sidesMargin = self.getDefaultMargin(); + if let Some(EncodeHintValue::Margin(margin)) = hints.get(&EncodeHintType::MARGIN) { + sidesMargin = margin.parse::().unwrap(); + } + // if hints.contains_key(&EncodeHintType::MARGIN) { + // sidesMargin = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString()); + // } + + let code = self.encode_oned_with_hints(contents, hints)?; + + Self::renderRXingResult(&code, width, height, sidesMargin) + } + } + }; + gen.into() +} diff --git a/src/maxicode/detector.rs b/src/maxicode/detector.rs index d0bfc0d..00aabed 100644 --- a/src/maxicode/detector.rs +++ b/src/maxicode/detector.rs @@ -134,8 +134,8 @@ impl Circle<'_> { let point_3 = self.find_width_at_degree(97.0).1[0]; let guessed_center_point = Self::find_center(point_1, point_2, point_3); self.center = ( - guessed_center_point.0.round() as u32, - guessed_center_point.1.round() as u32, + guessed_center_point.x.round() as u32, + guessed_center_point.y.round() as u32, ) } @@ -143,7 +143,7 @@ impl Circle<'_> { /// returns (ellipse, center, semi_major, semi_minor, linear_eccentricity) pub fn detect_ellipse(&self) -> (bool, (u32, u32), u32, u32, u32) { // find semi-major and semi-minor axi - let mut lengths = [(0, 0.0, [(0.0_f32, 0.0); 2]); 72]; + let mut lengths = [(0, 0.0, [Point::default(); 2]); 72]; let mut circle_points = Vec::new(); // for i_rotation in 0..72 { for (i_rotation, length_set) in lengths.iter_mut().enumerate() { @@ -193,7 +193,7 @@ impl Circle<'_> { let guessed_center_point = Self::find_center(point_1, point_2, point_3); ( false, - (guessed_center_point.0 as u32, guessed_center_point.1 as u32), + (guessed_center_point.x as u32, guessed_center_point.y as u32), self.radius, self.radius, 0, @@ -213,7 +213,7 @@ impl Circle<'_> { ); ( true, - (ellipse_center.0 as u32, ellipse_center.1 as u32), + (ellipse_center.x as u32, ellipse_center.y as u32), major_axis.0 / 2, minor_axis.0 / 2, linear_eccentricity, @@ -222,10 +222,10 @@ impl Circle<'_> { } } - fn find_center(p1: (f32, f32), p2: (f32, f32), p3: (f32, f32)) -> (f32, f32) { - let (x1, y1) = p1; - let (x2, y2) = p2; - let (x3, y3) = p3; + fn find_center(p1: Point, p2: Point, p3: Point) -> Point { + let Point { x: x1, y: y1 } = p1; + let Point { x: x2, y: y2 } = p2; + let Point { x: x3, y: y3 } = p3; let a = x1 * (y2 - y3) - y1 * (x2 - x3) + (x2 * y3 - x3 * y2); let bx = (x1 * x1 + y1 * y1) * (y3 - y2) @@ -238,22 +238,16 @@ impl Circle<'_> { let x = bx / (2.0 * a); let y = by / (2.0 * a); - (x.abs(), y.abs()) + (x.abs(), y.abs()).into() } - fn calculate_ellipse_center( - a: f32, - _b: f32, - p1: (f32, f32), - p2: (f32, f32), - p3: (f32, f32), - ) -> (f32, f32) { - let x1 = p1.0; - let y1 = p1.1; - let x2 = p2.0; - let y2 = p2.1; - let x3 = p3.0; - let y3 = p3.1; + fn calculate_ellipse_center(a: f32, _b: f32, p1: Point, p2: Point, p3: Point) -> Point { + let x1 = p1.x; + let y1 = p1.y; + let x2 = p2.x; + let y2 = p2.y; + let x3 = p3.x; + let y3 = p3.y; let ma = (x1 * x1 + y1 * y1 - a * a) / 2.0; let mb = (x2 * x2 + y2 * y2 - a * a) / 2.0; @@ -264,20 +258,20 @@ impl Circle<'_> { let x = (ma * y2 + mb * y3 + mc * y1) / determinant; let y = (x1 * mb + x2 * mc + x3 * ma) / determinant; - (x, y) + (x, y).into() } fn check_ellipse_point( center: (u32, u32), - point: &(f32, f32), + point: &Point, semi_major_axis: u32, semi_minor_axis: u32, ) -> f64 { - ((point.0 as f64 - center.0 as f64).powf(2.0) / (semi_major_axis as f64).powf(2.0)) - + ((point.1 as f64 - center.1 as f64).powf(2.0) / (semi_minor_axis as f64).powf(2.0)) + ((point.x as f64 - center.0 as f64).powf(2.0) / (semi_major_axis as f64).powf(2.0)) + + ((point.y as f64 - center.1 as f64).powf(2.0) / (semi_minor_axis as f64).powf(2.0)) } - fn find_width_at_degree(&self, rotation: f32) -> (u32, [(f32, f32); 2]) { + fn find_width_at_degree(&self, rotation: f32) -> (u32, [Point; 2]) { let mut x = self.center.0; let y = self.center.1; let mut length = 0; @@ -285,7 +279,7 @@ impl Circle<'_> { // count left while { let point = get_point(self.center, (x, y), rotation); - !self.image.get(point.0 as u32, point.1 as u32) && x > 0 + !self.image.get(point.x as u32, point.y as u32) && x > 0 } { x -= 1; length += 1; @@ -297,7 +291,7 @@ impl Circle<'_> { // count right while { let point = get_point(self.center, (x, y), rotation); - !self.image.get(point.0 as u32, point.1 as u32) + !self.image.get(point.x as u32, point.y as u32) } { x += 1; length += 1; @@ -344,7 +338,7 @@ pub fn detect(image: &BitMatrix, try_harder: bool) -> Result Result Result Result<([(f32, f32); 4], f32)> { +fn box_symbol(image: &BitMatrix, circle: &mut Circle) -> Result<([Point; 4], f32)> { let (left_boundary, right_boundary, top_boundary, bottom_boundary) = calculate_simple_boundary(circle, Some(image), None, false); @@ -743,10 +738,10 @@ fn box_symbol(image: &BitMatrix, circle: &mut Circle) -> Result<([(f32, f32); 4] Ok(( [ - (result_box[0].x, result_box[0].y), - (result_box[1].x, result_box[1].y), - (result_box[2].x, result_box[2].y), - (result_box[3].x, result_box[3].y), + (result_box[0].x, result_box[0].y).into(), + (result_box[1].x, result_box[1].y).into(), + (result_box[2].x, result_box[2].y).into(), + (result_box[3].x, result_box[3].y).into(), ], final_rotation, )) @@ -845,9 +840,9 @@ fn attempt_rotation_box( let p1_rot = get_point(circle.center, topl_p1, rotation); let p2_rot = get_point(circle.center, topl_p2, rotation); let p3_rot = get_point(circle.center, topl_p3, rotation); - let found_tl = image.try_get_area(p1_rot.0 as u32, p1_rot.1 as u32, 3)? - && image.try_get_area(p2_rot.0 as u32, p2_rot.1 as u32, 3)? - && image.try_get_area(p3_rot.0 as u32, p3_rot.1 as u32, 3)?; + let found_tl = image.try_get_area(p1_rot.x as u32, p1_rot.y as u32, 3)? + && image.try_get_area(p2_rot.x as u32, p2_rot.y as u32, 3)? + && image.try_get_area(p3_rot.x as u32, p3_rot.y as u32, 3)?; if !found_tl { continue; } @@ -858,9 +853,9 @@ fn attempt_rotation_box( let p1_rot = get_point(circle.center, topr_p1, rotation); let p2_rot = get_point(circle.center, topr_p2, rotation); let p3_rot = get_point(circle.center, topr_p3, rotation); - let found_tr = !image.try_get_area(p1_rot.0 as u32, p1_rot.1 as u32, 3)? - && !image.try_get_area(p2_rot.0 as u32, p2_rot.1 as u32, 3)? - && !image.try_get_area(p3_rot.0 as u32, p3_rot.1 as u32, 3)?; + let found_tr = !image.try_get_area(p1_rot.x as u32, p1_rot.y as u32, 3)? + && !image.try_get_area(p2_rot.x as u32, p2_rot.y as u32, 3)? + && !image.try_get_area(p3_rot.x as u32, p3_rot.y as u32, 3)?; if !found_tr { continue; } @@ -871,9 +866,9 @@ fn attempt_rotation_box( let p1_rot = get_point(circle.center, l_p1, rotation); let p2_rot = get_point(circle.center, l_p2, rotation); let p3_rot = get_point(circle.center, l_p3, rotation); - let found_l = image.try_get_area(p1_rot.0 as u32, p1_rot.1 as u32, 3)? - && !image.try_get_area(p2_rot.0 as u32, p2_rot.1 as u32, 3)? - && image.try_get_area(p3_rot.0 as u32, p3_rot.1 as u32, 3)?; + let found_l = image.try_get_area(p1_rot.x as u32, p1_rot.y as u32, 3)? + && !image.try_get_area(p2_rot.x as u32, p2_rot.y as u32, 3)? + && image.try_get_area(p3_rot.x as u32, p3_rot.y as u32, 3)?; if !found_l { continue; } @@ -884,9 +879,9 @@ fn attempt_rotation_box( let p1_rot = get_point(circle.center, r_p1, rotation); let p2_rot = get_point(circle.center, r_p2, rotation); let p3_rot = get_point(circle.center, r_p3, rotation); - let found_r = image.try_get_area(p1_rot.0 as u32, p1_rot.1 as u32, 3)? - && !image.try_get_area(p2_rot.0 as u32, p2_rot.1 as u32, 3)? - && image.try_get_area(p3_rot.0 as u32, p3_rot.1 as u32, 3)?; + let found_r = image.try_get_area(p1_rot.x as u32, p1_rot.y as u32, 3)? + && !image.try_get_area(p2_rot.x as u32, p2_rot.y as u32, 3)? + && image.try_get_area(p3_rot.x as u32, p3_rot.y as u32, 3)?; if !found_r { continue; } @@ -897,9 +892,9 @@ fn attempt_rotation_box( let p1_rot = get_point(circle.center, bottoml_p1, rotation); let p2_rot = get_point(circle.center, bottoml_p2, rotation); let p3_rot = get_point(circle.center, bottoml_p3, rotation); - let found_bl = image.try_get_area(p1_rot.0 as u32, p1_rot.1 as u32, 3)? - && !image.try_get_area(p2_rot.0 as u32, p2_rot.1 as u32, 3)? - && image.try_get_area(p3_rot.0 as u32, p3_rot.1 as u32, 3)?; + let found_bl = image.try_get_area(p1_rot.x as u32, p1_rot.y as u32, 3)? + && !image.try_get_area(p2_rot.x as u32, p2_rot.y as u32, 3)? + && image.try_get_area(p3_rot.x as u32, p3_rot.y as u32, 3)?; if !found_bl { continue; } @@ -910,9 +905,9 @@ fn attempt_rotation_box( let p1_rot = get_point(circle.center, bottomr_p1, rotation); let p2_rot = get_point(circle.center, bottomr_p2, rotation); let p3_rot = get_point(circle.center, bottomr_p3, rotation); - let found_br = image.try_get_area(p1_rot.0 as u32, p1_rot.1 as u32, 3)? - && !image.try_get_area(p2_rot.0 as u32, p2_rot.1 as u32, 3)? - && image.try_get_area(p3_rot.0 as u32, p3_rot.1 as u32, 3)?; + let found_br = image.try_get_area(p1_rot.x as u32, p1_rot.y as u32, 3)? + && !image.try_get_area(p2_rot.x as u32, p2_rot.y as u32, 3)? + && image.try_get_area(p3_rot.x as u32, p3_rot.y as u32, 3)?; if !found_br { continue; } @@ -952,10 +947,10 @@ fn attempt_rotation_box( Some(( [ - point(new_1.0, new_1.1), - point(new_2.0, new_2.1), - point(new_3.0, new_3.1), - point(new_4.0, new_4.1), + point(new_1.x, new_1.y), + point(new_2.x, new_2.y), + point(new_3.x, new_3.y), + point(new_4.x, new_4.y), ], final_rotation, )) @@ -977,7 +972,7 @@ fn get_adjusted_points( ) } -fn get_point(center: (u32, u32), original: (u32, u32), angle: f32) -> (f32, f32) { +fn get_point(center: (u32, u32), original: (u32, u32), angle: f32) -> Point { let radians = angle.to_radians(); let x = radians.cos() * (original.0 as f32 - center.0 as f32) - radians.sin() * (original.1 as f32 - center.1 as f32) @@ -986,7 +981,7 @@ fn get_point(center: (u32, u32), original: (u32, u32), angle: f32) -> (f32, f32) + radians.cos() * (original.1 as f32 - center.1 as f32) + center.1 as f32; - (x.abs(), y.abs()) + Point::new(x.abs(), y.abs()) } fn adjust_point_alternate(point: (u32, u32), circle: &Circle, center_scale: f64) -> (u32, u32) { From f450c6e0f7a30b07db4113b940e02e06951f51ac Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Wed, 1 Mar 2023 10:50:52 -0600 Subject: [PATCH 6/6] cargo clippy --fix --- src/aztec/decoder.rs | 2 +- src/datamatrix/decoder/decoded_bit_stream_parser.rs | 2 +- src/maxicode/detector.rs | 10 +++------- src/rxing_result.rs | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/aztec/decoder.rs b/src/aztec/decoder.rs index 0dc0be6..ca10c64 100644 --- a/src/aztec/decoder.rs +++ b/src/aztec/decoder.rs @@ -162,7 +162,7 @@ fn get_encoded_data(corrected_bits: &[bool]) -> Result { result.push_str( &encdr .decode(&decoded_bytes, encoding::DecoderTrap::Strict) - .map_err(|a| Exceptions::illegalStateWith(a))?, + .map_err(Exceptions::illegalStateWith)?, ); decoded_bytes.clear(); diff --git a/src/datamatrix/decoder/decoded_bit_stream_parser.rs b/src/datamatrix/decoder/decoded_bit_stream_parser.rs index 455e313..da7876c 100644 --- a/src/datamatrix/decoder/decoded_bit_stream_parser.rs +++ b/src/datamatrix/decoder/decoded_bit_stream_parser.rs @@ -732,7 +732,7 @@ fn decodeBase256Segment( result.append_string( &encoding::all::ISO_8859_1 .decode(&bytes, encoding::DecoderTrap::Strict) - .map_err(|e| Exceptions::parseWith(e))?, + .map_err(Exceptions::parseWith)?, ); byteSegments.push(bytes); diff --git a/src/maxicode/detector.rs b/src/maxicode/detector.rs index 00aabed..0ef8aeb 100644 --- a/src/maxicode/detector.rs +++ b/src/maxicode/detector.rs @@ -340,8 +340,8 @@ pub fn detect(image: &BitMatrix, try_harder: bool) -> Result Result &Vec { - &&self.resultPoints + &self.resultPoints } /** Currently necessary because the external OneDReader proc macro uses it. */