dd9fd62dcb
Le scanner du systeme demandait avec quoi ouvrir le lien. L'app ouvre la camera arriere, decode une image sur quatre et remplit URL + jeton des qu'un lien pmserver://sync est lu. Rien n'est enregistre avant Save. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
230 lines
6.6 KiB
ObjectPascal
230 lines
6.6 KiB
ObjectPascal
{
|
|
* 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
|
|
/// <summary>
|
|
/// <p>The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting
|
|
/// the Data Matrix Code from an image.</p>
|
|
/// </summary>
|
|
TDataMatrixDecoder = class sealed
|
|
private
|
|
rsDecoder: TReedSolomonDecoder;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function correctErrors(codewordBytes: TArray<Byte>; numDataCodewords: Integer): boolean;
|
|
function decode(bits: TBitMatrix): TDecoderResult; overload;
|
|
function decode(image: TArray < TArray < boolean >> ): TDecoderResult; overload;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TDataMatrixDecoder }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="Decoder"/> class.
|
|
/// </summary>
|
|
constructor TDataMatrixDecoder.Create;
|
|
begin
|
|
rsDecoder := TReedSolomonDecoder.Create(TGenericGF.DATA_MATRIX_FIELD_256);
|
|
end;
|
|
|
|
destructor TDataMatrixDecoder.Destroy;
|
|
begin
|
|
FreeAndNil(rsDecoder);
|
|
inherited;
|
|
end;
|
|
|
|
/// <summary>
|
|
/// <p>Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans.
|
|
/// "true" is taken to mean a black module.</p>
|
|
///
|
|
/// <param name="image">booleans representing white/black Data Matrix Code modules</param>
|
|
/// <returns>text and bytes encoded within the Data Matrix Code</returns>
|
|
/// <exception cref="FormatException">if the Data Matrix Code cannot be decoded</exception>
|
|
/// <exception cref="ChecksumException">if error correction fails</exception>
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// <p>Decodes a Data Matrix Code represented as a <see cref="BitMatrix" />. A 1 or "true" is taken
|
|
/// to mean a black module.</p>
|
|
/// </summary>
|
|
/// <param name="bits">booleans representing white/black Data Matrix Code modules</param>
|
|
/// <returns>text and bytes encoded within the Data Matrix Code</returns>
|
|
function TDataMatrixDecoder.decode(bits: TBitMatrix): TDecoderResult;
|
|
var
|
|
i, j: Integer;
|
|
db: TDataBlock;
|
|
parser: TBitMatrixParser;
|
|
codewords: TArray<Byte>;
|
|
dataBlocks: TArray<TDataBlock>;
|
|
dataBlocksCount, totalBytes: Integer;
|
|
resultBytes: TArray<Byte>;
|
|
DataBlock: TDataBlock;
|
|
codewordBytes: TArray<Byte>;
|
|
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<Byte>.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;
|
|
|
|
/// <summary>
|
|
/// <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
|
/// correct the errors in-place using Reed-Solomon error correction.</p>
|
|
///
|
|
/// <param name="codewordBytes">data and error correction codewords</param>
|
|
/// <param name="numDataCodewords">number of codewords that are data bytes</param>
|
|
/// </summary>
|
|
function TDataMatrixDecoder.correctErrors(codewordBytes: TArray<Byte>; numDataCodewords: Integer): boolean;
|
|
var
|
|
i, numCodewords, numECCodewords: Integer;
|
|
codewordsInts: TArray<Integer>;
|
|
begin
|
|
numCodewords := Length(codewordBytes);
|
|
// First read into an array of ints
|
|
codewordsInts := TArray<Integer>.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.
|