{
* Copyright 2007 ZXing authors
*
* 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.
* Original Author: bbrown@google.com (Brian Brown)
* Delphi Implementation by K. Gossens
}
unit ZXing.Datamatrix.DataMatrixReader;
interface
uses
System.SysUtils,
System.Generics.Collections,
ZXing.Common.Detector.MathUtils,
Math,
ZXing.Common.BitArray,
ZXing.BarcodeFormat,
ZXing.ReadResult,
ZXing.Reader,
ZXing.DecodeHintType,
ZXing.DecoderResult,
ZXing.Common.DetectorResult,
ZXing.ResultMetadataType,
ZXing.ResultPoint,
ZXing.Common.BitMatrix,
ZXing.BinaryBitmap,
ZXing.Datamatrix.Internal.Decoder,
ZXing.Datamatrix.Internal.Detector;
type
///
/// This implementation can detect and decode Data Matrix codes in an image.
///
TDataMatrixReader = class(TInterfacedObject, IReader)
private
FDecoder: TDataMatrixDecoder;
NO_POINTS: TArray;
///
/// 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
/// around it. This is a specialized method that works exceptionally fast in this special
/// case.
///
///
///
class function extractPureBits(const image: TBitMatrix): TBitMatrix; static;
class function moduleSize(const leftTopBlack: TArray;
const image: TBitMatrix; var moduleSize: Integer): Boolean; static;
public
constructor Create;
destructor Destroy; override;
///
/// This implementation can detect and decode Data Matrix codes in an image.
///
function decode(const image: TBinaryBitmap): TReadResult; overload;
function decode(const image: TBinaryBitmap;
hints: TDictionary): TReadResult; overload;
procedure reset;
end;
implementation
uses ZXing.ByteSegments;
{ TDataMatrixReader }
constructor TDataMatrixReader.Create;
begin
inherited;
FDecoder := TDataMatrixDecoder.Create;
NO_POINTS := TArray.Create();
end;
destructor TDataMatrixReader.Destroy;
begin
NO_POINTS := nil;
FDecoder.Free;
inherited;
end;
function TDataMatrixReader.decode(const image: TBinaryBitmap): TReadResult;
begin
Result := decode(image, nil);
end;
function TDataMatrixReader.decode(const image: TBinaryBitmap;
hints: TDictionary): TReadResult;
var
matrixDetector: TDataMatrixDetector;
DecoderResult: TDecoderResult;
points: TArray;
bits: TBitMatrix;
DetectorResult: TDetectorResult;
ByteSegments: IByteSegments;
begin
Result := nil;
DetectorResult := nil;
DecoderResult := nil;
try
if ((hints <> nil) and hints.ContainsKey(TDecodeHintType.PURE_BARCODE)) then
begin
bits := TDataMatrixReader.extractPureBits(image.BlackMatrix);
if Assigned(bits) then
begin
DecoderResult := FDecoder.decode(bits);
points := NO_POINTS;
FreeAndNil(bits);
end
else
exit;
end
else
begin
matrixDetector := TDataMatrixDetector.Create(image.BlackMatrix);
try
DetectorResult := matrixDetector.detect();
finally
matrixDetector.Free;
end;
if (DetectorResult = nil) then
exit;
DecoderResult := FDecoder.decode(DetectorResult.bits);
points := DetectorResult.points;
end;
if (DecoderResult = nil) then
exit;
Result := TReadResult.Create(DecoderResult.Text, DecoderResult.RawBytes,
points, TBarcodeFormat.DATA_MATRIX);
ByteSegments := DecoderResult.ByteSegments;
if (ByteSegments <> nil) then
Result.putMetadata(TResultMetadataType.BYTE_SEGMENTS, TResultMetaData.CreateByteSegmentsMetadata( byteSegments));
if (Length(DecoderResult.ECLevel) <> 0) then
Result.putMetadata(TResultMetadataType.ERROR_CORRECTION_LEVEL, TResultMetaData.CreateStringMetadata(DecoderResult.ECLevel));
finally
byteSegments:=nil;
if Assigned(DetectorResult) then
FreeAndNil(DetectorResult);
if Assigned(DecoderResult) then
FreeAndNil(DecoderResult);
end;
end;
class function TDataMatrixReader.extractPureBits(const image: TBitMatrix)
: TBitMatrix;
var
moduleSize: Integer;
leftTopBlack, rightBottomBlack: TArray;
top, bottom, left, right: Integer;
matrixWidth, matrixHeight: Integer;
nudge: Integer;
bits: TBitMatrix;
x, y, iOffset: Integer;
begin
Result := nil;
leftTopBlack := image.getTopLeftOnBit;
rightBottomBlack := image.getBottomRightOnBit;
if ((leftTopBlack = nil) or (rightBottomBlack = nil)) then
exit;
if (not TDataMatrixReader.moduleSize(leftTopBlack, image, moduleSize)) then
exit;
top := leftTopBlack[1];
bottom := rightBottomBlack[1];
left := leftTopBlack[0];
right := rightBottomBlack[0];
matrixWidth := ((right - left + 1) div moduleSize);
matrixHeight := ((bottom - top + 1) div moduleSize);
if ((matrixWidth <= 0) or (matrixHeight <= 0)) then
exit;
// 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
// little off, this will help recover.
nudge := TMathUtils.Asr(moduleSize,1);
Inc(top, nudge);
Inc(left, nudge);
// Now just read off the bits
bits := TBitMatrix.Create(matrixWidth, matrixHeight);
for y := 0 to Pred(matrixHeight) do
begin
iOffset := (top + (y * moduleSize));
for x := 0 to Pred(matrixWidth) do
begin
if (image[(left + (x * moduleSize)), iOffset]) then
bits[x, y] := true;
end;
end;
Result := bits;
end;
class function TDataMatrixReader.moduleSize(const leftTopBlack: TArray;
const image: TBitMatrix; var moduleSize: Integer): Boolean;
var
width, x, y: Integer;
begin
Result := false;
width := image.width;
x := leftTopBlack[0];
y := leftTopBlack[1];
while ((x < width) and image[x, y]) do
Inc(x);
if (x = width) then
begin
moduleSize := 0;
exit;
end;
moduleSize := (x - leftTopBlack[0]);
if (moduleSize = 0) then
exit;
Result := true;
end;
procedure TDataMatrixReader.reset;
begin
// do nothing
end;
end.