{ * Copyright 2008 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.Internal.Decoder; interface uses System.SysUtils, System.Generics.Collections, ZXing.DecodeHintType, ZXing.Common.BitMatrix, ZXing.Datamatrix.Internal.BitMatrixParser, ZXing.Datamatrix.Internal.DataBlock, ZXing.Common.ReedSolomon.ReedSolomonDecoder, ZXing.Common.ReedSolomon.GenericGF, ZXing.DecoderResult, ZXing.Datamatrix.Internal.DecodedBitStreamParser; type /// ///

The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting /// the Data Matrix Code from an image.

///
TDataMatrixDecoder = class sealed private rsDecoder: TReedSolomonDecoder; public constructor Create; destructor Destroy; override; function correctErrors(codewordBytes: TArray; numDataCodewords: Integer): boolean; function decode(bits: TBitMatrix): TDecoderResult; overload; function decode(image: TArray < TArray < boolean >> ): TDecoderResult; overload; end; implementation { TDataMatrixDecoder } /// /// Initializes a new instance of the class. /// constructor TDataMatrixDecoder.Create; begin rsDecoder := TReedSolomonDecoder.Create(TGenericGF.DATA_MATRIX_FIELD_256); end; destructor TDataMatrixDecoder.Destroy; begin FreeAndNil(rsDecoder); inherited; end; /// ///

Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans. /// "true" is taken to mean a black module.

/// /// booleans representing white/black Data Matrix Code modules /// text and bytes encoded within the Data Matrix Code /// if the Data Matrix Code cannot be decoded /// if error correction fails ///
function TDataMatrixDecoder.decode(image: TArray < TArray < boolean >> ): TDecoderResult; var i, j: Integer; dimension: Integer; bits: TBitMatrix; begin dimension := Length(image); bits := TBitMatrix.Create(dimension); for i := 0 to Pred(dimension) do begin for j := 0 to Pred(dimension) do begin if (image[i][j]) then bits[j, i] := true; end; end; Result := decode(bits); end; /// ///

Decodes a Data Matrix Code represented as a . A 1 or "true" is taken /// to mean a black module.

///
/// booleans representing white/black Data Matrix Code modules /// text and bytes encoded within the Data Matrix Code function TDataMatrixDecoder.decode(bits: TBitMatrix): TDecoderResult; var i, j: Integer; db: TDataBlock; parser: TBitMatrixParser; codewords: TArray; dataBlocks: TArray; dataBlocksCount, totalBytes: Integer; resultBytes: TArray; DataBlock: TDataBlock; codewordBytes: TArray; numDataCodewords: Integer; begin // Construct a parser and read version, error-correction level parser := TBitMatrixParser.Create(bits); DataBlock := nil; try if (parser.Version = nil) then begin Result := nil; exit; end; // Read codewords codewords := parser.readCodewords; if (codewords = nil) then begin Result := nil; exit; end; // Separate into data blocks dataBlocks := TDataBlock.getDataBlocks(codewords, parser.Version); dataBlocksCount := Length(dataBlocks); // Count total number of data bytes totalBytes := 0; for db in dataBlocks do begin Inc(totalBytes, db.numDataCodewords) end; resultBytes := TArray.Create(); SetLength(resultBytes, totalBytes); // Error-correct and copy data blocks together into a stream of bytes for j := 0 to Pred(dataBlocksCount) do begin DataBlock := dataBlocks[j]; codewordBytes := DataBlock.codewords; numDataCodewords := DataBlock.numDataCodewords; if (not correctErrors(codewordBytes, numDataCodewords)) then begin if Assigned(DataBlock) then DataBlock.Free; DataBlock := nil; resultBytes := nil; codewordBytes := nil; Result := nil; exit; end; for i := 0 to Pred(numDataCodewords) do begin // De-interlace data blocks. resultBytes[(i * dataBlocksCount) + j] := codewordBytes[i]; end; DataBlock.Free; DataBlock := nil; end; // Decode the contents of that stream of bytes Result := TDecodedBitStreamParser.decode(resultBytes); finally if Assigned(DataBlock) then DataBlock.Free; resultBytes := nil; codewordBytes := nil; parser.Free; end; end; /// ///

Given data and error-correction codewords received, possibly corrupted by errors, attempts to /// correct the errors in-place using Reed-Solomon error correction.

/// /// data and error correction codewords /// number of codewords that are data bytes ///
function TDataMatrixDecoder.correctErrors(codewordBytes: TArray; numDataCodewords: Integer): boolean; var i, numCodewords, numECCodewords: Integer; codewordsInts: TArray; begin numCodewords := Length(codewordBytes); // First read into an array of ints codewordsInts := TArray.Create(); SetLength(codewordsInts, numCodewords); for i := 0 to Pred(numCodewords) do begin codewordsInts[i] := (codewordBytes[i] and $FF); end; numECCodewords := (Length(codewordBytes) - numDataCodewords); if (not rsDecoder.decode(codewordsInts, numECCodewords)) then begin Result := false; exit; end; // Copy back into array of bytes -- only need to worry about the bytes that were data // We don't care about errors in the error-correction codewords for i := 0 to Pred(numDataCodewords) do begin codewordBytes[i] := Byte(codewordsInts[i]); end; Result := true; end; end.