mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-27 21:02:35 +00:00
format datamatrix
This commit is contained in:
@@ -2,13 +2,19 @@ pub mod decoder;
|
|||||||
pub mod detector;
|
pub mod detector;
|
||||||
pub mod encoder;
|
pub mod encoder;
|
||||||
|
|
||||||
use crate::{BarcodeFormat,BinaryBitmap,DecodeHintType,ChecksumException,FormatException,NotFoundException,Reader,RXingResult,ResultMetadataType,ResultPoint,EncodeHintType,Writer,Dimension};
|
use crate::common::{BitMatrix, DecoderResult, DetectorResult};
|
||||||
use crate::common::{DecoderResult,BitMatrix,DetectorResult,};
|
use crate::datamatrix::decoder::Decoder;
|
||||||
use crate::datamatrix::decoder::{Decoder};
|
use crate::datamatrix::detector::Detector;
|
||||||
use crate::datamatrix::detector::{Detector};
|
use crate::datamatrix::encoder::{
|
||||||
use crate::datamatrix::encoder::{DefaultPlacement,ErrorCorrection,HighLevelEncoder,MinimalEncoder,SymbolInfo,SymbolShapeHint};
|
DefaultPlacement, ErrorCorrection, HighLevelEncoder, MinimalEncoder, SymbolInfo,
|
||||||
|
SymbolShapeHint,
|
||||||
|
};
|
||||||
use crate::qrcode::encoder::ByteMatrix;
|
use crate::qrcode::encoder::ByteMatrix;
|
||||||
|
use crate::{
|
||||||
|
BarcodeFormat, BinaryBitmap, ChecksumException, DecodeHintType, Dimension, EncodeHintType,
|
||||||
|
FormatException, NotFoundException, RXingResult, Reader, ResultMetadataType, ResultPoint,
|
||||||
|
Writer,
|
||||||
|
};
|
||||||
|
|
||||||
// DataMatrixReader.java
|
// DataMatrixReader.java
|
||||||
/**
|
/**
|
||||||
@@ -19,94 +25,104 @@ use crate::qrcode::encoder::ByteMatrix;
|
|||||||
|
|
||||||
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
|
const NO_POINTS: [Option<ResultPoint>; 0] = [None; 0];
|
||||||
pub struct DataMatrixReader {
|
pub struct DataMatrixReader {
|
||||||
|
decoder: Decoder,
|
||||||
decoder: Decoder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reader for DataMatrixReader{
|
impl Reader for DataMatrixReader {
|
||||||
/**
|
/**
|
||||||
* Locates and decodes a Data Matrix code in an image.
|
* Locates and decodes a Data Matrix code in an image.
|
||||||
*
|
*
|
||||||
* @return a String representing the content encoded by the Data Matrix code
|
* @return a String representing the content encoded by the Data Matrix code
|
||||||
* @throws NotFoundException if a Data Matrix code cannot be found
|
* @throws NotFoundException if a Data Matrix code cannot be found
|
||||||
* @throws FormatException if a Data Matrix code cannot be decoded
|
* @throws FormatException if a Data Matrix code cannot be decoded
|
||||||
* @throws ChecksumException if error correction fails
|
* @throws ChecksumException if error correction fails
|
||||||
*/
|
*/
|
||||||
fn decode(&self, image: &BinaryBitmap, hints: &Map<DecodeHintType, _>) -> Result<Result, NotFoundException, ChecksumException, FormatException> {
|
fn decode(
|
||||||
let decoder_result: DecoderResult;
|
&self,
|
||||||
let mut points: Vec<ResultPoint>;
|
image: &BinaryBitmap,
|
||||||
if hints != null && hints.contains_key(DecodeHintType::PURE_BARCODE) {
|
hints: &Map<DecodeHintType, _>,
|
||||||
let bits: BitMatrix = ::extract_pure_bits(&image.get_black_matrix());
|
) -> Result<Result, NotFoundException, ChecksumException, FormatException> {
|
||||||
decoder_result = self.decoder.decode(bits);
|
let decoder_result: DecoderResult;
|
||||||
points = NO_POINTS;
|
let mut points: Vec<ResultPoint>;
|
||||||
} else {
|
if hints != null && hints.contains_key(DecodeHintType::PURE_BARCODE) {
|
||||||
let detector_result: DetectorResult = Detector::new(&image.get_black_matrix()).detect();
|
let bits: BitMatrix = ::extract_pure_bits(&image.get_black_matrix());
|
||||||
decoder_result = self.decoder.decode(&detector_result.get_bits());
|
decoder_result = self.decoder.decode(bits);
|
||||||
points = detector_result.get_points();
|
points = NO_POINTS;
|
||||||
|
} else {
|
||||||
|
let detector_result: DetectorResult = Detector::new(&image.get_black_matrix()).detect();
|
||||||
|
decoder_result = self.decoder.decode(&detector_result.get_bits());
|
||||||
|
points = detector_result.get_points();
|
||||||
|
}
|
||||||
|
let result: Result = Result::new(
|
||||||
|
&decoder_result.get_text(),
|
||||||
|
&decoder_result.get_raw_bytes(),
|
||||||
|
points,
|
||||||
|
BarcodeFormat::DATA_MATRIX,
|
||||||
|
);
|
||||||
|
let byte_segments: List<Vec<i8>> = decoder_result.get_byte_segments();
|
||||||
|
if byte_segments != null {
|
||||||
|
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
|
||||||
|
}
|
||||||
|
let ec_level: String = decoder_result.get_e_c_level();
|
||||||
|
if ec_level != null {
|
||||||
|
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
|
||||||
|
}
|
||||||
|
result.put_metadata(
|
||||||
|
ResultMetadataType::SYMBOLOGY_IDENTIFIER,
|
||||||
|
format!("]d{}", decoder_result.get_symbology_modifier()),
|
||||||
|
);
|
||||||
|
return Ok(result);
|
||||||
}
|
}
|
||||||
let result: Result = Result::new(&decoder_result.get_text(), &decoder_result.get_raw_bytes(), points, BarcodeFormat::DATA_MATRIX);
|
|
||||||
let byte_segments: List<Vec<i8>> = decoder_result.get_byte_segments();
|
|
||||||
if byte_segments != null {
|
|
||||||
result.put_metadata(ResultMetadataType::BYTE_SEGMENTS, &byte_segments);
|
|
||||||
}
|
|
||||||
let ec_level: String = decoder_result.get_e_c_level();
|
|
||||||
if ec_level != null {
|
|
||||||
result.put_metadata(ResultMetadataType::ERROR_CORRECTION_LEVEL, &ec_level);
|
|
||||||
}
|
|
||||||
result.put_metadata(ResultMetadataType::SYMBOLOGY_IDENTIFIER, format!("]d{}", decoder_result.get_symbology_modifier()));
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&self) {
|
fn reset(&self) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataMatrixReader {
|
impl DataMatrixReader {
|
||||||
|
pub fn new() -> Self {
|
||||||
pub fn new() -> Self {
|
Self {
|
||||||
Self{
|
decoder: Decoder::new(),
|
||||||
decoder: Decoder::new(),
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method detects a code in a "pure" image -- that is, pure monochrome image
|
* This method detects a code in a "pure" image -- that is, pure monochrome image
|
||||||
* which contains only an unrotated, unskewed, image of a code, with some white border
|
* which contains only an unrotated, unskewed, image of a code, with some white border
|
||||||
* around it. This is a specialized method that works exceptionally fast in this special
|
* around it. This is a specialized method that works exceptionally fast in this special
|
||||||
* case.
|
* case.
|
||||||
*/
|
*/
|
||||||
fn extract_pure_bits( image: &BitMatrix) -> Result<BitMatrix, NotFoundException> {
|
fn extract_pure_bits(image: &BitMatrix) -> Result<BitMatrix, NotFoundException> {
|
||||||
let left_top_black: Vec<i32> = image.get_top_left_on_bit();
|
let left_top_black: Vec<i32> = image.get_top_left_on_bit();
|
||||||
let right_bottom_black: Vec<i32> = image.get_bottom_right_on_bit();
|
let right_bottom_black: Vec<i32> = image.get_bottom_right_on_bit();
|
||||||
if left_top_black == null || right_bottom_black == null {
|
if left_top_black == null || right_bottom_black == null {
|
||||||
return Err( NotFoundException::get_not_found_instance());
|
return Err(NotFoundException::get_not_found_instance());
|
||||||
}
|
}
|
||||||
let module_size: i32 = self.module_size(&left_top_black, image);
|
let module_size: i32 = self.module_size(&left_top_black, image);
|
||||||
let mut top: i32 = left_top_black[1];
|
let mut top: i32 = left_top_black[1];
|
||||||
let bottom: i32 = right_bottom_black[1];
|
let bottom: i32 = right_bottom_black[1];
|
||||||
let mut left: i32 = left_top_black[0];
|
let mut left: i32 = left_top_black[0];
|
||||||
let right: i32 = right_bottom_black[0];
|
let right: i32 = right_bottom_black[0];
|
||||||
let matrix_width: i32 = (right - left + 1) / module_size;
|
let matrix_width: i32 = (right - left + 1) / module_size;
|
||||||
let matrix_height: i32 = (bottom - top + 1) / module_size;
|
let matrix_height: i32 = (bottom - top + 1) / module_size;
|
||||||
if matrix_width <= 0 || matrix_height <= 0 {
|
if matrix_width <= 0 || matrix_height <= 0 {
|
||||||
return Err( NotFoundException::get_not_found_instance());
|
return Err(NotFoundException::get_not_found_instance());
|
||||||
}
|
}
|
||||||
// Push in the "border" by half the module width so that we start
|
// Push in the "border" by half the module width so that we start
|
||||||
// sampling in the middle of the module. Just in case the image is a
|
// sampling in the middle of the module. Just in case the image is a
|
||||||
// little off, this will help recover.
|
// little off, this will help recover.
|
||||||
let nudge: i32 = module_size / 2;
|
let nudge: i32 = module_size / 2;
|
||||||
top += nudge;
|
top += nudge;
|
||||||
left += nudge;
|
left += nudge;
|
||||||
// Now just read off the bits
|
// Now just read off the bits
|
||||||
let bits: BitMatrix = BitMatrix::new(matrix_width, matrix_height);
|
let bits: BitMatrix = BitMatrix::new(matrix_width, matrix_height);
|
||||||
{
|
{
|
||||||
let mut y: i32 = 0;
|
let mut y: i32 = 0;
|
||||||
while y < matrix_height {
|
while y < matrix_height {
|
||||||
{
|
{
|
||||||
let i_offset: i32 = top + y * module_size;
|
let i_offset: i32 = top + y * module_size;
|
||||||
{
|
{
|
||||||
let mut x: i32 = 0;
|
let mut x: i32 = 0;
|
||||||
while x < matrix_width {
|
while x < matrix_width {
|
||||||
{
|
{
|
||||||
if image.get(left + x * module_size, i_offset) {
|
if image.get(left + x * module_size, i_offset) {
|
||||||
@@ -114,38 +130,34 @@ impl DataMatrixReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
y += 1;
|
y += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(bits);
|
return Ok(bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module_size( left_top_black: &Vec<i32>, image: &BitMatrix) -> Result<i32, NotFoundException> {
|
fn module_size(left_top_black: &Vec<i32>, image: &BitMatrix) -> Result<i32, NotFoundException> {
|
||||||
let width: i32 = image.get_width();
|
let width: i32 = image.get_width();
|
||||||
let mut x: i32 = left_top_black[0];
|
let mut x: i32 = left_top_black[0];
|
||||||
let y: i32 = left_top_black[1];
|
let y: i32 = left_top_black[1];
|
||||||
while x < width && image.get(x, y) {
|
while x < width && image.get(x, y) {
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
if x == width {
|
if x == width {
|
||||||
return Err( NotFoundException::get_not_found_instance());
|
return Err(NotFoundException::get_not_found_instance());
|
||||||
}
|
}
|
||||||
let module_size: i32 = x - left_top_black[0];
|
let module_size: i32 = x - left_top_black[0];
|
||||||
if module_size == 0 {
|
if module_size == 0 {
|
||||||
return Err( NotFoundException::get_not_found_instance());
|
return Err(NotFoundException::get_not_found_instance());
|
||||||
}
|
}
|
||||||
return Ok(module_size);
|
return Ok(module_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// DataMatrixWriter.java
|
// DataMatrixWriter.java
|
||||||
/**
|
/**
|
||||||
* This object renders a Data Matrix code as a BitMatrix 2D array of greyscale values.
|
* This object renders a Data Matrix code as a BitMatrix 2D array of greyscale values.
|
||||||
@@ -153,59 +165,92 @@ impl DataMatrixReader {
|
|||||||
* @author dswitkin@google.com (Daniel Switkin)
|
* @author dswitkin@google.com (Daniel Switkin)
|
||||||
* @author Guillaume Le Biller Added to zxing lib.
|
* @author Guillaume Le Biller Added to zxing lib.
|
||||||
*/
|
*/
|
||||||
pub struct DataMatrixWriter {
|
pub struct DataMatrixWriter {}
|
||||||
}
|
|
||||||
|
|
||||||
impl Writer for DataMatrixWriter{
|
impl Writer for DataMatrixWriter {
|
||||||
|
fn encode(
|
||||||
fn encode(&self, contents: &String, format: &BarcodeFormat, width: i32, height: i32, hints: &Map<EncodeHintType, _>) -> BitMatrix {
|
&self,
|
||||||
|
contents: &String,
|
||||||
|
format: &BarcodeFormat,
|
||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
hints: &Map<EncodeHintType, _>,
|
||||||
|
) -> BitMatrix {
|
||||||
if contents.is_empty() {
|
if contents.is_empty() {
|
||||||
return Err( IllegalArgumentException::new("Found empty contents"));
|
return Err(IllegalArgumentException::new("Found empty contents"));
|
||||||
}
|
}
|
||||||
if format != BarcodeFormat::DATA_MATRIX {
|
if format != BarcodeFormat::DATA_MATRIX {
|
||||||
return Err( IllegalArgumentException::new(format!("Can only encode DATA_MATRIX, but got {}", format)));
|
return Err(IllegalArgumentException::new(format!(
|
||||||
|
"Can only encode DATA_MATRIX, but got {}",
|
||||||
|
format
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
if width < 0 || height < 0 {
|
if width < 0 || height < 0 {
|
||||||
return Err( IllegalArgumentException::new(format!("Requested dimensions can't be negative: {}x{}", width, height)));
|
return Err(IllegalArgumentException::new(format!(
|
||||||
|
"Requested dimensions can't be negative: {}x{}",
|
||||||
|
width, height
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
// Try to get force shape & min / max size
|
// Try to get force shape & min / max size
|
||||||
let mut shape: SymbolShapeHint = SymbolShapeHint::FORCE_NONE;
|
let mut shape: SymbolShapeHint = SymbolShapeHint::FORCE_NONE;
|
||||||
let min_size: Dimension = null;
|
let min_size: Dimension = null;
|
||||||
let max_size: Dimension = null;
|
let max_size: Dimension = null;
|
||||||
if hints != null {
|
if hints != null {
|
||||||
let requested_shape: SymbolShapeHint = hints.get(EncodeHintType::DATA_MATRIX_SHAPE) as SymbolShapeHint;
|
let requested_shape: SymbolShapeHint =
|
||||||
|
hints.get(EncodeHintType::DATA_MATRIX_SHAPE) as SymbolShapeHint;
|
||||||
if requested_shape != null {
|
if requested_shape != null {
|
||||||
shape = requested_shape;
|
shape = requested_shape;
|
||||||
}
|
}
|
||||||
let requested_min_size: Dimension = hints.get(EncodeHintType::MIN_SIZE) as Dimension;
|
let requested_min_size: Dimension = hints.get(EncodeHintType::MIN_SIZE) as Dimension;
|
||||||
if requested_min_size != null {
|
if requested_min_size != null {
|
||||||
min_size = requested_min_size;
|
min_size = requested_min_size;
|
||||||
}
|
}
|
||||||
let requested_max_size: Dimension = hints.get(EncodeHintType::MAX_SIZE) as Dimension;
|
let requested_max_size: Dimension = hints.get(EncodeHintType::MAX_SIZE) as Dimension;
|
||||||
if requested_max_size != null {
|
if requested_max_size != null {
|
||||||
max_size = requested_max_size;
|
max_size = requested_max_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//1. step: Data encodation
|
//1. step: Data encodation
|
||||||
let mut encoded: String;
|
let mut encoded: String;
|
||||||
let has_compaction_hint: bool = hints != null && hints.contains_key(EncodeHintType::DATA_MATRIX_COMPACT) && Boolean::parse_boolean(&hints.get(EncodeHintType::DATA_MATRIX_COMPACT).to_string());
|
let has_compaction_hint: bool = hints != null
|
||||||
|
&& hints.contains_key(EncodeHintType::DATA_MATRIX_COMPACT)
|
||||||
|
&& Boolean::parse_boolean(&hints.get(EncodeHintType::DATA_MATRIX_COMPACT).to_string());
|
||||||
if has_compaction_hint {
|
if has_compaction_hint {
|
||||||
let has_g_s1_format_hint: bool = hints.contains_key(EncodeHintType::GS1_FORMAT) && Boolean::parse_boolean(&hints.get(EncodeHintType::GS1_FORMAT).to_string());
|
let has_g_s1_format_hint: bool = hints.contains_key(EncodeHintType::GS1_FORMAT)
|
||||||
let mut charset: Charset = null;
|
&& Boolean::parse_boolean(&hints.get(EncodeHintType::GS1_FORMAT).to_string());
|
||||||
let has_encoding_hint: bool = hints.contains_key(EncodeHintType::CHARACTER_SET);
|
let mut charset: Charset = null;
|
||||||
|
let has_encoding_hint: bool = hints.contains_key(EncodeHintType::CHARACTER_SET);
|
||||||
if has_encoding_hint {
|
if has_encoding_hint {
|
||||||
charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string());
|
charset = Charset::for_name(&hints.get(EncodeHintType::CHARACTER_SET).to_string());
|
||||||
}
|
}
|
||||||
encoded = MinimalEncoder::encode_high_level(&contents, &charset, if has_g_s1_format_hint { 0x1D } else { -1 }, &shape);
|
encoded = MinimalEncoder::encode_high_level(
|
||||||
|
&contents,
|
||||||
|
&charset,
|
||||||
|
if has_g_s1_format_hint { 0x1D } else { -1 },
|
||||||
|
&shape,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
let has_force_c40_hint: bool = hints != null && hints.contains_key(EncodeHintType::FORCE_C40) && Boolean::parse_boolean(&hints.get(EncodeHintType::FORCE_C40).to_string());
|
let has_force_c40_hint: bool = hints != null
|
||||||
encoded = HighLevelEncoder::encode_high_level(&contents, shape, min_size, max_size, has_force_c40_hint);
|
&& hints.contains_key(EncodeHintType::FORCE_C40)
|
||||||
|
&& Boolean::parse_boolean(&hints.get(EncodeHintType::FORCE_C40).to_string());
|
||||||
|
encoded = HighLevelEncoder::encode_high_level(
|
||||||
|
&contents,
|
||||||
|
shape,
|
||||||
|
min_size,
|
||||||
|
max_size,
|
||||||
|
has_force_c40_hint,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let symbol_info: SymbolInfo = SymbolInfo::lookup(&encoded.length(), shape, min_size, max_size, true);
|
let symbol_info: SymbolInfo =
|
||||||
|
SymbolInfo::lookup(&encoded.length(), shape, min_size, max_size, true);
|
||||||
//2. step: ECC generation
|
//2. step: ECC generation
|
||||||
let codewords: String = ErrorCorrection::encode_e_c_c200(&encoded, &symbol_info);
|
let codewords: String = ErrorCorrection::encode_e_c_c200(&encoded, &symbol_info);
|
||||||
//3. step: Module placement in Matrix
|
//3. step: Module placement in Matrix
|
||||||
let placement: DefaultPlacement = DefaultPlacement::new(&codewords, &symbol_info.get_symbol_data_width(), &symbol_info.get_symbol_data_height());
|
let placement: DefaultPlacement = DefaultPlacement::new(
|
||||||
|
&codewords,
|
||||||
|
&symbol_info.get_symbol_data_width(),
|
||||||
|
&symbol_info.get_symbol_data_height(),
|
||||||
|
);
|
||||||
placement.place();
|
placement.place();
|
||||||
//4. step: low-level encoding
|
//4. step: low-level encoding
|
||||||
return ::encode_low_level(placement, symbol_info, width, height);
|
return ::encode_low_level(placement, symbol_info, width, height);
|
||||||
@@ -213,44 +258,50 @@ impl Writer for DataMatrixWriter{
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DataMatrixWriter {
|
impl DataMatrixWriter {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode the given symbol info to a bit matrix.
|
* Encode the given symbol info to a bit matrix.
|
||||||
*
|
*
|
||||||
* @param placement The DataMatrix placement.
|
* @param placement The DataMatrix placement.
|
||||||
* @param symbolInfo The symbol info to encode.
|
* @param symbolInfo The symbol info to encode.
|
||||||
* @return The bit matrix generated.
|
* @return The bit matrix generated.
|
||||||
*/
|
*/
|
||||||
fn encode_low_level( placement: &DefaultPlacement, symbol_info: &SymbolInfo, width: i32, height: i32) -> BitMatrix {
|
fn encode_low_level(
|
||||||
let symbol_width: i32 = symbol_info.get_symbol_data_width();
|
placement: &DefaultPlacement,
|
||||||
let symbol_height: i32 = symbol_info.get_symbol_data_height();
|
symbol_info: &SymbolInfo,
|
||||||
let matrix: ByteMatrix = ByteMatrix::new(&symbol_info.get_symbol_width(), &symbol_info.get_symbol_height());
|
width: i32,
|
||||||
let matrix_y: i32 = 0;
|
height: i32,
|
||||||
{
|
) -> BitMatrix {
|
||||||
let mut y: i32 = 0;
|
let symbol_width: i32 = symbol_info.get_symbol_data_width();
|
||||||
|
let symbol_height: i32 = symbol_info.get_symbol_data_height();
|
||||||
|
let matrix: ByteMatrix = ByteMatrix::new(
|
||||||
|
&symbol_info.get_symbol_width(),
|
||||||
|
&symbol_info.get_symbol_height(),
|
||||||
|
);
|
||||||
|
let matrix_y: i32 = 0;
|
||||||
|
{
|
||||||
|
let mut y: i32 = 0;
|
||||||
while y < symbol_height {
|
while y < symbol_height {
|
||||||
{
|
{
|
||||||
// Fill the top edge with alternate 0 / 1
|
// Fill the top edge with alternate 0 / 1
|
||||||
let matrix_x: i32;
|
let matrix_x: i32;
|
||||||
if (y % symbol_info.matrixHeight) == 0 {
|
if (y % symbol_info.matrixHeight) == 0 {
|
||||||
matrix_x = 0;
|
matrix_x = 0;
|
||||||
{
|
{
|
||||||
let mut x: i32 = 0;
|
let mut x: i32 = 0;
|
||||||
while x < symbol_info.get_symbol_width() {
|
while x < symbol_info.get_symbol_width() {
|
||||||
{
|
{
|
||||||
matrix.set(matrix_x, matrix_y, (x % 2) == 0);
|
matrix.set(matrix_x, matrix_y, (x % 2) == 0);
|
||||||
matrix_x += 1;
|
matrix_x += 1;
|
||||||
}
|
}
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matrix_y += 1;
|
matrix_y += 1;
|
||||||
}
|
}
|
||||||
matrix_x = 0;
|
matrix_x = 0;
|
||||||
{
|
{
|
||||||
let mut x: i32 = 0;
|
let mut x: i32 = 0;
|
||||||
while x < symbol_width {
|
while x < symbol_width {
|
||||||
{
|
{
|
||||||
// Fill the right edge with full 1
|
// Fill the right edge with full 1
|
||||||
@@ -267,51 +318,55 @@ impl DataMatrixWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matrix_y += 1;
|
matrix_y += 1;
|
||||||
// Fill the bottom edge with full 1
|
// Fill the bottom edge with full 1
|
||||||
if (y % symbol_info.matrixHeight) == symbol_info.matrixHeight - 1 {
|
if (y % symbol_info.matrixHeight) == symbol_info.matrixHeight - 1 {
|
||||||
matrix_x = 0;
|
matrix_x = 0;
|
||||||
{
|
{
|
||||||
let mut x: i32 = 0;
|
let mut x: i32 = 0;
|
||||||
while x < symbol_info.get_symbol_width() {
|
while x < symbol_info.get_symbol_width() {
|
||||||
{
|
{
|
||||||
matrix.set(matrix_x, matrix_y, true);
|
matrix.set(matrix_x, matrix_y, true);
|
||||||
matrix_x += 1;
|
matrix_x += 1;
|
||||||
}
|
}
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matrix_y += 1;
|
matrix_y += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
y += 1;
|
y += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ::convert_byte_matrix_to_bit_matrix(matrix, width, height);
|
return ::convert_byte_matrix_to_bit_matrix(matrix, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the ByteMatrix to BitMatrix.
|
* Convert the ByteMatrix to BitMatrix.
|
||||||
*
|
*
|
||||||
* @param reqHeight The requested height of the image (in pixels) with the Datamatrix code
|
* @param reqHeight The requested height of the image (in pixels) with the Datamatrix code
|
||||||
* @param reqWidth The requested width of the image (in pixels) with the Datamatrix code
|
* @param reqWidth The requested width of the image (in pixels) with the Datamatrix code
|
||||||
* @param matrix The input matrix.
|
* @param matrix The input matrix.
|
||||||
* @return The output matrix.
|
* @return The output matrix.
|
||||||
*/
|
*/
|
||||||
fn convert_byte_matrix_to_bit_matrix( matrix: &ByteMatrix, req_width: i32, req_height: i32) -> BitMatrix {
|
fn convert_byte_matrix_to_bit_matrix(
|
||||||
let matrix_width: i32 = matrix.get_width();
|
matrix: &ByteMatrix,
|
||||||
let matrix_height: i32 = matrix.get_height();
|
req_width: i32,
|
||||||
let output_width: i32 = Math::max(req_width, matrix_width);
|
req_height: i32,
|
||||||
let output_height: i32 = Math::max(req_height, matrix_height);
|
) -> BitMatrix {
|
||||||
let multiple: i32 = Math::min(output_width / matrix_width, output_height / matrix_height);
|
let matrix_width: i32 = matrix.get_width();
|
||||||
let left_padding: i32 = (output_width - (matrix_width * multiple)) / 2;
|
let matrix_height: i32 = matrix.get_height();
|
||||||
let top_padding: i32 = (output_height - (matrix_height * multiple)) / 2;
|
let output_width: i32 = Math::max(req_width, matrix_width);
|
||||||
let mut output: BitMatrix;
|
let output_height: i32 = Math::max(req_height, matrix_height);
|
||||||
|
let multiple: i32 = Math::min(output_width / matrix_width, output_height / matrix_height);
|
||||||
|
let left_padding: i32 = (output_width - (matrix_width * multiple)) / 2;
|
||||||
|
let top_padding: i32 = (output_height - (matrix_height * multiple)) / 2;
|
||||||
|
let mut output: BitMatrix;
|
||||||
// remove padding if requested width and height are too small
|
// remove padding if requested width and height are too small
|
||||||
if req_height < matrix_height || req_width < matrix_width {
|
if req_height < matrix_height || req_width < matrix_width {
|
||||||
left_padding = 0;
|
left_padding = 0;
|
||||||
@@ -321,15 +376,15 @@ impl DataMatrixWriter {
|
|||||||
output = BitMatrix::new(req_width, req_height);
|
output = BitMatrix::new(req_width, req_height);
|
||||||
}
|
}
|
||||||
output.clear();
|
output.clear();
|
||||||
{
|
{
|
||||||
let input_y: i32 = 0;
|
let input_y: i32 = 0;
|
||||||
let output_y: i32 = top_padding;
|
let output_y: i32 = top_padding;
|
||||||
while input_y < matrix_height {
|
while input_y < matrix_height {
|
||||||
{
|
{
|
||||||
// Write the contents of this row of the bytematrix
|
// Write the contents of this row of the bytematrix
|
||||||
{
|
{
|
||||||
let input_x: i32 = 0;
|
let input_x: i32 = 0;
|
||||||
let output_x: i32 = left_padding;
|
let output_x: i32 = left_padding;
|
||||||
while input_x < matrix_width {
|
while input_x < matrix_width {
|
||||||
{
|
{
|
||||||
if matrix.get(input_x, input_y) == 1 {
|
if matrix.get(input_x, input_y) == 1 {
|
||||||
@@ -338,16 +393,14 @@ impl DataMatrixWriter {
|
|||||||
}
|
}
|
||||||
input_x += 1;
|
input_x += 1;
|
||||||
output_x += multiple;
|
output_x += multiple;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
input_y += 1;
|
input_y += 1;
|
||||||
output_y += multiple;
|
output_y += multiple;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
use crate::{NotFoundException,ResultPoint};
|
|
||||||
use crate::common::{BitMatrix,DetectorResult,GridSampler};
|
|
||||||
use crate::common::detector::WhiteRectangleDetector;
|
use crate::common::detector::WhiteRectangleDetector;
|
||||||
|
use crate::common::{BitMatrix, DetectorResult, GridSampler};
|
||||||
|
use crate::{NotFoundException, ResultPoint};
|
||||||
|
|
||||||
// Detector.java
|
// Detector.java
|
||||||
/**
|
/**
|
||||||
@@ -10,86 +10,94 @@ use crate::common::detector::WhiteRectangleDetector;
|
|||||||
* @author Sean Owen
|
* @author Sean Owen
|
||||||
*/
|
*/
|
||||||
pub struct Detector {
|
pub struct Detector {
|
||||||
|
image: BitMatrix,
|
||||||
|
|
||||||
image: BitMatrix,
|
rectangle_detector: WhiteRectangleDetector,
|
||||||
|
|
||||||
rectangle_detector: WhiteRectangleDetector
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Detector {
|
impl Detector {
|
||||||
|
pub fn new(image: &BitMatrix) -> Result<Self, NotFoundException> {
|
||||||
|
let d: Self;
|
||||||
|
d.image = image;
|
||||||
|
d.rectangle_detector = WhiteRectangleDetector::new(image, None, None, None);
|
||||||
|
|
||||||
pub fn new( image: &BitMatrix) -> Result<Self, NotFoundException> {
|
Ok(d)
|
||||||
let d : Self;
|
}
|
||||||
d .image = image;
|
|
||||||
d.rectangle_detector = WhiteRectangleDetector::new(image, None, None, None);
|
|
||||||
|
|
||||||
Ok(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Detects a Data Matrix Code in an image.</p>
|
* <p>Detects a Data Matrix Code in an image.</p>
|
||||||
*
|
*
|
||||||
* @return {@link DetectorResult} encapsulating results of detecting a Data Matrix Code
|
* @return {@link DetectorResult} encapsulating results of detecting a Data Matrix Code
|
||||||
* @throws NotFoundException if no Data Matrix Code can be found
|
* @throws NotFoundException if no Data Matrix Code can be found
|
||||||
*/
|
*/
|
||||||
pub fn detect(&self) -> Result<DetectorResult, NotFoundException> {
|
pub fn detect(&self) -> Result<DetectorResult, NotFoundException> {
|
||||||
let corner_points: Vec<ResultPoint> = self.rectangle_detector.detect();
|
let corner_points: Vec<ResultPoint> = self.rectangle_detector.detect();
|
||||||
let mut points: Vec<ResultPoint> = self.detect_solid1(&corner_points);
|
let mut points: Vec<ResultPoint> = self.detect_solid1(&corner_points);
|
||||||
points = self.detect_solid2(points?);
|
points = self.detect_solid2(points?);
|
||||||
points[3] = self.correct_top_right(points?);
|
points[3] = self.correct_top_right(points?);
|
||||||
if points[3] == null {
|
if points[3] == null {
|
||||||
return Err( NotFoundException::get_not_found_instance());
|
return Err(NotFoundException::get_not_found_instance());
|
||||||
}
|
}
|
||||||
points = self.shift_to_module_center(points?);
|
points = self.shift_to_module_center(points?);
|
||||||
let top_left: ResultPoint = points[0];
|
let top_left: ResultPoint = points[0];
|
||||||
let bottom_left: ResultPoint = points[1];
|
let bottom_left: ResultPoint = points[1];
|
||||||
let bottom_right: ResultPoint = points[2];
|
let bottom_right: ResultPoint = points[2];
|
||||||
let top_right: ResultPoint = points[3];
|
let top_right: ResultPoint = points[3];
|
||||||
let dimension_top: i32 = self.transitions_between(&top_left, &top_right) + 1;
|
let dimension_top: i32 = self.transitions_between(&top_left, &top_right) + 1;
|
||||||
let dimension_right: i32 = self.transitions_between(&bottom_right, &top_right) + 1;
|
let dimension_right: i32 = self.transitions_between(&bottom_right, &top_right) + 1;
|
||||||
if (dimension_top & 0x01) == 1 {
|
if (dimension_top & 0x01) == 1 {
|
||||||
dimension_top += 1;
|
dimension_top += 1;
|
||||||
}
|
}
|
||||||
if (dimension_right & 0x01) == 1 {
|
if (dimension_right & 0x01) == 1 {
|
||||||
dimension_right += 1;
|
dimension_right += 1;
|
||||||
}
|
}
|
||||||
if 4 * dimension_top < 6 * dimension_right && 4 * dimension_right < 6 * dimension_top {
|
if 4 * dimension_top < 6 * dimension_right && 4 * dimension_right < 6 * dimension_top {
|
||||||
// The matrix is square
|
// The matrix is square
|
||||||
dimension_top = dimension_right = Math::max(dimension_top, dimension_right);
|
dimension_top = dimension_right = Math::max(dimension_top, dimension_right);
|
||||||
}
|
}
|
||||||
let bits: BitMatrix = ::sample_grid(self.image, top_left, bottom_left, bottom_right, top_right, dimension_top, dimension_right);
|
let bits: BitMatrix = ::sample_grid(
|
||||||
return Ok(DetectorResult::new(bits, vec![top_left, bottom_left, bottom_right, top_right, ]
|
self.image,
|
||||||
));
|
top_left,
|
||||||
}
|
bottom_left,
|
||||||
|
bottom_right,
|
||||||
|
top_right,
|
||||||
|
dimension_top,
|
||||||
|
dimension_right,
|
||||||
|
);
|
||||||
|
return Ok(DetectorResult::new(
|
||||||
|
bits,
|
||||||
|
vec![top_left, bottom_left, bottom_right, top_right],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
fn shift_point( point: &ResultPoint, to: &ResultPoint, div: i32) -> ResultPoint {
|
fn shift_point(point: &ResultPoint, to: &ResultPoint, div: i32) -> ResultPoint {
|
||||||
let x: f32 = (to.get_x() - point.get_x()) / (div + 1);
|
let x: f32 = (to.get_x() - point.get_x()) / (div + 1);
|
||||||
let y: f32 = (to.get_y() - point.get_y()) / (div + 1);
|
let y: f32 = (to.get_y() - point.get_y()) / (div + 1);
|
||||||
return ResultPoint::new(point.get_x() + x, point.get_y() + y);
|
return ResultPoint::new(point.get_x() + x, point.get_y() + y);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_away( point: &ResultPoint, from_x: f32, from_y: f32) -> ResultPoint {
|
fn move_away(point: &ResultPoint, from_x: f32, from_y: f32) -> ResultPoint {
|
||||||
let mut x: f32 = point.get_x();
|
let mut x: f32 = point.get_x();
|
||||||
let mut y: f32 = point.get_y();
|
let mut y: f32 = point.get_y();
|
||||||
if x < from_x {
|
if x < from_x {
|
||||||
x -= 1.0;
|
x -= 1.0;
|
||||||
} else {
|
} else {
|
||||||
x += 1.0;
|
x += 1.0;
|
||||||
}
|
}
|
||||||
if y < from_y {
|
if y < from_y {
|
||||||
y -= 1.0;
|
y -= 1.0;
|
||||||
} else {
|
} else {
|
||||||
y += 1.0;
|
y += 1.0;
|
||||||
}
|
}
|
||||||
return ResultPoint::new(x, y);
|
return ResultPoint::new(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect a solid side which has minimum transition.
|
* Detect a solid side which has minimum transition.
|
||||||
*/
|
*/
|
||||||
fn detect_solid1(&self, corner_points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
fn detect_solid1(&self, corner_points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
||||||
// 0 2
|
// 0 2
|
||||||
// 1 3
|
// 1 3
|
||||||
let point_a: ResultPoint = corner_points[0];
|
let point_a: ResultPoint = corner_points[0];
|
||||||
let point_b: ResultPoint = corner_points[1];
|
let point_b: ResultPoint = corner_points[1];
|
||||||
let point_c: ResultPoint = corner_points[3];
|
let point_c: ResultPoint = corner_points[3];
|
||||||
@@ -98,215 +106,258 @@ impl Detector {
|
|||||||
let tr_b_c: i32 = self.transitions_between(&point_b, &point_c);
|
let tr_b_c: i32 = self.transitions_between(&point_b, &point_c);
|
||||||
let tr_c_d: i32 = self.transitions_between(&point_c, &point_d);
|
let tr_c_d: i32 = self.transitions_between(&point_c, &point_d);
|
||||||
let tr_d_a: i32 = self.transitions_between(&point_d, &point_a);
|
let tr_d_a: i32 = self.transitions_between(&point_d, &point_a);
|
||||||
// 0..3
|
// 0..3
|
||||||
// : :
|
// : :
|
||||||
// 1--2
|
// 1--2
|
||||||
let mut min: i32 = tr_a_b;
|
let mut min: i32 = tr_a_b;
|
||||||
let mut points: vec![Vec<ResultPoint>; 4] = vec![point_d, point_a, point_b, point_c, ]
|
let mut points: vec![Vec<ResultPoint>; 4] = vec![point_d, point_a, point_b, point_c];
|
||||||
;
|
if min > tr_b_c {
|
||||||
if min > tr_b_c {
|
min = tr_b_c;
|
||||||
min = tr_b_c;
|
points[0] = point_a;
|
||||||
points[0] = point_a;
|
points[1] = point_b;
|
||||||
points[1] = point_b;
|
points[2] = point_c;
|
||||||
points[2] = point_c;
|
points[3] = point_d;
|
||||||
points[3] = point_d;
|
}
|
||||||
}
|
if min > tr_c_d {
|
||||||
if min > tr_c_d {
|
min = tr_c_d;
|
||||||
min = tr_c_d;
|
points[0] = point_b;
|
||||||
points[0] = point_b;
|
points[1] = point_c;
|
||||||
points[1] = point_c;
|
points[2] = point_d;
|
||||||
points[2] = point_d;
|
points[3] = point_a;
|
||||||
points[3] = point_a;
|
}
|
||||||
}
|
if min > tr_d_a {
|
||||||
if min > tr_d_a {
|
points[0] = point_c;
|
||||||
points[0] = point_c;
|
points[1] = point_d;
|
||||||
points[1] = point_d;
|
points[2] = point_a;
|
||||||
points[2] = point_a;
|
points[3] = point_b;
|
||||||
points[3] = point_b;
|
}
|
||||||
}
|
return points;
|
||||||
return points;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect a second solid side next to first solid side.
|
* Detect a second solid side next to first solid side.
|
||||||
*/
|
*/
|
||||||
fn detect_solid2(&self, points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
fn detect_solid2(&self, points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
||||||
// A..D
|
// A..D
|
||||||
// : :
|
// : :
|
||||||
// B--C
|
// B--C
|
||||||
let point_a: ResultPoint = points[0];
|
let point_a: ResultPoint = points[0];
|
||||||
let point_b: ResultPoint = points[1];
|
let point_b: ResultPoint = points[1];
|
||||||
let point_c: ResultPoint = points[2];
|
let point_c: ResultPoint = points[2];
|
||||||
let point_d: ResultPoint = points[3];
|
let point_d: ResultPoint = points[3];
|
||||||
// Transition detection on the edge is not stable.
|
// Transition detection on the edge is not stable.
|
||||||
// To safely detect, shift the points to the module center.
|
// To safely detect, shift the points to the module center.
|
||||||
let tr: i32 = self.transitions_between(&point_a, &point_d);
|
let tr: i32 = self.transitions_between(&point_a, &point_d);
|
||||||
let point_bs: ResultPoint = ::shift_point(point_b, point_c, (tr + 1) * 4);
|
let point_bs: ResultPoint = ::shift_point(point_b, point_c, (tr + 1) * 4);
|
||||||
let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr + 1) * 4);
|
let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr + 1) * 4);
|
||||||
let tr_b_a: i32 = self.transitions_between(&point_bs, &point_a);
|
let tr_b_a: i32 = self.transitions_between(&point_bs, &point_a);
|
||||||
let tr_c_d: i32 = self.transitions_between(&point_cs, &point_d);
|
let tr_c_d: i32 = self.transitions_between(&point_cs, &point_d);
|
||||||
// 1--2
|
// 1--2
|
||||||
if tr_b_a < tr_c_d {
|
if tr_b_a < tr_c_d {
|
||||||
// solid sides: A-B-C
|
// solid sides: A-B-C
|
||||||
points[0] = point_a;
|
points[0] = point_a;
|
||||||
points[1] = point_b;
|
points[1] = point_b;
|
||||||
points[2] = point_c;
|
points[2] = point_c;
|
||||||
points[3] = point_d;
|
points[3] = point_d;
|
||||||
} else {
|
} else {
|
||||||
// solid sides: B-C-D
|
// solid sides: B-C-D
|
||||||
points[0] = point_b;
|
points[0] = point_b;
|
||||||
points[1] = point_c;
|
points[1] = point_c;
|
||||||
points[2] = point_d;
|
points[2] = point_d;
|
||||||
points[3] = point_a;
|
points[3] = point_a;
|
||||||
}
|
}
|
||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the corner position of the white top right module.
|
* Calculates the corner position of the white top right module.
|
||||||
*/
|
*/
|
||||||
fn correct_top_right(&self, points: &Vec<ResultPoint>) -> ResultPoint {
|
fn correct_top_right(&self, points: &Vec<ResultPoint>) -> ResultPoint {
|
||||||
// A..D
|
// A..D
|
||||||
// | :
|
// | :
|
||||||
// B--C
|
// B--C
|
||||||
let point_a: ResultPoint = points[0];
|
let point_a: ResultPoint = points[0];
|
||||||
let point_b: ResultPoint = points[1];
|
let point_b: ResultPoint = points[1];
|
||||||
let point_c: ResultPoint = points[2];
|
let point_c: ResultPoint = points[2];
|
||||||
let point_d: ResultPoint = points[3];
|
let point_d: ResultPoint = points[3];
|
||||||
// shift points for safe transition detection.
|
// shift points for safe transition detection.
|
||||||
let tr_top: i32 = self.transitions_between(&point_a, &point_d);
|
let tr_top: i32 = self.transitions_between(&point_a, &point_d);
|
||||||
let tr_right: i32 = self.transitions_between(&point_b, &point_d);
|
let tr_right: i32 = self.transitions_between(&point_b, &point_d);
|
||||||
let point_as: ResultPoint = ::shift_point(point_a, point_b, (tr_right + 1) * 4);
|
let point_as: ResultPoint = ::shift_point(point_a, point_b, (tr_right + 1) * 4);
|
||||||
let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr_top + 1) * 4);
|
let point_cs: ResultPoint = ::shift_point(point_c, point_b, (tr_top + 1) * 4);
|
||||||
tr_top = self.transitions_between(&point_as, &point_d);
|
tr_top = self.transitions_between(&point_as, &point_d);
|
||||||
tr_right = self.transitions_between(&point_cs, &point_d);
|
tr_right = self.transitions_between(&point_cs, &point_d);
|
||||||
let candidate1: ResultPoint = ResultPoint::new(point_d.get_x() + (point_c.get_x() - point_b.get_x()) / (tr_top + 1), point_d.get_y() + (point_c.get_y() - point_b.get_y()) / (tr_top + 1));
|
let candidate1: ResultPoint = ResultPoint::new(
|
||||||
let candidate2: ResultPoint = ResultPoint::new(point_d.get_x() + (point_a.get_x() - point_b.get_x()) / (tr_right + 1), point_d.get_y() + (point_a.get_y() - point_b.get_y()) / (tr_right + 1));
|
point_d.get_x() + (point_c.get_x() - point_b.get_x()) / (tr_top + 1),
|
||||||
if !self.is_valid(&candidate1) {
|
point_d.get_y() + (point_c.get_y() - point_b.get_y()) / (tr_top + 1),
|
||||||
if self.is_valid(&candidate2) {
|
);
|
||||||
return candidate2;
|
let candidate2: ResultPoint = ResultPoint::new(
|
||||||
}
|
point_d.get_x() + (point_a.get_x() - point_b.get_x()) / (tr_right + 1),
|
||||||
return null;
|
point_d.get_y() + (point_a.get_y() - point_b.get_y()) / (tr_right + 1),
|
||||||
}
|
);
|
||||||
if !self.is_valid(&candidate2) {
|
if !self.is_valid(&candidate1) {
|
||||||
return candidate1;
|
if self.is_valid(&candidate2) {
|
||||||
}
|
return candidate2;
|
||||||
let sumc1: i32 = self.transitions_between(&point_as, &candidate1) + self.transitions_between(&point_cs, &candidate1);
|
}
|
||||||
let sumc2: i32 = self.transitions_between(&point_as, &candidate2) + self.transitions_between(&point_cs, &candidate2);
|
return null;
|
||||||
if sumc1 > sumc2 {
|
}
|
||||||
return candidate1;
|
if !self.is_valid(&candidate2) {
|
||||||
} else {
|
return candidate1;
|
||||||
return candidate2;
|
}
|
||||||
}
|
let sumc1: i32 = self.transitions_between(&point_as, &candidate1)
|
||||||
}
|
+ self.transitions_between(&point_cs, &candidate1);
|
||||||
|
let sumc2: i32 = self.transitions_between(&point_as, &candidate2)
|
||||||
|
+ self.transitions_between(&point_cs, &candidate2);
|
||||||
|
if sumc1 > sumc2 {
|
||||||
|
return candidate1;
|
||||||
|
} else {
|
||||||
|
return candidate2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shift the edge points to the module center.
|
* Shift the edge points to the module center.
|
||||||
*/
|
*/
|
||||||
fn shift_to_module_center(&self, points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
fn shift_to_module_center(&self, points: &Vec<ResultPoint>) -> Vec<ResultPoint> {
|
||||||
// A..D
|
// A..D
|
||||||
// | :
|
// | :
|
||||||
// B--C
|
// B--C
|
||||||
let point_a: ResultPoint = points[0];
|
let point_a: ResultPoint = points[0];
|
||||||
let point_b: ResultPoint = points[1];
|
let point_b: ResultPoint = points[1];
|
||||||
let point_c: ResultPoint = points[2];
|
let point_c: ResultPoint = points[2];
|
||||||
let point_d: ResultPoint = points[3];
|
let point_d: ResultPoint = points[3];
|
||||||
// calculate pseudo dimensions
|
// calculate pseudo dimensions
|
||||||
let dim_h: i32 = self.transitions_between(&point_a, &point_d) + 1;
|
let dim_h: i32 = self.transitions_between(&point_a, &point_d) + 1;
|
||||||
let dim_v: i32 = self.transitions_between(&point_c, &point_d) + 1;
|
let dim_v: i32 = self.transitions_between(&point_c, &point_d) + 1;
|
||||||
// shift points for safe dimension detection
|
// shift points for safe dimension detection
|
||||||
let point_as: ResultPoint = ::shift_point(point_a, point_b, dim_v * 4);
|
let point_as: ResultPoint = ::shift_point(point_a, point_b, dim_v * 4);
|
||||||
let point_cs: ResultPoint = ::shift_point(point_c, point_b, dim_h * 4);
|
let point_cs: ResultPoint = ::shift_point(point_c, point_b, dim_h * 4);
|
||||||
// calculate more precise dimensions
|
// calculate more precise dimensions
|
||||||
dim_h = self.transitions_between(&point_as, &point_d) + 1;
|
dim_h = self.transitions_between(&point_as, &point_d) + 1;
|
||||||
dim_v = self.transitions_between(&point_cs, &point_d) + 1;
|
dim_v = self.transitions_between(&point_cs, &point_d) + 1;
|
||||||
if (dim_h & 0x01) == 1 {
|
if (dim_h & 0x01) == 1 {
|
||||||
dim_h += 1;
|
dim_h += 1;
|
||||||
}
|
}
|
||||||
if (dim_v & 0x01) == 1 {
|
if (dim_v & 0x01) == 1 {
|
||||||
dim_v += 1;
|
dim_v += 1;
|
||||||
}
|
}
|
||||||
// WhiteRectangleDetector returns points inside of the rectangle.
|
// WhiteRectangleDetector returns points inside of the rectangle.
|
||||||
// I want points on the edges.
|
// I want points on the edges.
|
||||||
let center_x: f32 = (point_a.get_x() + point_b.get_x() + point_c.get_x() + point_d.get_x()) / 4;
|
let center_x: f32 =
|
||||||
let center_y: f32 = (point_a.get_y() + point_b.get_y() + point_c.get_y() + point_d.get_y()) / 4;
|
(point_a.get_x() + point_b.get_x() + point_c.get_x() + point_d.get_x()) / 4;
|
||||||
point_a = ::move_away(point_a, center_x, center_y);
|
let center_y: f32 =
|
||||||
point_b = ::move_away(point_b, center_x, center_y);
|
(point_a.get_y() + point_b.get_y() + point_c.get_y() + point_d.get_y()) / 4;
|
||||||
point_c = ::move_away(point_c, center_x, center_y);
|
point_a = ::move_away(point_a, center_x, center_y);
|
||||||
point_d = ::move_away(point_d, center_x, center_y);
|
point_b = ::move_away(point_b, center_x, center_y);
|
||||||
|
point_c = ::move_away(point_c, center_x, center_y);
|
||||||
|
point_d = ::move_away(point_d, center_x, center_y);
|
||||||
let point_bs: ResultPoint;
|
let point_bs: ResultPoint;
|
||||||
let point_ds: ResultPoint;
|
let point_ds: ResultPoint;
|
||||||
// shift points to the center of each modules
|
// shift points to the center of each modules
|
||||||
point_as = ::shift_point(point_a, point_b, dim_v * 4);
|
point_as = ::shift_point(point_a, point_b, dim_v * 4);
|
||||||
point_as = ::shift_point(point_as, point_d, dim_h * 4);
|
point_as = ::shift_point(point_as, point_d, dim_h * 4);
|
||||||
point_bs = ::shift_point(point_b, point_a, dim_v * 4);
|
point_bs = ::shift_point(point_b, point_a, dim_v * 4);
|
||||||
point_bs = ::shift_point(point_bs, point_c, dim_h * 4);
|
point_bs = ::shift_point(point_bs, point_c, dim_h * 4);
|
||||||
point_cs = ::shift_point(point_c, point_d, dim_v * 4);
|
point_cs = ::shift_point(point_c, point_d, dim_v * 4);
|
||||||
point_cs = ::shift_point(point_cs, point_b, dim_h * 4);
|
point_cs = ::shift_point(point_cs, point_b, dim_h * 4);
|
||||||
point_ds = ::shift_point(point_d, point_c, dim_v * 4);
|
point_ds = ::shift_point(point_d, point_c, dim_v * 4);
|
||||||
point_ds = ::shift_point(point_ds, point_a, dim_h * 4);
|
point_ds = ::shift_point(point_ds, point_a, dim_h * 4);
|
||||||
return vec![point_as, point_bs, point_cs, point_ds, ]
|
return vec![point_as, point_bs, point_cs, point_ds];
|
||||||
;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn is_valid(&self, p: &ResultPoint) -> bool {
|
fn is_valid(&self, p: &ResultPoint) -> bool {
|
||||||
return p.get_x() >= 0 && p.get_x() <= self.image.get_width() - 1 && p.get_y() > 0 && p.get_y() <= self.image.get_height() - 1;
|
return p.get_x() >= 0
|
||||||
}
|
&& p.get_x() <= self.image.get_width() - 1
|
||||||
|
&& p.get_y() > 0
|
||||||
|
&& p.get_y() <= self.image.get_height() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
fn sample_grid( image: &BitMatrix, top_left: &ResultPoint, bottom_left: &ResultPoint, bottom_right: &ResultPoint, top_right: &ResultPoint, dimension_x: i32, dimension_y: i32) -> /* throws NotFoundException */Result<BitMatrix, Rc<Exception>> {
|
fn sample_grid(
|
||||||
|
image: &BitMatrix,
|
||||||
|
top_left: &ResultPoint,
|
||||||
|
bottom_left: &ResultPoint,
|
||||||
|
bottom_right: &ResultPoint,
|
||||||
|
top_right: &ResultPoint,
|
||||||
|
dimension_x: i32,
|
||||||
|
dimension_y: i32,
|
||||||
|
) -> Result<BitMatrix, Rc<Exception>> {
|
||||||
let sampler: GridSampler = GridSampler::get_instance();
|
let sampler: GridSampler = GridSampler::get_instance();
|
||||||
return Ok(sampler.sample_grid(image, dimension_x, dimension_y, 0.5f32, 0.5f32, dimension_x - 0.5f32, 0.5f32, dimension_x - 0.5f32, dimension_y - 0.5f32, 0.5f32, dimension_y - 0.5f32, &top_left.get_x(), &top_left.get_y(), &top_right.get_x(), &top_right.get_y(), &bottom_right.get_x(), &bottom_right.get_y(), &bottom_left.get_x(), &bottom_left.get_y()));
|
return Ok(sampler.sample_grid(
|
||||||
}
|
image,
|
||||||
|
dimension_x,
|
||||||
|
dimension_y,
|
||||||
|
0.5f32,
|
||||||
|
0.5f32,
|
||||||
|
dimension_x - 0.5f32,
|
||||||
|
0.5f32,
|
||||||
|
dimension_x - 0.5f32,
|
||||||
|
dimension_y - 0.5f32,
|
||||||
|
0.5f32,
|
||||||
|
dimension_y - 0.5f32,
|
||||||
|
&top_left.get_x(),
|
||||||
|
&top_left.get_y(),
|
||||||
|
&top_right.get_x(),
|
||||||
|
&top_right.get_y(),
|
||||||
|
&bottom_right.get_x(),
|
||||||
|
&bottom_right.get_y(),
|
||||||
|
&bottom_left.get_x(),
|
||||||
|
&bottom_left.get_y(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
|
* Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
|
||||||
*/
|
*/
|
||||||
fn transitions_between(&self, from: &ResultPoint, to: &ResultPoint) -> i32 {
|
fn transitions_between(&self, from: &ResultPoint, to: &ResultPoint) -> i32 {
|
||||||
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
|
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
|
||||||
let from_x: i32 = from.get_x() as i32;
|
let from_x: i32 = from.get_x() as i32;
|
||||||
let from_y: i32 = from.get_y() as i32;
|
let from_y: i32 = from.get_y() as i32;
|
||||||
let to_x: i32 = to.get_x() as i32;
|
let to_x: i32 = to.get_x() as i32;
|
||||||
let to_y: i32 = Math::min(self.image.get_height() - 1, to.get_y() as i32);
|
let to_y: i32 = Math::min(self.image.get_height() - 1, to.get_y() as i32);
|
||||||
let steep: bool = Math::abs(to_y - from_y) > Math::abs(to_x - from_x);
|
let steep: bool = Math::abs(to_y - from_y) > Math::abs(to_x - from_x);
|
||||||
if steep {
|
if steep {
|
||||||
let mut temp: i32 = from_x;
|
let mut temp: i32 = from_x;
|
||||||
from_x = from_y;
|
from_x = from_y;
|
||||||
from_y = temp;
|
from_y = temp;
|
||||||
temp = to_x;
|
temp = to_x;
|
||||||
to_x = to_y;
|
to_x = to_y;
|
||||||
to_y = temp;
|
to_y = temp;
|
||||||
}
|
}
|
||||||
let dx: i32 = Math::abs(to_x - from_x);
|
let dx: i32 = Math::abs(to_x - from_x);
|
||||||
let dy: i32 = Math::abs(to_y - from_y);
|
let dy: i32 = Math::abs(to_y - from_y);
|
||||||
let mut error: i32 = -dx / 2;
|
let mut error: i32 = -dx / 2;
|
||||||
let ystep: i32 = if from_y < to_y { 1 } else { -1 };
|
let ystep: i32 = if from_y < to_y { 1 } else { -1 };
|
||||||
let xstep: i32 = if from_x < to_x { 1 } else { -1 };
|
let xstep: i32 = if from_x < to_x { 1 } else { -1 };
|
||||||
let mut transitions: i32 = 0;
|
let mut transitions: i32 = 0;
|
||||||
let in_black: bool = self.image.get( if steep { from_y } else { from_x }, if steep { from_x } else { from_y });
|
let in_black: bool = self.image.get(
|
||||||
|
if steep { from_y } else { from_x },
|
||||||
|
if steep { from_x } else { from_y },
|
||||||
|
);
|
||||||
{
|
{
|
||||||
let mut x: i32 = from_x;
|
let mut x: i32 = from_x;
|
||||||
let mut y: i32 = from_y;
|
let mut y: i32 = from_y;
|
||||||
while x != to_x {
|
while x != to_x {
|
||||||
{
|
{
|
||||||
let is_black: bool = self.image.get( if steep { y } else { x }, if steep { x } else { y });
|
let is_black: bool = self
|
||||||
if is_black != in_black {
|
.image
|
||||||
transitions += 1;
|
.get(if steep { y } else { x }, if steep { x } else { y });
|
||||||
in_black = is_black;
|
if is_black != in_black {
|
||||||
}
|
transitions += 1;
|
||||||
error += dy;
|
in_black = is_black;
|
||||||
if error > 0 {
|
}
|
||||||
if y == to_y {
|
error += dy;
|
||||||
break;
|
if error > 0 {
|
||||||
}
|
if y == to_y {
|
||||||
y += ystep;
|
break;
|
||||||
error -= dx;
|
}
|
||||||
}
|
y += ystep;
|
||||||
}
|
error -= dx;
|
||||||
x += xstep;
|
}
|
||||||
|
}
|
||||||
|
x += xstep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return transitions;
|
return transitions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user