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>
312 lines
7.8 KiB
ObjectPascal
312 lines
7.8 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.
|
|
|
|
* Delphi Implementation by K. Gossens
|
|
}
|
|
|
|
unit ZXing.OneD.UPCEANExtension5Support;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.Generics.Collections,
|
|
System.Math,
|
|
ZXing.Reader,
|
|
ZXing.BinaryBitmap,
|
|
ZXing.ReadResult,
|
|
ZXing.BarcodeFormat,
|
|
ZXing.DecodeHintType,
|
|
ZXing.ResultMetadataType,
|
|
ZXing.ResultPoint,
|
|
ZXing.Common.BitArray,
|
|
ZXing.Common.Detector.MathUtils;
|
|
|
|
type
|
|
(**
|
|
* @see TUPCEANExtension2Support
|
|
*)
|
|
TUPCEANExtension5Support = class sealed
|
|
private
|
|
class var
|
|
CHECK_DIGIT_ENCODINGS : TArray<Integer>;
|
|
decodeMiddleCounters : TArray<Integer>;
|
|
decodeRowStringBuffer : TStringBuilder;
|
|
|
|
class procedure InitializeClass; static;
|
|
class procedure FinalizeClass; static;
|
|
|
|
class function decodeMiddle(const row: IBitArray;
|
|
const startRange: TArray<Integer>;
|
|
const resultString: TStringBuilder): Integer;
|
|
|
|
class function extensionChecksum(const s: string): Integer; static;
|
|
|
|
class function determineCheckDigit(const lgPatternFound: Integer;
|
|
var checkDigit: Integer): Boolean; static;
|
|
|
|
/// <summary>
|
|
/// Parses the extension string.
|
|
/// </summary>
|
|
/// <param name="raw">raw content of extension</param>
|
|
/// <returns>formatted interpretation of raw content as a {@link TMap} mapping
|
|
/// one {@link TResultMetadataType} to appropriate value, or {@code nil} if not known</returns>
|
|
class function parseExtensionString(
|
|
const raw: string): TResultMetadata; static;
|
|
|
|
class function parseExtension5String(const raw: String): String; static;
|
|
public
|
|
class function decodeRow(const rowNumber: Integer; const row: IBitArray;
|
|
const extensionStartRange: TArray<Integer>): TReadResult;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
ZXing.OneD.UPCEANReader;
|
|
|
|
{ TUPCEANExtension2Support }
|
|
|
|
class procedure TUPCEANExtension5Support.InitializeClass;
|
|
begin
|
|
CHECK_DIGIT_ENCODINGS := TArray<Integer>.Create($18, $14, $12, $11, $0C,
|
|
$06, $03, $0A, $09, $05);
|
|
decodeMiddleCounters := TArray<Integer>.Create(0, 0, 0, 0);
|
|
decodeRowStringBuffer := TStringBuilder.Create;
|
|
end;
|
|
|
|
class procedure TUPCEANExtension5Support.FinalizeClass;
|
|
begin
|
|
CHECK_DIGIT_ENCODINGS := nil;
|
|
decodeMiddleCounters := nil;
|
|
decodeRowStringBuffer.Free;
|
|
end;
|
|
|
|
class function TUPCEANExtension5Support.decodeRow(const rowNumber: Integer;
|
|
const row: IBitArray; const extensionStartRange: TArray<Integer>): TReadResult;
|
|
var
|
|
res : TStringBuilder;
|
|
ending : Integer;
|
|
resultString : String;
|
|
extensionData : TResultMetadata;
|
|
resultPoints : TArray<IResultPoint>;
|
|
extensionResult : TReadResult;
|
|
begin
|
|
Result := nil;
|
|
|
|
res := decodeRowStringBuffer;
|
|
res.Length := 0;
|
|
ending := decodeMiddle(row, extensionStartRange, res);
|
|
if (ending < 0)
|
|
then
|
|
exit;
|
|
|
|
resultString := res.ToString;
|
|
extensionData := parseExtensionString(resultString);
|
|
resultPoints := TArray<IResultPoint>.Create(
|
|
TResultPointHelpers.CreateResultPoint((extensionStartRange[0] + extensionStartRange[1]) div 2, rowNumber),
|
|
TResultPointHelpers.CreateResultPoint(ending, rowNumber));
|
|
|
|
extensionResult := TReadResult.Create(resultString, nil, resultPoints, TBarcodeFormat.UPC_EAN_EXTENSION);
|
|
if (extensionData <> nil)
|
|
then
|
|
begin
|
|
extensionResult.putAllMetadata(extensionData);
|
|
FreeAndNil(extensionData);
|
|
end;
|
|
Result := extensionResult;
|
|
end;
|
|
|
|
class function TUPCEANExtension5Support.decodeMiddle(const row: IBitArray;
|
|
const startRange: TArray<Integer>; const resultString: TStringBuilder): Integer;
|
|
var
|
|
bestMatch: Integer;
|
|
counter: Integer;
|
|
ending: Integer;
|
|
counters : TArray<Integer>;
|
|
rowOffset, x,
|
|
lgPatternFound,
|
|
checkDigit : Integer;
|
|
begin
|
|
Result := -1;
|
|
|
|
counters := decodeMiddleCounters;
|
|
counters[0] := 0;
|
|
counters[1] := 0;
|
|
counters[2] := 0;
|
|
counters[3] := 0;
|
|
ending := row.Size;
|
|
rowOffset := startRange[1];
|
|
|
|
lgPatternFound := 0;
|
|
|
|
x := 0;
|
|
while (((x < 5) and (rowOffset < ending))) do
|
|
begin
|
|
if (not TUPCEANReader.decodeDigit(row, counters, rowOffset, TUPCEANReader.L_AND_G_PATTERNS, bestMatch))
|
|
then
|
|
exit;
|
|
|
|
resultString.Append(IntToStr(bestMatch mod 10));
|
|
|
|
for counter in counters do
|
|
Inc(rowOffset, counter);
|
|
|
|
if (bestMatch >= 10)
|
|
then
|
|
lgPatternFound := lgPatternFound or (1 shl (4 - x));
|
|
|
|
if (x <> 4) then
|
|
begin
|
|
// Read off separator if not last
|
|
rowOffset := row.getNextSet(rowOffset);
|
|
rowOffset := row.getNextUnset(rowOffset)
|
|
end;
|
|
Inc(x);
|
|
end;
|
|
|
|
if (resultString.Length <> 5)
|
|
then
|
|
exit;
|
|
|
|
if (not determineCheckDigit(lgPatternFound, checkDigit))
|
|
then
|
|
exit;
|
|
|
|
if (extensionChecksum(resultString.ToString) <> checkDigit)
|
|
then
|
|
exit;
|
|
|
|
Result := rowOffset;
|
|
end;
|
|
|
|
class function TUPCEANExtension5Support.extensionChecksum(
|
|
const s: String): Integer;
|
|
var
|
|
len,
|
|
sum, i : Integer;
|
|
begin
|
|
len := Length(s);
|
|
sum := 0;
|
|
i := (len - 2);
|
|
while ((i >= 0)) do
|
|
begin
|
|
Inc(sum, StrToIntDef(s.Chars[i], 0));
|
|
Dec(i, 2);
|
|
end;
|
|
sum := (sum * 3);
|
|
i := (len - 1);
|
|
while ((i >= 0)) do
|
|
begin
|
|
Inc(sum, StrToIntDef(s.Chars[i], 0));
|
|
Dec(i, 2);
|
|
end;
|
|
sum := (sum * 3);
|
|
|
|
Result := (sum mod 10);
|
|
end;
|
|
|
|
class function TUPCEANExtension5Support.determineCheckDigit(
|
|
const lgPatternFound: Integer; var checkDigit: Integer): Boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := false;
|
|
|
|
for i := 0 to Pred(10) do
|
|
begin
|
|
if (lgPatternFound = CHECK_DIGIT_ENCODINGS[i]) then
|
|
begin
|
|
Result := true;
|
|
checkDigit := i;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
class function TUPCEANExtension5Support.parseExtensionString(
|
|
const raw: String): TResultMetadata;
|
|
var
|
|
value: String;
|
|
dictionary1: TResultMetadata;
|
|
begin
|
|
Result := nil;
|
|
if (Length(raw) <> 5)
|
|
then
|
|
exit;
|
|
|
|
value := TUPCEANExtension5Support.parseExtension5String(raw);
|
|
//
|
|
// if (Length(value) = 0)
|
|
// then
|
|
// Result := nil;
|
|
|
|
dictionary1 := TResultMetadata.Create();
|
|
dictionary1.Add(ZXing.ResultMetadataType.SUGGESTED_PRICE, TResultMetadata.CreateStringMetadata(value));
|
|
|
|
Result := dictionary1;
|
|
end;
|
|
|
|
class function TUPCEANExtension5Support.parseExtension5String(
|
|
const raw: String): String;
|
|
var
|
|
currency,
|
|
unitsString,
|
|
hundredthsString : string;
|
|
rawAmount,
|
|
hundredths : Integer;
|
|
begin
|
|
Result := '';
|
|
|
|
case raw[1] of
|
|
'0' : currency := '£';
|
|
'5' : currency := '$';
|
|
'9' : begin
|
|
// Reference: http://www.jollytech.com
|
|
if ('90000'.Equals(raw))
|
|
then
|
|
// No suggested retail price
|
|
exit;
|
|
if ('99991'.Equals(raw))
|
|
then
|
|
// Complementary
|
|
Result := '0.00';
|
|
if ('99990'.Equals(raw))
|
|
then
|
|
Result := 'Used';
|
|
// Otherwise... unknown currency?
|
|
currency := '';
|
|
end;
|
|
else currency := '';
|
|
end;
|
|
|
|
rawAmount := Integer.Parse(raw.Substring(1));
|
|
unitsString := ((rawAmount div 100)).ToString;
|
|
hundredths := (rawAmount mod 100);
|
|
if (hundredths < 10)
|
|
then
|
|
hundredthsString := '0' + hundredths.ToString
|
|
else
|
|
hundredthsString := hundredths.ToString;
|
|
|
|
Result := currency + unitsString + '.' + hundredthsString;
|
|
end;
|
|
|
|
initialization
|
|
TUPCEANExtension5Support.InitializeClass;
|
|
finalization
|
|
TUPCEANExtension5Support.FinalizeClass;
|
|
end.
|