feat(apk): scanner le QR du poste depuis l'app (ZXing.Delphi, Apache 2.0)
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>
This commit is contained in:
Vendored
+632
@@ -0,0 +1,632 @@
|
||||
{
|
||||
* 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: Sean Owen
|
||||
* Delphi Implementation by K. Gossens
|
||||
}
|
||||
|
||||
unit ZXing.Datamatrix.Internal.Detector;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Math,
|
||||
System.Generics.Defaults,
|
||||
System.Generics.Collections,
|
||||
ZXing.Common.BitMatrix,
|
||||
ZXing.DefaultGridSampler,
|
||||
ZXing.Common.DetectorResult,
|
||||
ZXing.ResultPoint,
|
||||
ZXing.Common.GridSampler,
|
||||
ZXing.Common.Detector.MathUtils,
|
||||
ZXing.Common.Detector.WhiteRectangleDetector;
|
||||
|
||||
type
|
||||
/// <summary>
|
||||
/// <p>Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code
|
||||
/// is rotated or skewed, or partially obscured.</p>
|
||||
/// </summary>
|
||||
TDataMatrixDetector = class(TObject)
|
||||
private
|
||||
var
|
||||
Fimage: TBitMatrix;
|
||||
FrectangleDetector: TWhiteRectangleDetector;
|
||||
|
||||
type
|
||||
/// <summary>
|
||||
/// Simply encapsulates two points and a number of transitions between them.
|
||||
/// </summary>
|
||||
TResultPointsAndTransitions = class sealed
|
||||
public
|
||||
From: IResultPoint;
|
||||
To_: IResultPoint;
|
||||
Transitions: Integer;
|
||||
|
||||
constructor Create(From: IResultPoint; To_: IResultPoint;
|
||||
Transitions: Integer);
|
||||
destructor Destroy; override;
|
||||
function ToString: String; override;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Orders ResultPointsAndTransitions by number of transitions, ascending.
|
||||
/// </summary>
|
||||
TResultPointsAndTransitionsComparator = class sealed
|
||||
(TComparer<TResultPointsAndTransitions>)
|
||||
public
|
||||
function Compare(const o1, o2: TResultPointsAndTransitions)
|
||||
: Integer; override;
|
||||
end;
|
||||
|
||||
var
|
||||
FtransCompare: TResultPointsAndTransitionsComparator;
|
||||
public
|
||||
constructor Create(const image: TBitMatrix);
|
||||
destructor Destroy; override;
|
||||
function detect: TDetectorResult;
|
||||
function transitionsBetween(Afrom, Ato: IResultPoint)
|
||||
: TResultPointsAndTransitions;
|
||||
function distance(a: IResultPoint; b: IResultPoint): Integer;
|
||||
procedure increment(table: TDictionary<IResultPoint, Integer>;
|
||||
key: IResultPoint);
|
||||
function sampleGrid(image: TBitMatrix; topLeft, bottomLeft, bottomRight,
|
||||
topRight: IResultPoint; dimensionX, dimensionY: Integer): TBitMatrix;
|
||||
function isValid(p: IResultPoint): Boolean;
|
||||
function correctTopRight(bottomLeft, bottomRight, topLeft,
|
||||
topRight: IResultPoint; dimension: Integer): IResultPoint;
|
||||
function correctTopRightRectangular(bottomLeft, bottomRight, topLeft,
|
||||
topRight: IResultPoint; dimensionTop, dimensionRight: Integer)
|
||||
: IResultPoint;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TDataMatrixDetector }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Detector"/> class.
|
||||
/// </summary>
|
||||
/// <param name="image">The image.</param>
|
||||
constructor TDataMatrixDetector.Create(const image: TBitMatrix);
|
||||
begin
|
||||
Self.Fimage := image;
|
||||
Self.FrectangleDetector := TWhiteRectangleDetector.New(image);
|
||||
Self.FtransCompare := TResultPointsAndTransitionsComparator.Create;
|
||||
end;
|
||||
|
||||
destructor TDataMatrixDetector.Destroy;
|
||||
begin
|
||||
if (FrectangleDetector <> nil) then
|
||||
FrectangleDetector.Free;
|
||||
|
||||
FtransCompare.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// <p>Detects a Data Matrix Code in an image.</p>
|
||||
/// </summary>
|
||||
/// <returns><see cref="DetectorResult" />encapsulating results of detecting a Data Matrix Code or null</returns>
|
||||
function TDataMatrixDetector.detect(): TDetectorResult;
|
||||
var
|
||||
topRight, correctedTopRight, pointA, pointB, pointC, pointD, maybeTopLeft,
|
||||
bottomLeft, bottomRight, topLeft, maybeBottomRight, point: IResultPoint;
|
||||
|
||||
cornerPoints: TArray<IResultPoint>;
|
||||
bits: TBitMatrix;
|
||||
entry: TPair<IResultPoint, Integer>; // TKeyValuePair
|
||||
Transitions: TObjectList<TResultPointsAndTransitions>;
|
||||
lSideOne, lSideTwo, transBetween, transA, transB: TResultPointsAndTransitions;
|
||||
pointCount: TDictionary<IResultPoint, Integer>;
|
||||
|
||||
corners: TArray<IResultPoint>;
|
||||
|
||||
dimensionTop, dimensionRight, dimension, dimensionCorrected: Integer;
|
||||
begin
|
||||
Result := nil;
|
||||
|
||||
if (FrectangleDetector = nil) then
|
||||
// can be null, if the image is to small
|
||||
exit;
|
||||
|
||||
cornerPoints := FrectangleDetector.detect();
|
||||
if (cornerPoints = nil) then
|
||||
exit;
|
||||
|
||||
pointA := cornerPoints[0];
|
||||
pointB := cornerPoints[1];
|
||||
pointC := cornerPoints[2];
|
||||
pointD := cornerPoints[3];
|
||||
|
||||
// Point A and D are across the diagonal from one another,
|
||||
// as are B and C. Figure out which are the solid black lines
|
||||
// by counting transitions
|
||||
Transitions := TObjectList<TResultPointsAndTransitions>.Create;
|
||||
pointCount := TDictionary<IResultPoint, Integer>.Create();
|
||||
try
|
||||
Transitions.Add(transitionsBetween(pointA, pointB));
|
||||
Transitions.Add(transitionsBetween(pointA, pointC));
|
||||
Transitions.Add(transitionsBetween(pointB, pointD));
|
||||
Transitions.Add(transitionsBetween(pointC, pointD));
|
||||
Transitions.Sort(FtransCompare);
|
||||
|
||||
// Sort by number of transitions. First two will be the two solid sides; last two
|
||||
// will be the two alternating black/white sides
|
||||
lSideOne := Transitions[0];
|
||||
lSideTwo := Transitions[1];
|
||||
|
||||
// Figure out which point is their intersection by tallying up the number of times we see the
|
||||
// endpoints in the four endpoints. One will show up twice.
|
||||
|
||||
increment(pointCount, lSideOne.From);
|
||||
increment(pointCount, lSideOne.To_);
|
||||
increment(pointCount, lSideTwo.From);
|
||||
increment(pointCount, lSideTwo.To_);
|
||||
|
||||
maybeTopLeft := nil;
|
||||
bottomLeft := nil;
|
||||
maybeBottomRight := nil;
|
||||
|
||||
for entry in pointCount do
|
||||
begin
|
||||
point := entry.key;
|
||||
if (entry.Value = 2) then
|
||||
bottomLeft := point
|
||||
// this is definitely the bottom left, then -- end of two L sides
|
||||
else
|
||||
begin
|
||||
// Otherwise it's either top left or bottom right -- just assign the two arbitrarily now
|
||||
if (maybeTopLeft = nil) then
|
||||
maybeTopLeft := point
|
||||
else
|
||||
maybeBottomRight := point;
|
||||
end;
|
||||
end;
|
||||
|
||||
if ((maybeTopLeft = nil) or (bottomLeft = nil) or (maybeBottomRight = nil))
|
||||
then
|
||||
exit;
|
||||
|
||||
// Bottom left is correct but top left and bottom right might be switched
|
||||
corners := TArray<IResultPoint>.Create(maybeTopLeft, bottomLeft,
|
||||
maybeBottomRight);
|
||||
// Use the dot product trick to sort them out
|
||||
TResultPointHelpers.orderBestPatterns(corners);
|
||||
|
||||
// Now we know which is which:
|
||||
bottomRight := corners[0];
|
||||
bottomLeft := corners[1];
|
||||
topLeft := corners[2];
|
||||
|
||||
// Which point didn't we find in relation to the "L" sides? that's the top right corner
|
||||
if (not pointCount.ContainsKey(pointA)) then
|
||||
topRight := pointA
|
||||
else if (not pointCount.ContainsKey(pointB)) then
|
||||
topRight := pointB
|
||||
else if (not pointCount.ContainsKey(pointC)) then
|
||||
topRight := pointC
|
||||
else
|
||||
topRight := pointD;
|
||||
|
||||
// Next determine the dimension by tracing along the top or right side and counting black/white
|
||||
// transitions. Since we start inside a black module, we should see a number of transitions
|
||||
// equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
|
||||
// end on a black module:
|
||||
|
||||
// The top right point is actually the corner of a module, which is one of the two black modules
|
||||
// adjacent to the white module at the top right. Tracing to that corner from either the top left
|
||||
// or bottom right should work here.
|
||||
transBetween := transitionsBetween(topLeft, topRight);
|
||||
dimensionTop := transBetween.Transitions;
|
||||
transBetween.Free;
|
||||
|
||||
transBetween := transitionsBetween(bottomRight, topRight);
|
||||
dimensionRight := transBetween.Transitions;
|
||||
transBetween.Free;
|
||||
|
||||
if ((dimensionTop and $01) = 1) then
|
||||
// it can't be odd, so, round... up?
|
||||
Inc(dimensionTop);
|
||||
Inc(dimensionTop, 2);
|
||||
|
||||
if ((dimensionRight and $01) = 1) then
|
||||
// it can't be odd, so, round... up?
|
||||
Inc(dimensionRight);
|
||||
Inc(dimensionRight, 2);
|
||||
|
||||
// Rectangular symbols are 6x16, 6x28, 10x24, 10x32, 14x32, or 14x44. If one dimension is more
|
||||
// than twice the other, it's certainly rectangular, but to cut a bit more slack we accept it as
|
||||
// rectangular if the bigger side is at least 7/4 times the other:
|
||||
if (((4 * dimensionTop) >= (7 * dimensionRight)) or
|
||||
((4 * dimensionRight) >= (7 * dimensionTop))) then
|
||||
begin
|
||||
// The matrix is rectangular
|
||||
correctedTopRight := correctTopRightRectangular(bottomLeft, bottomRight,
|
||||
topLeft, topRight, dimensionTop, dimensionRight);
|
||||
if (correctedTopRight = nil) then
|
||||
correctedTopRight := topRight;
|
||||
|
||||
transBetween := transitionsBetween(topLeft, correctedTopRight);
|
||||
dimensionTop := transBetween.Transitions;
|
||||
transBetween.Free;
|
||||
|
||||
transBetween := transitionsBetween(bottomRight, correctedTopRight);
|
||||
dimensionRight := transBetween.Transitions;
|
||||
transBetween.Free;
|
||||
|
||||
if ((dimensionTop and $01) = 1) then
|
||||
// it can't be odd, so, round... up?
|
||||
Inc(dimensionTop);
|
||||
|
||||
if ((dimensionRight and $01) = 1) then
|
||||
// it can't be odd, so, round... up?
|
||||
Inc(dimensionRight);
|
||||
|
||||
bits := sampleGrid(Fimage, topLeft, bottomLeft, bottomRight,
|
||||
correctedTopRight, dimensionTop, dimensionRight)
|
||||
end
|
||||
else
|
||||
begin
|
||||
// The matrix is square
|
||||
dimension := System.Math.Min(dimensionRight, dimensionTop);
|
||||
// correct top right point to match the white module
|
||||
correctedTopRight := correctTopRight(bottomLeft, bottomRight, topLeft,
|
||||
topRight, dimension);
|
||||
if (correctedTopRight = nil) then
|
||||
correctedTopRight := topRight;
|
||||
|
||||
// Redetermine the dimension using the corrected top right point
|
||||
transA := transitionsBetween(topLeft, correctedTopRight);
|
||||
transB := transitionsBetween(bottomRight, correctedTopRight);
|
||||
dimensionCorrected :=
|
||||
(System.Math.Max(transA.Transitions, transB.Transitions) + 1);
|
||||
|
||||
transA.Free;
|
||||
transB.Free;
|
||||
|
||||
if ((dimensionCorrected and $01) = 1) then
|
||||
Inc(dimensionCorrected);
|
||||
|
||||
bits := sampleGrid(Fimage, topLeft, bottomLeft, bottomRight,
|
||||
correctedTopRight, dimensionCorrected, dimensionCorrected);
|
||||
end;
|
||||
|
||||
if (bits = nil) then
|
||||
exit;
|
||||
|
||||
Result := TDetectorResult.Create(bits, TArray<IResultPoint>.Create(topLeft,
|
||||
bottomLeft, bottomRight, correctedTopRight));
|
||||
|
||||
finally
|
||||
pointCount.Free;
|
||||
Transitions.Free;
|
||||
cornerPoints := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the position of the white top right module using the output of the rectangle detector
|
||||
/// for a rectangular matrix
|
||||
/// </summary>
|
||||
function TDataMatrixDetector.correctTopRightRectangular(bottomLeft, bottomRight,
|
||||
topLeft, topRight: IResultPoint; dimensionTop, dimensionRight: Integer)
|
||||
: IResultPoint;
|
||||
var
|
||||
corr, norm, cos, sin: Single;
|
||||
c1, c2: IResultPoint;
|
||||
l1, l2: Integer;
|
||||
rpT1, rpT2: TResultPointsAndTransitions;
|
||||
begin
|
||||
corr := (distance(bottomLeft, bottomRight) / dimensionTop);
|
||||
norm := distance(topLeft, topRight);
|
||||
if (norm = 0) then
|
||||
begin
|
||||
Result := nil;
|
||||
exit
|
||||
end;
|
||||
cos := ((topRight.X - topLeft.X) / norm);
|
||||
sin := ((topRight.Y - topLeft.Y) / norm);
|
||||
|
||||
c1 := TResultPointHelpers.CreateResultPoint((topRight.X + (corr * cos)),
|
||||
(topRight.Y + (corr * sin)));
|
||||
|
||||
corr := (distance(bottomLeft, topLeft) / dimensionRight);
|
||||
norm := distance(bottomRight, topRight);
|
||||
if (norm = 0) then
|
||||
begin
|
||||
Result := nil;
|
||||
exit;
|
||||
end;
|
||||
cos := ((topRight.X - bottomRight.X) / norm);
|
||||
sin := ((topRight.Y - bottomRight.Y) / norm);
|
||||
|
||||
c2 := TResultPointHelpers.CreateResultPoint((topRight.X + (corr * cos)),
|
||||
(topRight.Y + (corr * sin)));
|
||||
if (not isValid(c1)) then
|
||||
begin
|
||||
if (isValid(c2)) then
|
||||
begin
|
||||
Result := c2;
|
||||
exit;
|
||||
end;
|
||||
|
||||
Result := nil;
|
||||
exit;
|
||||
end;
|
||||
if (not isValid(c2)) then
|
||||
begin
|
||||
Result := c1;
|
||||
exit;
|
||||
end;
|
||||
|
||||
rpT1 := transitionsBetween(topLeft, c1);
|
||||
rpT2 := transitionsBetween(bottomRight, c1);
|
||||
|
||||
l1 := (Abs((dimensionTop - rpT1.Transitions)) +
|
||||
Abs((dimensionRight - rpT2.Transitions)));
|
||||
|
||||
FreeAndNil(rpT1);
|
||||
FreeAndNil(rpT2);
|
||||
|
||||
rpT1 := transitionsBetween(topLeft, c2);
|
||||
rpT2 := transitionsBetween(bottomRight, c2);
|
||||
|
||||
l2 := (Abs((dimensionTop - rpT1.Transitions)) +
|
||||
Abs((dimensionRight - rpT2.Transitions)));
|
||||
|
||||
FreeAndNil(rpT1);
|
||||
FreeAndNil(rpT2);
|
||||
|
||||
if (l1 <= l2) then
|
||||
begin
|
||||
Result := c1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := c2;
|
||||
end;
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the position of the white top right module using the output of the rectangle detector
|
||||
/// for a square matrix
|
||||
/// </summary>
|
||||
function TDataMatrixDetector.correctTopRight(bottomLeft, bottomRight, topLeft,
|
||||
topRight: IResultPoint; dimension: Integer): IResultPoint;
|
||||
var
|
||||
corr, cos, sin: Single;
|
||||
norm: Integer;
|
||||
c1, c2: IResultPoint;
|
||||
l1, l2: Integer;
|
||||
transA, transB: TResultPointsAndTransitions;
|
||||
begin
|
||||
corr := (distance(bottomLeft, bottomRight) / dimension);
|
||||
norm := distance(topLeft, topRight);
|
||||
if (norm = 0) then
|
||||
begin
|
||||
Result := nil;
|
||||
exit;
|
||||
end;
|
||||
cos := ((topRight.X - topLeft.X) / norm);
|
||||
sin := ((topRight.Y - topLeft.Y) / norm);
|
||||
|
||||
c1 := TResultPointHelpers.CreateResultPoint((topRight.X + (corr * cos)),
|
||||
(topRight.Y + (corr * sin)));
|
||||
|
||||
corr := (distance(bottomLeft, topLeft) / dimension);
|
||||
norm := distance(bottomRight, topRight);
|
||||
if (norm = 0) then
|
||||
begin
|
||||
Result := nil;
|
||||
exit;
|
||||
end;
|
||||
cos := ((topRight.X - bottomRight.X) / norm);
|
||||
sin := ((topRight.Y - bottomRight.Y) / norm);
|
||||
|
||||
c2 := TResultPointHelpers.CreateResultPoint((topRight.X + (corr * cos)),
|
||||
(topRight.Y + (corr * sin)));
|
||||
|
||||
if (not isValid(c1)) then
|
||||
begin
|
||||
if (isValid(c2)) then
|
||||
begin
|
||||
Result := c2;
|
||||
exit;
|
||||
end;
|
||||
|
||||
Result := nil;
|
||||
exit;
|
||||
end;
|
||||
|
||||
if (not isValid(c2)) then
|
||||
begin
|
||||
Result := c1;
|
||||
exit;
|
||||
end;
|
||||
|
||||
transA := transitionsBetween(topLeft, c1);
|
||||
transB := transitionsBetween(bottomRight, c1);
|
||||
l1 := (Abs(transA.Transitions - transB.Transitions));
|
||||
transA.Free;
|
||||
transB.Free;
|
||||
|
||||
transA := transitionsBetween(topLeft, c2);
|
||||
transB := transitionsBetween(bottomRight, c2);
|
||||
l2 := (Abs(transA.Transitions - transB.Transitions));
|
||||
transA.Free;
|
||||
transB.Free;
|
||||
|
||||
if (l1 <= l2) then
|
||||
begin
|
||||
Result := c1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := c2;
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
function TDataMatrixDetector.isValid(p: IResultPoint): Boolean;
|
||||
begin
|
||||
Result := ((((p.X >= 0) and (p.X < Fimage.Width)) and (p.Y > 0)) and
|
||||
(p.Y < Fimage.Height))
|
||||
end;
|
||||
|
||||
// L2 distance
|
||||
function TDataMatrixDetector.distance(a: IResultPoint; b: IResultPoint)
|
||||
: Integer;
|
||||
begin
|
||||
Result := TMathUtils.round(TResultPointHelpers.distance(a, b))
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Increments the Integer associated with a key by one.
|
||||
/// </summary>
|
||||
procedure TDataMatrixDetector.increment
|
||||
(table: TDictionary<IResultPoint, Integer>; key: IResultPoint);
|
||||
var
|
||||
Value: Integer;
|
||||
begin
|
||||
if (table.ContainsKey(key)) then
|
||||
begin
|
||||
Value := table[key];
|
||||
table[key] := (Value + 1);
|
||||
end
|
||||
else
|
||||
table.Add(key, 1); // table[key] := 1;
|
||||
end;
|
||||
|
||||
function TDataMatrixDetector.sampleGrid(image: TBitMatrix;
|
||||
topLeft, bottomLeft, bottomRight, topRight: IResultPoint;
|
||||
dimensionX, dimensionY: Integer): TBitMatrix;
|
||||
begin
|
||||
// TGridSampler.instance
|
||||
Result := TDefaultGridSampler.sampleGrid(image, dimensionX, dimensionY, 0.5,
|
||||
0.5, (dimensionX - 0.5), 0.5, (dimensionX - 0.5), (dimensionY - 0.5), 0.5,
|
||||
(dimensionY - 0.5), topLeft.X, topLeft.Y, topRight.X, topRight.Y,
|
||||
bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y);
|
||||
end;
|
||||
|
||||
/// <summary>
|
||||
/// Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
|
||||
/// </summary>
|
||||
function TDataMatrixDetector.transitionsBetween(Afrom, Ato: IResultPoint)
|
||||
: TResultPointsAndTransitions;
|
||||
var
|
||||
temp, fromX, fromY, toX, toY: Integer;
|
||||
steep: Boolean;
|
||||
dx, dy: Int64;
|
||||
xstep, ystep, Transitions: Integer;
|
||||
error: Int64;
|
||||
inBlack, isBlack: Boolean;
|
||||
X, Y: Integer;
|
||||
begin
|
||||
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
|
||||
fromX := Trunc(Afrom.X);
|
||||
fromY := Trunc(Afrom.Y);
|
||||
toX := Trunc(Ato.X);
|
||||
toY := Trunc(Ato.Y);
|
||||
steep := (Abs((toY - fromY)) > Abs((toX - fromX)));
|
||||
if (steep) then
|
||||
begin
|
||||
temp := fromX;
|
||||
fromX := fromY;
|
||||
fromY := temp;
|
||||
temp := toX;
|
||||
toX := toY;
|
||||
toY := temp;
|
||||
end;
|
||||
|
||||
dx := Abs(toX - fromX);
|
||||
dy := Abs(toY - fromY);
|
||||
error := TMathUtils.Asr(-dx, 1);
|
||||
if (fromY < toY) then
|
||||
ystep := 1
|
||||
else
|
||||
ystep := -1;
|
||||
if (fromX < toX) then
|
||||
xstep := 1
|
||||
else
|
||||
xstep := -1;
|
||||
Transitions := 0;
|
||||
if steep then
|
||||
inBlack := Fimage[fromY, fromX]
|
||||
else
|
||||
inBlack := Fimage[fromX, fromY];
|
||||
|
||||
X := fromX;
|
||||
Y := fromY;
|
||||
while ((X <> toX)) do
|
||||
begin
|
||||
if steep then
|
||||
isBlack := Fimage[Y, X]
|
||||
else
|
||||
isBlack := Fimage[X, Y];
|
||||
|
||||
if (isBlack <> inBlack) then
|
||||
begin
|
||||
Inc(Transitions);
|
||||
inBlack := isBlack;
|
||||
end;
|
||||
Inc(error, dy);
|
||||
if (error > 0) then
|
||||
begin
|
||||
if (Y = toY) then
|
||||
break;
|
||||
Inc(Y, ystep);
|
||||
Dec(error, dx);
|
||||
end;
|
||||
Inc(X, xstep)
|
||||
end;
|
||||
|
||||
Result := TResultPointsAndTransitions.Create(Afrom, Ato, Transitions);
|
||||
end;
|
||||
|
||||
{ TResultPointsAndTransitions }
|
||||
|
||||
constructor TDataMatrixDetector.TResultPointsAndTransitions.Create
|
||||
(From: IResultPoint; To_: IResultPoint; Transitions: Integer);
|
||||
begin
|
||||
Self.From := From;
|
||||
Self.To_ := To_;
|
||||
Self.Transitions := Transitions;
|
||||
end;
|
||||
|
||||
destructor TDataMatrixDetector.TResultPointsAndTransitions.Destroy;
|
||||
begin
|
||||
|
||||
// if (Assigned(Self.From)) then
|
||||
// Self.From := nil;
|
||||
//
|
||||
// if (Assigned(Self.To_)) then
|
||||
// Self.To_:=nil;
|
||||
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TDataMatrixDetector.TResultPointsAndTransitions.ToString: string;
|
||||
begin
|
||||
Result := From.ToString + '/' + To_.ToString + '/' + IntToStr(Transitions);
|
||||
end;
|
||||
|
||||
function TDataMatrixDetector.TResultPointsAndTransitionsComparator.Compare
|
||||
(const o1, o2: TResultPointsAndTransitions): Integer;
|
||||
begin
|
||||
Result := (o1.Transitions - o2.Transitions);
|
||||
end;
|
||||
|
||||
end.
|
||||
Reference in New Issue
Block a user