diff --git a/src/decode_hints.rs b/src/decode_hints.rs index 8c6dce0d..20b1597f 100644 --- a/src/decode_hints.rs +++ b/src/decode_hints.rs @@ -16,7 +16,7 @@ //package com.google.zxing; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use crate::{BarcodeFormat, PointCallback}; @@ -242,3 +242,232 @@ pub enum DecodeHintValue { */ TelepenAsNumeric(bool), } + +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Default, Clone)] +pub struct DecodeHints { + /** + * Unspecified, application-specific hint. Maps to an unspecified {@link Object}. + */ + pub Other: Option, + + /** + * Image is a pure monochrome image of a barcode. Doesn't matter what it maps to; + * use {@link Boolean#TRUE}. + */ + pub PureBarcode: Option, + + /** + * Image is known to be of one of a few possible formats. + * Maps to a {@link List} of {@link BarcodeFormat}s. + */ + pub PossibleFormats: Option>, + + /** + * Spend more time to try to find a barcode; optimize for accuracy, not speed. + * Doesn't matter what it maps to; use {@link Boolean#TRUE}. + */ + pub TryHarder: Option, + + /** + * Specifies what character encoding to use when decoding, where applicable (type String) + */ + pub CharacterSet: Option, + + /** + * Allowed lengths of encoded data -- reject anything else. Maps to an {@code int[]}. + */ + pub AllowedLengths: Option>, + + /** + * Assume Code 39 codes employ a check digit. Doesn't matter what it maps to; + * use {@link Boolean#TRUE}. + */ + pub AssumeCode39CheckDigit: 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). Doesn't matter what it maps to; + * use {@link Boolean#TRUE}. + */ + pub AssumeGs1: 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. Doesn't matter what it maps to; use {@link Boolean#TRUE}. + */ + pub ReturnCodabarStartEnd: Option, + + /** + * The caller needs to be notified via callback when a possible {@link Point} + * is found. Maps to a {@link PointCallback}. + */ + #[cfg_attr(feature = "serde", serde(skip_serializing, skip_deserializing))] + pub NeedResultPointCallback: 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. + */ + pub AllowedEanExtensions: Option>, + + /** + * If true, also tries to decode as inverted image. All configured decoders are simply called a + * second time with an inverted image. Doesn't matter what it maps to; use {@link Boolean#TRUE}. + */ + pub AlsoInverted: Option, + + /** + * Specifies that the codes are expected to be in conformance with the specification + * ISO/IEC 18004 regading the interpretation of character encoding. Values encoded in BYTE mode + * or in KANJI mode are interpreted as ISO-8859-1 characters unless an ECI specified at a prior + * location in the input specified a different encoding. By default the encoding of BYTE encoded + * values is determinied by the {@link #CHARACTER_SET} hint or otherwise by a heuristic that + * examines the bytes. By default KANJI encoded values are interpreted as the bytes of Shift-JIS + * encoded characters (note that this is the case even if an ECI specifies a different + * encoding). + */ + #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] + pub QrAssumeSpecConformInput: Option, + + /** + * Translate the ASCII values parsed by the Telepen reader into the Telepen Numeric form; use {@link Boolean#TRUE}. + */ + pub TelepenAsNumeric: Option, +} + +impl From for DecodeHints { + fn from(value: super::DecodingHintDictionary) -> Self { + let mut new_self: Self = Self::default(); + for (_, v) in value.into_iter() { + match v { + DecodeHintValue::Other(v) => new_self.Other = Some(v), + DecodeHintValue::PureBarcode(v) => new_self.PureBarcode = Some(v), + DecodeHintValue::PossibleFormats(v) => new_self.PossibleFormats = Some(v), + DecodeHintValue::TryHarder(v) => new_self.TryHarder = Some(v), + DecodeHintValue::CharacterSet(v) => new_self.CharacterSet = Some(v), + DecodeHintValue::AllowedLengths(v) => new_self.AllowedLengths = Some(v), + DecodeHintValue::AssumeCode39CheckDigit(v) => { + new_self.AssumeCode39CheckDigit = Some(v) + } + DecodeHintValue::AssumeGs1(v) => new_self.AssumeGs1 = Some(v), + DecodeHintValue::ReturnCodabarStartEnd(v) => { + new_self.ReturnCodabarStartEnd = Some(v) + } + DecodeHintValue::NeedResultPointCallback(v) => { + new_self.NeedResultPointCallback = Some(v) + } + DecodeHintValue::AllowedEanExtensions(v) => new_self.AllowedEanExtensions = Some(v), + DecodeHintValue::AlsoInverted(v) => new_self.AlsoInverted = Some(v), + DecodeHintValue::TelepenAsNumeric(v) => new_self.TelepenAsNumeric = Some(v), + #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] + DecodeHintValue::QrAssumeSpecConformInput(v) => { + new_self.QrAssumeSpecConformInput = Some(v) + } + } + } + new_self + } +} + +impl From for super::DecodingHintDictionary { + fn from(value: DecodeHints) -> Self { + let mut new_self = HashMap::default(); + + if let Some(v) = value.Other { + new_self.insert(DecodeHintType::OTHER, DecodeHintValue::Other(v)); + } + + if let Some(v) = value.PureBarcode { + new_self.insert( + DecodeHintType::PURE_BARCODE, + DecodeHintValue::PureBarcode(v), + ); + } + + if let Some(v) = value.PossibleFormats { + new_self.insert( + DecodeHintType::POSSIBLE_FORMATS, + DecodeHintValue::PossibleFormats(v), + ); + } + + if let Some(v) = value.TryHarder { + new_self.insert(DecodeHintType::TRY_HARDER, DecodeHintValue::TryHarder(v)); + } + + if let Some(v) = value.CharacterSet { + new_self.insert( + DecodeHintType::CHARACTER_SET, + DecodeHintValue::CharacterSet(v), + ); + } + + if let Some(v) = value.AllowedLengths { + new_self.insert( + DecodeHintType::ALLOWED_LENGTHS, + DecodeHintValue::AllowedLengths(v), + ); + } + + if let Some(v) = value.AssumeCode39CheckDigit { + new_self.insert( + DecodeHintType::ASSUME_CODE_39_CHECK_DIGIT, + DecodeHintValue::AssumeCode39CheckDigit(v), + ); + } + + if let Some(v) = value.AssumeGs1 { + new_self.insert(DecodeHintType::ASSUME_GS1, DecodeHintValue::AssumeGs1(v)); + } + + if let Some(v) = value.ReturnCodabarStartEnd { + new_self.insert( + DecodeHintType::RETURN_CODABAR_START_END, + DecodeHintValue::ReturnCodabarStartEnd(v), + ); + } + + if let Some(v) = value.NeedResultPointCallback { + new_self.insert( + DecodeHintType::NEED_RESULT_POINT_CALLBACK, + DecodeHintValue::NeedResultPointCallback(v), + ); + } + + if let Some(v) = value.AllowedEanExtensions { + new_self.insert( + DecodeHintType::ALLOWED_EAN_EXTENSIONS, + DecodeHintValue::AllowedEanExtensions(v), + ); + } + + if let Some(v) = value.AlsoInverted { + new_self.insert( + DecodeHintType::ALSO_INVERTED, + DecodeHintValue::AlsoInverted(v), + ); + } + + if let Some(v) = value.TelepenAsNumeric { + new_self.insert( + DecodeHintType::TELEPEN_AS_NUMERIC, + DecodeHintValue::TelepenAsNumeric(v), + ); + } + + #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] + if let Some(v) = value.QrAssumeSpecConformInput { + new_self.insert( + DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT, + DecodeHintValue::QrAssumeSpecConformInput(v), + ); + } + + new_self + } +} diff --git a/src/dimension.rs b/src/dimension.rs index 341ddab7..730fce0f 100644 --- a/src/dimension.rs +++ b/src/dimension.rs @@ -25,7 +25,7 @@ use serde::{Deserialize, Serialize}; * Simply encapsulates a width and height. */ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Eq, PartialEq, Hash, Copy, Clone)] +#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] pub struct Dimension(usize, usize); impl Dimension { diff --git a/src/encode_hints.rs b/src/encode_hints.rs index 07cf387d..abf9447b 100644 --- a/src/encode_hints.rs +++ b/src/encode_hints.rs @@ -344,3 +344,195 @@ pub enum EncodeHintValue { */ TelepenAsNumeric(bool), } + +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Default, Clone)] +pub struct EncodeHints { + /** + * 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 type + * {@link com.google.zxing.qrcode.decoder.ErrorCorrectionLevel ErrorCorrectionLevel}. + * For Aztec it is of type {@link Integer}, representing the minimal percentage of error correction words. + * For PDF417 it is of type {@link Integer}, valid values being 0 to 8. + * In all cases, it can also be a {@link String} representation of the desired value as well. + * Note: an Aztec symbol should have a minimum of 25% EC words. + */ + pub ErrorCorrection: Option, + + /** + * Specifies what character encoding to use where applicable (type {@link String}) + */ + pub CharacterSet: Option, + + /** + * Specifies the matrix shape for Data Matrix (type {@link com.google.zxing.datamatrix.encoder.SymbolShapeHint}) + */ + pub DataMatrixShape: Option, + + /** + * Specifies whether to use compact mode for Data Matrix (type {@link Boolean}, or "true" or "false" + * {@link String } value). + * 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 {@link #CHARACTER_SET} encoding hint. + * Compact encoding also provides GS1-FNC1 support when {@link #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. + * This option and {@link #FORCE_C40} are mutually exclusive. + */ + pub DataMatrixCompact: Option, + + /** + * Specifies a minimum barcode size (type {@link Dimension}). Only applicable to Data Matrix now. + * + * @deprecated use width/height params in + * {@link com.google.zxing.datamatrix.DataMatrixWriter#encode(String, BarcodeFormat, int, int)} + */ + #[deprecated] + pub MinSize: Option, + + /** + * Specifies a maximum barcode size (type {@link Dimension}). Only applicable to Data Matrix now. + * + * @deprecated without replacement + */ + #[deprecated] + pub MaxSize: 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. (Type {@link Integer}, or {@link String} representation of the integer value). + */ + pub Margin: Option, + + /** + * Specifies whether to use compact mode for PDF417 (type {@link Boolean}, or "true" or "false" + * {@link String} value). + */ + pub Pdf417Compact: Option, + + /** + * Specifies what compaction mode to use for PDF417 (type + * {@link com.google.zxing.pdf417.encoder.Compaction Compaction} or {@link String} value of one of its + * enum values). + */ + pub Pdf417Compaction: Option, + + /** + * Specifies the minimum and maximum number of rows and columns for PDF417 (type + * {@link com.google.zxing.pdf417.encoder.Dimensions Dimensions}). + */ + pub Pdf417Dimensions: Option, + + /** + * Specifies whether to automatically insert ECIs when encoding PDF417 (type {@link Boolean}, or "true" or "false" + * {@link String} value). + * 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 {@link #CHARACTER_SET} encoding hint. + */ + pub Pdf417AutoEci: 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. + * (Type {@link Integer}, or {@link String} representation of the integer value). + */ + pub AztecLayers: Option, + + /** + * Specifies the exact version of QR code to be encoded. + * (Type {@link Integer}, or {@link String} representation of the integer value). + */ + pub QrVersion: Option, + + /** + * Specifies the QR code mask pattern to be used. Allowed values are + * 0..QRCode.NUM_MASK_PATTERNS-1. By default the code will automatically select + * the optimal mask pattern. + * * (Type {@link Integer}, or {@link String} representation of the integer value). + */ + pub QrMaskPattern: Option, + + /** + * Specifies whether to use compact mode for QR code (type {@link Boolean}, or "true" or "false" + * {@link String } value). + * 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 {@link #CHARACTER_SET} encoding hint. + */ + pub QrCompact: Option, + + /** + * Specifies whether the data should be encoded to the GS1 standard (type {@link Boolean}, or "true" or "false" + * {@link String } value). + */ + pub Gs1Format: Option, + + /** + * Forces which encoding will be used. Currently only used for Code-128 code sets (Type {@link String}). + * Valid values are "A", "B", "C". + * This option and {@link #CODE128_COMPACT} are mutually exclusive. + */ + pub ForceCodeSet: Option, + + /** + * Forces C40 encoding for data-matrix (type {@link Boolean}, or "true" or "false") {@link String } value). This + * option and {@link #DATA_MATRIX_COMPACT} are mutually exclusive. + */ + pub ForceC40: Option, + + /** + * Specifies whether to use compact mode for Code-128 code (type {@link Boolean}, or "true" or "false" + * {@link String } value). + * This can yield slightly smaller bar codes. This option and {@link #FORCE_CODE_SET} are mutually + * exclusive. + */ + pub Code128Compact: Option, + + /** + * Translate the numeric values received by the Telepen reader into the Telepen Alphaumeric form; use {@link Boolean#TRUE}. + */ + pub TelepenAsNumeric: Option, +} + +impl From for EncodeHints { + fn from(value: super::EncodingHintDictionary) -> Self { + let mut new_self = Self::default(); + + for (_, v) in value.into_iter() { + match v { + EncodeHintValue::ErrorCorrection(v) => new_self.ErrorCorrection = Some(v), + EncodeHintValue::CharacterSet(v) => new_self.CharacterSet = Some(v), + EncodeHintValue::DataMatrixShape(v) => new_self.DataMatrixShape = Some(v), + EncodeHintValue::DataMatrixCompact(v) => new_self.DataMatrixCompact = Some(v), + EncodeHintValue::MinSize(v) => new_self.MinSize = Some(v), + EncodeHintValue::MaxSize(v) => new_self.MaxSize = Some(v), + EncodeHintValue::Margin(v) => new_self.Margin = Some(v), + EncodeHintValue::Pdf417Compact(v) => new_self.Pdf417Compact = Some(v), + EncodeHintValue::Pdf417Compaction(v) => new_self.Pdf417Compaction = Some(v), + EncodeHintValue::Pdf417Dimensions(v) => new_self.Pdf417Dimensions = Some(v), + EncodeHintValue::Pdf417AutoEci(v) => new_self.Pdf417AutoEci = Some(v), + EncodeHintValue::AztecLayers(v) => new_self.AztecLayers = Some(v), + EncodeHintValue::QrVersion(v) => new_self.QrVersion = Some(v), + EncodeHintValue::QrMaskPattern(v) => new_self.QrMaskPattern = Some(v), + EncodeHintValue::QrCompact(v) => new_self.QrCompact = Some(v), + EncodeHintValue::Gs1Format(v) => new_self.Gs1Format = Some(v), + EncodeHintValue::ForceCodeSet(v) => new_self.ForceCodeSet = Some(v), + EncodeHintValue::ForceC40(v) => new_self.ForceC40 = Some(v), + EncodeHintValue::Code128Compact(v) => new_self.Code128Compact = Some(v), + EncodeHintValue::TelepenAsNumeric(v) => new_self.TelepenAsNumeric = Some(v), + } + } + + new_self + } +} diff --git a/src/filtered_image_reader.rs b/src/filtered_image_reader.rs index 264b4fb6..05039e29 100644 --- a/src/filtered_image_reader.rs +++ b/src/filtered_image_reader.rs @@ -1,10 +1,7 @@ use std::collections::HashMap; use crate::common::{BitMatrix, HybridBinarizer, Result}; -use crate::{ - Binarizer, BinaryBitmap, Exceptions, Luma8LuminanceSource, LuminanceSource, - Reader, -}; +use crate::{Binarizer, BinaryBitmap, Exceptions, Luma8LuminanceSource, LuminanceSource, Reader}; pub const DEFAULT_DOWNSCALE_THRESHHOLD: usize = 500; pub const DEFAULT_DOWNSCALE_FACTOR: usize = 3; diff --git a/src/multi_format_reader.rs b/src/multi_format_reader.rs index a58f5e54..cdb746df 100644 --- a/src/multi_format_reader.rs +++ b/src/multi_format_reader.rs @@ -20,13 +20,13 @@ use crate::common::Result; #[cfg(feature = "experimental_features")] use crate::oned::cpp::ODReader; use crate::qrcode::cpp_port::QrReader; +use crate::ONE_D_FORMATS; use crate::{ aztec::AztecReader, datamatrix::DataMatrixReader, maxicode::MaxiCodeReader, oned::MultiFormatOneDReader, pdf417::PDF417Reader, qrcode::QRCodeReader, BarcodeFormat, Binarizer, BinaryBitmap, DecodeHintType, DecodeHintValue, DecodingHintDictionary, Exceptions, RXingResult, Reader, }; -use crate::ONE_D_FORMATS; /** * MultiFormatReader is a convenience class and the main entry point into the library for most uses. diff --git a/src/pdf417/encoder/dimensions.rs b/src/pdf417/encoder/dimensions.rs index 354be7ac..58bd60d0 100644 --- a/src/pdf417/encoder/dimensions.rs +++ b/src/pdf417/encoder/dimensions.rs @@ -23,7 +23,7 @@ use serde::{Deserialize, Serialize}; * @author qwandor@google.com (Andrew Walbran) */ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct Dimensions { minCols: usize, maxCols: usize,