diff --git a/AndroidManifest.template.xml b/AndroidManifest.template.xml index 8ba60b4..82e3abe 100644 --- a/AndroidManifest.template.xml +++ b/AndroidManifest.template.xml @@ -31,6 +31,9 @@ BiometricPrompt n'existe pas encore. --> + + + <%queries-child-elements%> diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code128Reader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code128Reader.pas new file mode 100644 index 0000000..d6a7ec9 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code128Reader.pas @@ -0,0 +1,696 @@ +{ + * 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 Authors: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.OneD.Code128Reader; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + System.Math, + ZXing.Helpers, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat; + +var + CODE_PATTERNS: TArray>; + +type + /// + ///

Decodes Code 128 barcodes.

+ ///
+ TCode128Reader = class(TOneDReader) + private const + CODE_SHIFT = 98; + CODE_CODE_C = 99; + CODE_CODE_B = 100; + CODE_CODE_A = 101; + CODE_FNC_1 = 102; + CODE_FNC_2 = 97; + CODE_FNC_3 = 96; + CODE_FNC_4_A = 101; + CODE_FNC_4_B = 100; + CODE_START_A = 103; + CODE_START_B = 104; + CODE_START_C = 105; + CODE_STOP = 106; + + class var MAX_AVG_VARIANCE: Integer; + class var MAX_INDIVIDUAL_VARIANCE: Integer; + class function FindStartPattern(row: IBitArray): TArray; + class function DecodeCode(row: IBitArray; counters: TArray; + rowOffset: Integer; var code: Integer): Boolean; + + class procedure DoInitialize(); + class procedure DoFinalize(); + public + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; + override; + end; + +implementation + +class procedure TCode128Reader.DoFinalize; +begin + CODE_PATTERNS := nil; +end; + +class procedure TCode128Reader.DoInitialize; +begin + CODE_PATTERNS := [[2, 1, 2, 2, 2, 2], // 0 + [2, 2, 2, 1, 2, 2], [2, 2, 2, 2, 2, 1], [1, 2, 1, 2, 2, 3], + [1, 2, 1, 3, 2, 2], [1, 3, 1, 2, 2, 2], // 5 + [1, 2, 2, 2, 1, 3], [1, 2, 2, 3, 1, 2], [1, 3, 2, 2, 1, 2], + [2, 2, 1, 2, 1, 3], [2, 2, 1, 3, 1, 2], // 10 + [2, 3, 1, 2, 1, 2], [1, 1, 2, 2, 3, 2], [1, 2, 2, 1, 3, 2], + [1, 2, 2, 2, 3, 1], [1, 1, 3, 2, 2, 2], // 15 + [1, 2, 3, 1, 2, 2], [1, 2, 3, 2, 2, 1], [2, 2, 3, 2, 1, 1], + [2, 2, 1, 1, 3, 2], [2, 2, 1, 2, 3, 1], // 20 + [2, 1, 3, 2, 1, 2], [2, 2, 3, 1, 1, 2], [3, 1, 2, 1, 3, 1], + [3, 1, 1, 2, 2, 2], [3, 2, 1, 1, 2, 2], // 25 + [3, 2, 1, 2, 2, 1], [3, 1, 2, 2, 1, 2], [3, 2, 2, 1, 1, 2], + [3, 2, 2, 2, 1, 1], [2, 1, 2, 1, 2, 3], // 30 + [2, 1, 2, 3, 2, 1], [2, 3, 2, 1, 2, 1], [1, 1, 1, 3, 2, 3], + [1, 3, 1, 1, 2, 3], [1, 3, 1, 3, 2, 1], // 35 + [1, 1, 2, 3, 1, 3], [1, 3, 2, 1, 1, 3], [1, 3, 2, 3, 1, 1], + [2, 1, 1, 3, 1, 3], [2, 3, 1, 1, 1, 3], // 40 + [2, 3, 1, 3, 1, 1], [1, 1, 2, 1, 3, 3], [1, 1, 2, 3, 3, 1], + [1, 3, 2, 1, 3, 1], [1, 1, 3, 1, 2, 3], // 45 + [1, 1, 3, 3, 2, 1], [1, 3, 3, 1, 2, 1], [3, 1, 3, 1, 2, 1], + [2, 1, 1, 3, 3, 1], [2, 3, 1, 1, 3, 1], // 50 + [2, 1, 3, 1, 1, 3], [2, 1, 3, 3, 1, 1], [2, 1, 3, 1, 3, 1], + [3, 1, 1, 1, 2, 3], [3, 1, 1, 3, 2, 1], // 55 + [3, 3, 1, 1, 2, 1], [3, 1, 2, 1, 1, 3], [3, 1, 2, 3, 1, 1], + [3, 3, 2, 1, 1, 1], [3, 1, 4, 1, 1, 1], // 60 + [2, 2, 1, 4, 1, 1], [4, 3, 1, 1, 1, 1], [1, 1, 1, 2, 2, 4], + [1, 1, 1, 4, 2, 2], [1, 2, 1, 1, 2, 4], // 65 + [1, 2, 1, 4, 2, 1], [1, 4, 1, 1, 2, 2], [1, 4, 1, 2, 2, 1], + [1, 1, 2, 2, 1, 4], [1, 1, 2, 4, 1, 2], // 70 + [1, 2, 2, 1, 1, 4], [1, 2, 2, 4, 1, 1], [1, 4, 2, 1, 1, 2], + [1, 4, 2, 2, 1, 1], [2, 4, 1, 2, 1, 1], // 75 + [2, 2, 1, 1, 1, 4], [4, 1, 3, 1, 1, 1], [2, 4, 1, 1, 1, 2], + [1, 3, 4, 1, 1, 1], [1, 1, 1, 2, 4, 2], // 80 + [1, 2, 1, 1, 4, 2], [1, 2, 1, 2, 4, 1], [1, 1, 4, 2, 1, 2], + [1, 2, 4, 1, 1, 2], [1, 2, 4, 2, 1, 1], // 85 + [4, 1, 1, 2, 1, 2], [4, 2, 1, 1, 1, 2], [4, 2, 1, 2, 1, 1], + [2, 1, 2, 1, 4, 1], [2, 1, 4, 1, 2, 1], // 90 + [4, 1, 2, 1, 2, 1], [1, 1, 1, 1, 4, 3], [1, 1, 1, 3, 4, 1], + [1, 3, 1, 1, 4, 1], [1, 1, 4, 1, 1, 3], // 95 + [1, 1, 4, 3, 1, 1], [4, 1, 1, 1, 1, 3], [4, 1, 1, 3, 1, 1], + [1, 1, 3, 1, 4, 1], [1, 1, 4, 1, 3, 1], // 100 + [3, 1, 1, 1, 4, 1], [4, 1, 1, 1, 3, 1], [2, 1, 1, 4, 1, 2], + [2, 1, 1, 2, 1, 4], [2, 1, 1, 2, 3, 2], // 105 + [2, 3, 3, 1, 1, 1, 2]]; + + MAX_AVG_VARIANCE := Floor(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25); + MAX_INDIVIDUAL_VARIANCE := Floor(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7); + +end; + +class function TCode128Reader.FindStartPattern(row: IBitArray): TArray; +var + i, bestMatch, startCode, bestVariance, width, rowOffset, patternStart, + patternLength, variance, counterPosition: Integer; + counters: TArray; + isWhite: Boolean; + +begin + width := row.Size; + rowOffset := row.getNextSet(0); + counterPosition := 0; + counters := TArray.Create(); + SetLength(counters, 6); + patternStart := rowOffset; + isWhite := false; + patternLength := Length(counters); + + for i := rowOffset to width - 1 do + begin + + if row[i] xor isWhite then + begin + inc(counters[counterPosition]) + end + else + begin + if counterPosition = patternLength - 1 then + begin + bestVariance := MAX_AVG_VARIANCE; + bestMatch := -1; + + startCode := CODE_START_A; + while startCode <= CODE_START_C do + begin + + variance := patternMatchVariance(counters, CODE_PATTERNS[startCode], + MAX_INDIVIDUAL_VARIANCE); + + if variance < bestVariance then + begin + bestVariance := variance; + bestMatch := startCode + end; + + inc(startCode); + end; + + if bestMatch >= 0 then + begin + // Look for whitespace before start pattern, >= 50% of width of start pattern + if row.isRange(Max(0, patternStart - (i - patternStart) div 2), + patternStart, false) then + begin + result := [patternStart, i, bestMatch]; + exit; + end + end; + + patternStart := patternStart + counters[0] + counters[1]; + + // Array.Copy(counters, 2, counters, 0, patternLength - 2); + // source, source index, dest, dest index, lengte + + counters := TArray.CopyInSameArray(counters, 2, patternLength - 2); + counters[patternLength - 2] := 0; + counters[patternLength - 1] := 0; + + dec(counterPosition); + end + else + begin + inc(counterPosition); + end; + + counters[counterPosition] := 1; + isWhite := not isWhite + end; + + end; + + result := nil; + +end; + +class function TCode128Reader.DecodeCode(row: IBitArray; + counters: TArray; rowOffset: Integer; var code: Integer): Boolean; +var + bestVariance, l, d, variance: Integer; + pattern: TArray; +begin + + code := -1; + if not recordPattern(row, rowOffset, counters) then + begin + result := false; + exit; + end; + + bestVariance := MAX_AVG_VARIANCE; + + // worst variance we'll accept + l := Length(CODE_PATTERNS) - 1; + for d := 0 to l do + begin + pattern := CODE_PATTERNS[d]; + variance := patternMatchVariance(counters, pattern, + MAX_INDIVIDUAL_VARIANCE); + if variance < bestVariance then + begin + bestVariance := variance; + code := d + end; + end; + + // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6. + result := code >= 0; +end; + +function TCode128Reader.decodeRow(const rowNumber: Integer; + const row: IBitArray; const hints: TDictionary) + : TReadResult; +var + shiftUpperMode, upperMode, lastCharacterWasPrintable, convertFNC1, done, + unshift, isNextShifted: Boolean; + counters, startPatternInfo: TArray; + lastPatternSize, multiplier, checksumTotal, code, lastCode, nextStart, + lastStart, startCode, codeSet, l, rawCodesSize: Integer; + rawCodes: TList; + rawBytes: TArray; + aResult: String; + counter, resultLength, i: Integer; + left, right: Single; + resultPointCallback: TResultPointCallback; + obj: TObject; + resultPoints: TArray; + resultPointLeft, resultPointRight: IResultPoint; +begin + convertFNC1 := (hints <> nil) and + (hints.ContainsKey(ZXing.DecodeHintType.ASSUME_GS1)); + + startPatternInfo := FindStartPattern(row); + if (startPatternInfo = nil) then + begin + result := nil; + exit; + end; + + startCode := startPatternInfo[2]; + + rawCodes := TList.Create(); + + try + + rawCodes.Add(Byte(startCode)); + + case startCode of + CODE_START_A: + begin + codeSet := CODE_CODE_A; + end; + CODE_START_B: + begin + codeSet := CODE_CODE_B; + end; + CODE_START_C: + begin + codeSet := CODE_CODE_C; + end + else + result := nil; + exit; + end; + + done := false; + isNextShifted := false; + lastStart := startPatternInfo[0]; + nextStart := startPatternInfo[1]; + SetLength(counters, 6); + lastCode := 0; + code := 0; + checksumTotal := startCode; + multiplier := 0; + lastCharacterWasPrintable := true; + upperMode := false; + shiftUpperMode := false; + + while not done do + begin + + unshift := isNextShifted; + isNextShifted := false; + + // Save off last code + lastCode := code; + + // Decode another code from image + if not DecodeCode(row, counters, nextStart, code) then + begin + result := nil; + exit; + end; + + rawCodes.Add(Byte(code)); + + // Remember whether the last code was printable or not (excluding CODE_STOP) + if code <> CODE_STOP then + begin + lastCharacterWasPrintable := true + end; + + // Add to checksum computation (if not CODE_STOP of course) + if code <> CODE_STOP then + begin + inc(multiplier); + checksumTotal := checksumTotal + (multiplier * code); + end; + + // Advance to where the next code will to start + lastStart := nextStart; + l := Length(counters) - 1; + for counter := 0 to l do + begin + nextStart := nextStart + counters[counter]; + end; + + // Take care of illegal start codes + case code of + CODE_START_A, CODE_START_B, CODE_START_C: + begin + result := nil; + exit; + end; + end; + + case codeSet of + + CODE_CODE_A: + begin + if code < 64 then + begin + if shiftUpperMode = upperMode then + begin + aResult := aResult + Char(32 + code); + end + else + begin + aResult := aResult + Char(32 + 128) + end; + shiftUpperMode := false + end + else if code < 96 then + begin + if shiftUpperMode = upperMode then + begin + aResult := aResult + Char(code - 64) + end + else + begin + aResult := aResult + Char(code + 64) + end; + shiftUpperMode := false + end + else + begin + // Don't let CODE_STOP, which always appears, affect whether whether we think the last + // code was printable or not. + if code <> CODE_STOP then + begin + lastCharacterWasPrintable := false + end; + case code of + CODE_FNC_1: + begin + if convertFNC1 then + begin + if Length(aResult) = 0 then + begin + // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code + // is FNC1 then this is GS1-128. We add the symbology identifier. + aResult := aResult + ']C1' + end + else + begin + // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) + aResult := aResult + Char(29) + end + end; + end; + CODE_FNC_2, CODE_FNC_3: + begin + + // do nothing? + end; + CODE_FNC_4_A: + begin + if (not upperMode) and (shiftUpperMode) then + begin + upperMode := true; + shiftUpperMode := false + end + else if (upperMode) and (shiftUpperMode) then + begin + upperMode := false; + shiftUpperMode := false + end + else + begin + shiftUpperMode := true + end; + end; + CODE_SHIFT: + begin + isNextShifted := true; + codeSet := CODE_CODE_B; + end; + CODE_CODE_B: + begin + codeSet := CODE_CODE_B; + end; + CODE_CODE_C: + begin + codeSet := CODE_CODE_C; + end; + CODE_STOP: + begin + done := true; + end; + end + end; + end; + CODE_CODE_B: + begin + if code < 96 then + begin + if shiftUpperMode = upperMode then + begin + aResult := aResult + Char(32 + code) + end + else + begin + aResult := aResult + Char(32 + code + 128) + end; + shiftUpperMode := false + end + else + begin + if code <> CODE_STOP then + begin + lastCharacterWasPrintable := false + end; + case code of + CODE_FNC_1: + begin + if convertFNC1 then + begin + if Length(aResult) = 0 then + begin + // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code + // is FNC1 then this is GS1-128. We add the symbology identifier. + aResult := aResult + (']C1') + end + else + begin + // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) + aResult := aResult + Char(29) + end + end; + end; + CODE_FNC_2, CODE_FNC_3: + begin + // do nothing? + end; + CODE_FNC_4_B: + begin + if (not upperMode) and (shiftUpperMode) then + begin + upperMode := true; + shiftUpperMode := false + end + else if (upperMode) and (shiftUpperMode) then + begin + upperMode := false; + shiftUpperMode := false + end + else + begin + shiftUpperMode := true + end; + end; + CODE_SHIFT: + begin + isNextShifted := true; + codeSet := CODE_CODE_A; + end; + CODE_CODE_A: + begin + codeSet := CODE_CODE_A; + end; + CODE_CODE_C: + begin + codeSet := CODE_CODE_C; + end; + CODE_STOP: + begin + done := true; + end; + end + end; + end; + CODE_CODE_C: + begin + if code < 100 then + begin + if code < 10 then + begin + aResult := aResult + ('0') + end; + aResult := aResult + IntToStr(code); + end + else + begin + if code <> CODE_STOP then + begin + lastCharacterWasPrintable := false + end; + case code of + CODE_FNC_1: + begin + if convertFNC1 then + begin + if Length(aResult) = 0 then + begin + // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code + // is FNC1 then this is GS1-128. We add the symbology identifier. + aResult := aResult + (']C1') + end + else + begin + // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) + aResult := aResult + Char(29) + end + end; + end; + CODE_CODE_A: + begin + codeSet := CODE_CODE_A; + end; + CODE_CODE_B: + begin + codeSet := CODE_CODE_B; + end; + CODE_STOP: + begin + done := true; + end; + end + end; + end; + end; + + // Unshift back to another code set if we were shifted + if (unshift) then + begin + if (codeSet = CODE_CODE_A) then + codeSet := CODE_CODE_B + else + codeSet := CODE_CODE_A; + end; + end; + + lastPatternSize := nextStart - lastStart; + + // Check for ample whitespace following pattern, but, to do this we first need to remember that + // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left + // to read off. Would be slightly better to properly read. Here we just skip it: + nextStart := row.getNextUnset(nextStart); + if not row.isRange(nextStart, System.Math.Min(row.Size, + nextStart + (nextStart - lastStart) div 2), false) then + begin + result := nil; + exit; + end; + + // Pull out from sum the value of the penultimate check code + checksumTotal := checksumTotal - (multiplier * lastCode); + // lastCode is the checksum then: + if checksumTotal mod 103 <> lastCode then + begin + result := nil; + exit; + end; + + // Need to pull out the check digits from string + resultLength := Length(aResult); + if resultLength = 0 then + begin + // false positive + result := nil; + exit; + end; + + // Only bother if the result had at least one character, and if the checksum digit happened to + // be a printable character. If it was just interpreted as a control code, nothing to remove. + if (resultLength > 0) and (lastCharacterWasPrintable) then + begin + if codeSet = CODE_CODE_C then + begin + aResult := aResult.Remove(resultLength - 2, 2); + end + else + begin + aResult := aResult.Remove(resultLength - 1, 1); + end + end; + + left := (startPatternInfo[1] + startPatternInfo[0]) / 2; + right := lastStart + lastPatternSize / 2; + + rawCodesSize := rawCodes.Count; + SetLength(rawBytes, rawCodesSize); + + for i := 0 to rawCodesSize - 1 do + rawBytes[i] := rawCodes[i]; + + resultPointLeft := TResultPointHelpers.CreateResultPoint(left, rowNumber); + resultPointRight := TResultPointHelpers.CreateResultPoint(right, rowNumber); + resultPoints := [resultPointLeft, resultPointRight]; + + resultPointCallback := nil; + // had to add this initialization because the following if/else construct does not assign a value + // for all possible cases. Being resultPointCallback a local variable it is not initialized by default to null, + // so you could get unpredictable results + + if ((hints = nil) or + (not hints.ContainsKey(TDecodeHintType.NEED_RESULT_POINT_CALLBACK))) then + resultPointCallback := nil + else + begin + obj := hints[TDecodeHintType.NEED_RESULT_POINT_CALLBACK]; + if (obj is TResultPointEventObject) then + resultPointCallback := TResultPointEventObject(obj).Event; + end; + + if Assigned(resultPointCallback) then + begin + resultPointCallback(resultPointLeft); + resultPointCallback(resultPointRight); + end; + finally + FreeAndNil(rawCodes); + end; + + result := TReadResult.Create(aResult, rawBytes, resultPoints, + TBarcodeFormat.CODE_128); +end; + +initialization + +TCode128Reader.DoInitialize; + +finalization + +TCode128Reader.DoFinalize; + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code39Reader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code39Reader.pas new file mode 100644 index 0000000..5ff3ce4 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code39Reader.pas @@ -0,0 +1,471 @@ +unit ZXing.OneD.Code39Reader; +{ + * 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 Authors: Sean Owen + * Implemented by Nano103 and E. Spelt for Delphi +} + +interface + +uses + System.SysUtils, + System.Generics.Collections, + Math, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat, + ZXing.Common.Detector.MathUtils; + +type + + TCode39Reader = class sealed(TOneDReader) + + private + class var ALPHABET: TArray; + class function decodeExtended(encoded: string): string; static; + + function findAsteriskPattern(row: IBitArray): TArray; + class function patternToChar(pattern: Integer; var c: Char) + : boolean; static; + class function toNarrowWidePattern(counters: TArray) + : Integer; static; + + const + ALPHABET_STRING: string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%'; + class var ASTERISK_ENCODING: Integer; + + class var + CHARACTER_ENCODINGS: TArray; + counters: TArray; + decodeRowResult: TStringBuilder; + usingCheckDigit: boolean; + extendedMode: boolean; + public + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; + override; + + constructor Create(AUsingCheckDigit, AExtendedMode: boolean); + destructor Destroy(); override; + + end; + +implementation + +{ Code93Reader } + +constructor TCode39Reader.Create(AUsingCheckDigit, AExtendedMode: boolean); +begin + ALPHABET := ALPHABET_STRING.ToCharArray; + CHARACTER_ENCODINGS := TArray.Create($034, $121, $061, $160, $031, + $130, $070, $025, $124, $064, // 0-9 + $109, $049, $148, $019, $118, $058, $00D, $10C, $04C, $01C, // A-J + $103, $043, $142, $013, $112, $052, $007, $106, $046, $016, // K-T + $181, $0C1, $1C0, $091, $190, $0D0, $085, $184, $0C4, $094, // U-* + $0A8, $0A2, $08A, $02A // $-% + ); + + ASTERISK_ENCODING := TCode39Reader.CHARACTER_ENCODINGS[$27]; + + counters := TArray.Create(); + SetLength(counters, 9); + decodeRowResult := TStringBuilder.Create(); + usingCheckDigit := AUsingCheckDigit; + extendedMode := AExtendedMode; + +end; + +destructor TCode39Reader.Destroy; +begin + ALPHABET := nil; + CHARACTER_ENCODINGS := nil; + counters := nil; + FreeAndNil(decodeRowResult); + inherited; +end; + +class function TCode39Reader.decodeExtended(encoded: string): string; +var + next, c, decodedChar: Char; + length, i: Integer; + decoded: TStringBuilder; + +begin + length := encoded.length; + decoded := TStringBuilder.Create(length); + try + + i := 0; + while i < length do + begin + c := encoded.Chars[i]; + if (((c = '+') or (c = '$')) or ((c = '%') or (c = '/'))) then + begin + if ((i + 1) >= encoded.length) then + begin + Result := ''; + exit + end; + next := encoded.Chars[(i + 1)]; + decodedChar := Char(#0); + case c of + '+': + begin + if ((next >= 'A') and (next <= 'Z')) then + begin + decodedChar := Char(ord(next) + 32); + end + else + begin + exit(''); + end + end; + '$': + begin + if ((next >= 'A') and (next <= 'Z')) then + begin + decodedChar := Char(ord(next) - 64); + end + else + begin + exit(''); + end + end; + '%': + begin + if ((next >= 'A') and (next <= 'E')) then + decodedChar := Char(ord(next) - 38) + else if ((next >= 'F') and (next <= 'W')) then + decodedChar := Char(ord(next) - 11) + else + begin + exit(''); + end; + + end; + '/': + begin + if ((next >= 'A') and (next <= 'O')) then + begin + decodedChar := Char(ord(next) - 32); + end + else if (next = 'Z') then + begin + decodedChar := ':'; + end + else + exit(''); + end; + + end; + + decoded.Append(decodedChar); + Inc(i); + end + else + decoded.Append(c); + + Inc(i); + end; // end loop/while + + Result := decoded.ToString; + finally + decoded.Free; + end; + +end; + +function TCode39Reader.decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; +var + decodedChar: Char; + lastStart: Integer; + index, nextStart, counter, aEnd, pattern, lastPatternSize: Integer; + start: TArray; + resultString: String; + Left, Right: Single; + resultPoints: TArray; + resultPointLeft, resultPointRight: IResultPoint; + whiteSpaceAfterEnd: Integer; + i, max, total: Integer; +begin + for index := 0 to length(counters) - 1 do + begin + counters[index] := 0; + end; + + decodeRowResult.length := 0; + + start := self.findAsteriskPattern(row); + if (start = nil) then + begin + Result := nil; + exit + end; + nextStart := row.getNextSet(start[1]); + aEnd := row.Size; + repeat + if (not TOneDReader.recordPattern(row, nextStart, self.counters)) then + begin + Result := nil; + exit + end; + + pattern := TCode39Reader.toNarrowWidePattern(self.counters); + if (pattern < 0) then + begin + Result := nil; + exit + end; + + if (not TCode39Reader.patternToChar(pattern, decodedChar)) then + begin + Result := nil; + exit + end; + + self.decodeRowResult.Append(decodedChar); + lastStart := nextStart; + + for counter in self.counters do + begin + Inc(nextStart, counter) + end; + + nextStart := row.getNextSet(nextStart) + + until (decodedChar = '*'); + + self.decodeRowResult.Remove((self.decodeRowResult.length - 1), 1); + + lastPatternSize := 0; + + for counter in self.counters do + begin + Inc(lastPatternSize, counter) + end; + + whiteSpaceAfterEnd := nextStart - lastStart - lastPatternSize; + + if (nextStart <> aEnd) and ((whiteSpaceAfterEnd shl 1) < lastPatternSize) then + begin + Result := nil; + exit + end; + + if (usingCheckDigit) then + begin + max := self.decodeRowResult.length - 1; + total := 0; + for i := 0 to max - 1 do + begin + Inc(total, ALPHABET_STRING.indexOf(decodeRowResult.Chars[i])); + end; + + if (self.decodeRowResult.Chars[max] <> ALPHABET_STRING[total mod 43]) then + begin + Result := nil; + exit + end; + + self.decodeRowResult.Remove(max, self.decodeRowResult.length); + end; + + if (self.decodeRowResult.length = 0) then + begin + Result := nil; + exit + end; + + if extendedMode then + resultString := TCode39Reader.decodeExtended + (self.decodeRowResult.ToString()) + else + resultString := decodeRowResult.ToString(); + + if (resultString = '') then + begin + Result := nil; + exit + end; + + Left := (start[1] + start[0]) / 2; + Right := lastStart + (lastPatternSize / 2); + + resultPointLeft := TResultPointHelpers.CreateResultPoint(Left, rowNumber); + resultPointRight := TResultPointHelpers.CreateResultPoint(Right, rowNumber); + resultPoints := [resultPointLeft, resultPointRight]; + + Result := TReadResult.Create(resultString, nil, resultPoints, + TBarcodeFormat.CODE_39); + +end; + +function TCode39Reader.findAsteriskPattern(row: IBitArray): TArray; +var + i, l, patternStart, patternLength, width, counterPosition, rowOffset, + index: Integer; + isWhite: boolean; + +begin + width := row.Size; + rowOffset := row.getNextSet(0); + index := 0; + while (index < length(self.counters)) do + begin + self.counters[index] := 0; + Inc(index) + end; + + counterPosition := 0; + patternStart := rowOffset; + isWhite := False; + patternLength := length(counters); + + for i := rowOffset to width - 1 do + begin + + if (row[i] xor isWhite) then + begin + Inc(counters[counterPosition]) + end + else + begin + if (counterPosition = (patternLength - 1)) then + begin + + if (TCode39Reader.toNarrowWidePattern(counters) + = TCode39Reader.ASTERISK_ENCODING) then + begin + Result := TArray.Create(patternStart, i); + exit + end; + + Inc(patternStart, (counters[0] + counters[1])); + + for l := 2 to patternLength - 2 do + begin + counters[l - 2] := counters[l]; + end; + + counters[(patternLength - 2)] := 0; + counters[(patternLength - 1)] := 0; + dec(counterPosition) + + end + else + Inc(counterPosition); + + counters[counterPosition] := 1; + isWhite := not isWhite + end; + end; + + Result := nil; + +end; + +class function TCode39Reader.patternToChar(pattern: Integer; + var c: Char): boolean; +var + i: Integer; +begin + i := 0; + while (i < length(TCode39Reader.CHARACTER_ENCODINGS)) do + begin + if (TCode39Reader.CHARACTER_ENCODINGS[i] = pattern) then + begin + c := TCode39Reader.ALPHABET[i]; + begin + Result := true; + exit + end + end; + Inc(i) + end; + c := '*'; + Result := False; +end; + +class function TCode39Reader.toNarrowWidePattern + (counters: TArray): Integer; +var + numCounters: Integer; + maxNarrowCounter: Integer; + wideCounters: Integer; + minCounter: Integer; + counter: Integer; + totalWideCountersWidth: Integer; + pattern: Integer; + i: Integer; +begin + numCounters := length(counters); + maxNarrowCounter := 0; + + repeat + minCounter := High(Integer); + for counter in counters do + begin + if (counter < minCounter) and (counter > maxNarrowCounter) then + minCounter := counter; + end; + + maxNarrowCounter := minCounter; + wideCounters := 0; + totalWideCountersWidth := 0; + pattern := 0; + for i := 0 to numCounters - 1 do + begin + counter := counters[i]; + if (counter > maxNarrowCounter) then + begin + pattern := pattern or (1 shl (numCounters - 1 - i)); + Inc(wideCounters); + Inc(totalWideCountersWidth, counter); + end; + end; + if (wideCounters = 3) then + begin + // Found 3 wide counters, but are they close enough in width? + // We can perform a cheap, conservative check to see if any individual + // counter is more than 1.5 times the average: + i := 0; + while (i < numCounters) and (wideCounters > 0) do + begin + counter := counters[i]; + if (counter > maxNarrowCounter) then + begin + dec(wideCounters); + // totalWideCountersWidth = 3 * average, so this checks if counter >= 3/2 * average + if ((counter * 2) >= totalWideCountersWidth) then + begin + Result := -1; + exit; + end; + end; + Inc(i); + end; + Result := pattern; + exit; + end; + until (wideCounters <= 3); + Result := -1; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code93Reader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code93Reader.pas new file mode 100644 index 0000000..4e3d98e --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.Code93Reader.pas @@ -0,0 +1,523 @@ +{ + * Copyright 2010 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 Authors: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.OneD.Code93Reader; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + Math, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat, + ZXing.Common.Detector.MathUtils; + +type + /// + ///

Decodes Code 93 barcodes.

+ /// + ///
+ TCode93Reader = class sealed(TOneDReader) + private + class var ALPHABET: TArray; + class function checkChecksums(pResult: TStringBuilder): boolean; static; + class function checkOneChecksum(pResult: TStringBuilder; + checkPosition, weightMax: Integer): boolean; + class function decodeExtended(encoded: TStringBuilder): string; static; + + function findAsteriskPattern(row: IBitArray): TArray; + class function patternToChar(pattern: Integer; var c: Char) + : boolean; static; + class function toPattern(counters: TArray): Integer; static; + + const + ALPHABET_STRING + : string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*'; + class var ASTERISK_ENCODING: Integer; + + class var + CHARACTER_ENCODINGS: TArray; + counters: TArray; + decodeRowResult: TStringBuilder; + + public + constructor Create; + destructor Destroy; override; + + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; + override; + end; + +implementation + +{ Code93Reader } + +constructor TCode93Reader.Create; +begin + ALPHABET := '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*'.ToCharArray; + CHARACTER_ENCODINGS := TArray.Create($114, $148, $144, $142, $128, + $124, 290, $150, $112, $10A, $1A8, 420, $1A2, $194, $192, $18A, 360, $164, + $162, $134, $11A, $158, $14C, $146, 300, $116, $1B4, $1B2, $1AC, $1A6, $196, + 410, $16C, $166, 310, $13A, $12E, $1D4, $1D2, $1CA, $16E, $176, 430, $126, + $1DA, 470, $132, 350); + + ASTERISK_ENCODING := TCode93Reader.CHARACTER_ENCODINGS[$2F]; + + counters := TArray.Create(); + SetLength(counters, 6); + decodeRowResult := TStringBuilder.Create(); +end; + +destructor TCode93Reader.Destroy; +begin + ALPHABET := nil; + CHARACTER_ENCODINGS := nil; + counters := nil; + FreeAndNil(decodeRowResult); + inherited; +end; + +class function TCode93Reader.checkChecksums(pResult: TStringBuilder): boolean; +var + length: Integer; +begin + length := pResult.length; + if (not TCode93Reader.checkOneChecksum(pResult, (length - 2), 20)) then + begin + Result := false; + exit + end; + if (not TCode93Reader.checkOneChecksum(pResult, (length - 1), 15)) then + begin + Result := false; + exit + end; + begin + Result := true; + exit + end +end; + +class function TCode93Reader.checkOneChecksum(pResult: TStringBuilder; + checkPosition, weightMax: Integer): boolean; +var + weight, total, i: Integer; +begin + weight := 1; + total := 0; + i := (checkPosition - 1); + while ((i >= 0)) do + begin + + inc(total, (weight * ALPHABET_STRING.IndexOf(pResult.Chars[i]))); + + inc(weight); + + if (weight > weightMax) then + weight := 1; + + dec(i) + end; + + if (pResult.Chars[checkPosition] <> TCode93Reader.ALPHABET[(total mod $2F)]) + then + begin + Result := false; + exit + end; + begin + Result := true; + exit + end +end; + +class function TCode93Reader.decodeExtended(encoded: TStringBuilder): string; +var + next, c: Char; + decodedChar: Char; + length, i: Integer; + decoded: TStringBuilder; + +label Label_0179, Label_0169, Label_014A; + +begin + length := encoded.length; + decoded := TStringBuilder.Create(length); + try + i := 0; + next := Char(0); + while ((i < length)) do + begin + + c := encoded.Chars[i]; + + if ((c < 'a') or (c > 'd')) then + goto Label_0179; + + if (i < (length - 1)) then + begin + + next := encoded.Chars[(i + 1)]; + decodedChar := #0; + + case c of + 'a': + begin + if ((next < 'A') or (next > 'Z')) then + begin + Result := ''; + exit + end; + decodedChar := Char(ord(next) - ord('@')); + goto Label_0169 + end; + 'b': + begin + if ((next < 'A') or (next > 'E')) then + break;; + decodedChar := Char(ord(next) - ord('&')); + goto Label_0169 + end; + 'c': + begin + if ((next < 'A') or (next > 'O')) then + goto Label_014A; + decodedChar := Char(ord(next) - ord(' ')); + goto Label_0169 + end; + 'd': + begin + if ((next < 'A') or (next > 'Z')) then + begin + Result := ''; + exit + end; + decodedChar := Char(ord(next) + ord(' ')); + goto Label_0169 + end; + else + begin + goto Label_0169 + end; + end; + if ((next >= 'F') and (next <= 'W')) then + begin + decodedChar := Char(ord(next) - ord(' ')); + goto Label_0169 + end + end; + begin + Result := ''; + exit + end; + + Label_014A: + if (next = 'Z') then + decodedChar := ':' + else + begin + Result := ''; + exit + end; + + Label_0169: + decoded.Append(decodedChar); + inc(i); + continue; + + Label_0179: + decoded.Append(c); + inc(i) + end; + + Result := decoded.ToString; + + finally + FreeAndNil(decoded); + end; + +end; + +function TCode93Reader.decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; +var + decodedChar: Char; + lastStart: Integer; + index, nextStart, counter, aEnd, pattern, lastPatternSize: Integer; + start: TArray; + resultString: String; + Left, Right: Single; + resultPointCallback: TResultPointCallback; + obj: TObject; + resultPoints: TArray; + resultPointLeft, resultPointRight: IResultPoint; +begin + for index := 0 to length(counters) - 1 do + counters[index] := 0; + + decodeRowResult.length := 0; + + start := self.findAsteriskPattern(row); + if (start = nil) then + begin + Result := nil; + exit + end; + nextStart := row.getNextSet(start[1]); + aEnd := row.Size; + repeat + if (not TOneDReader.recordPattern(row, nextStart, self.counters)) then + begin + Result := nil; + exit + end; + pattern := TCode93Reader.toPattern(self.counters); + if (pattern < 0) then + begin + Result := nil; + exit + end; + if (not TCode93Reader.patternToChar(pattern, decodedChar)) then + begin + Result := nil; + exit + end; + + self.decodeRowResult.Append(decodedChar); + lastStart := nextStart; + + for counter in self.counters do + begin + inc(nextStart, counter) + end; + nextStart := row.getNextSet(nextStart) + + until (decodedChar = '*'); + + self.decodeRowResult.Remove((self.decodeRowResult.length - 1), 1); + + lastPatternSize := 0; + + for counter in self.counters do + begin + inc(lastPatternSize, counter) + end; + + if (not((nextStart <> aEnd) and row[nextStart])) then + begin + Result := nil; + exit + end; + + if (self.decodeRowResult.length < 2) then + begin + Result := nil; + exit + end; + + if (not TCode93Reader.checkChecksums(self.decodeRowResult)) then + begin + Result := nil; + exit + end; + + self.decodeRowResult.length := self.decodeRowResult.length - 2; + + resultString := TCode93Reader.decodeExtended(self.decodeRowResult); + if (resultString = '') then + begin + Result := nil; + exit + end; + + Left := (start[1] + start[0]) div 2; + Right := (lastStart + lastPatternSize) / 2; + + resultPointLeft := TResultPointHelpers.CreateResultPoint(Left, rowNumber); + resultPointRight := TResultPointHelpers.CreateResultPoint(Right, rowNumber); + resultPoints := [resultPointLeft, resultPointRight]; + + resultPointCallback := nil; + // it is a local variable: it doesn't get NIL as default value, and the following ifs do not assign a value for all possible cases + + if ((hints = nil) or + (not hints.ContainsKey(TDecodeHintType.NEED_RESULT_POINT_CALLBACK))) then + resultPointCallback := nil + else + begin + obj := hints[TDecodeHintType.NEED_RESULT_POINT_CALLBACK]; + if (obj is TResultPointEventObject) then + resultPointCallback := TResultPointEventObject(obj).Event; + end; + + if Assigned(resultPointCallback) then + begin + resultPointCallback(resultPointLeft); + resultPointCallback(resultPointRight); + end; + + Result := TReadResult.Create(resultString, nil, resultPoints, + TBarcodeFormat.CODE_93); +end; + +function TCode93Reader.findAsteriskPattern(row: IBitArray): TArray; +var + i, l, patternStart, patternLength, width, counterPosition, rowOffset, + index: Integer; + isWhite: boolean; + +begin + width := row.Size; + rowOffset := row.getNextSet(0); + index := 0; + while (index < length(self.counters)) do + begin + self.counters[index] := 0; + inc(index) + end; + + counterPosition := 0; + patternStart := rowOffset; + isWhite := false; + patternLength := length(counters); + + for i := rowOffset to width - 1 do + begin + + if (row[i] xor isWhite) then + begin + inc(counters[counterPosition]) + end + else + begin + if (counterPosition = (patternLength - 1)) then + begin + + if (TCode93Reader.toPattern(counters) = TCode93Reader.ASTERISK_ENCODING) + then + begin + Result := TArray.Create(patternStart, i); + exit + end; + + inc(patternStart, (counters[0] + counters[1])); + + for l := 2 to patternLength - 2 do + begin + counters[l - 2] := counters[l]; + end; + + counters[(patternLength - 2)] := 0; + counters[(patternLength - 1)] := 0; + dec(counterPosition) + + end + else + inc(counterPosition); + + counters[counterPosition] := 1; + isWhite := not isWhite + end; + end; + + Result := nil; + +end; + +class function TCode93Reader.patternToChar(pattern: Integer; + var c: Char): boolean; +var + i: Integer; +begin + i := 0; + while (i < length(TCode93Reader.CHARACTER_ENCODINGS)) do + begin + if (TCode93Reader.CHARACTER_ENCODINGS[i] = pattern) then + begin + c := TCode93Reader.ALPHABET[i]; + begin + Result := true; + exit + end + end; + inc(i) + end; + c := '*'; + Result := false; +end; + +class function TCode93Reader.toPattern(counters: TArray): Integer; +var + counter, max, sum, pattern, i, j, scaledShifted, scaledUnshifted: Integer; +begin + max := length(counters); + sum := 0; + + for counter in counters do + begin + inc(sum, counter) + end; + + pattern := 0; + i := 0; + while ((i < max)) do + begin + + scaledShifted := (((counters[i] shl TOneDReader.INTEGER_MATH_SHIFT) * + 9) div sum); + + scaledUnshifted := TMathUtils.Asr(scaledShifted, + TOneDReader.INTEGER_MATH_SHIFT); + + if ((scaledShifted and $FF) > $7F) then + inc(scaledUnshifted); + + if ((scaledUnshifted < 1) or (scaledUnshifted > 4)) then + begin + Result := -1; + exit + end; + + if ((i and 1) = 0) then + begin + j := 0; + + while ((j < scaledUnshifted)) do + begin + pattern := ((pattern shl 1) or 1); + inc(j) + end + end + else + pattern := (pattern shl scaledUnshifted); + + inc(i) + end; + + Result := pattern; + +end; + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EAN13Reader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EAN13Reader.pas new file mode 100644 index 0000000..25c8410 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EAN13Reader.pas @@ -0,0 +1,219 @@ +{ + * 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 Authors: dswitkin@google.com (Daniel Switkin), Sean Owen and + * alasdair@google.com (Alasdair Mackintosh) + * Delphi Implementation by K. Gossens, E. Spelt +} + +unit ZXing.OneD.EAN13Reader; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + System.Math, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.OneD.UPCEANReader, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat; + +type + /// + ///

Implements decoding of the EAN-13 format.

+ ///
+ TEAN13Reader = class(TUPCEANReader) + private + // For an EAN-13 barcode, the first digit is represented by the parities used + // to encode the next six digits, according to the table below. For example, + // if the barcode is 5 123456 789012 then the value of the first digit is + // signified by using odd for '1', even for '2', even for '3', odd for '4', + // odd for '5', and even for '6'. See http://en.wikipedia.org/wiki/EAN-13 + // + // Parity of next 6 digits + // Digit 0 1 2 3 4 5 + // 0 Odd Odd Odd Odd Odd Odd + // 1 Odd Odd Even Odd Even Even + // 2 Odd Odd Even Even Odd Even + // 3 Odd Odd Even Even Even Odd + // 4 Odd Even Odd Odd Even Even + // 5 Odd Even Even Odd Odd Even + // 6 Odd Even Even Even Odd Odd + // 7 Odd Even Odd Even Odd Even + // 8 Odd Even Odd Even Even Odd + // 9 Odd Even Even Odd Even Odd + // + // Note that the encoding for '0' uses the same parity as a UPC barcode. Hence + // a UPC barcode can be converted to an EAN-13 barcode by prepending a 0. + // + // The encoding is represented by the following array, which is a bit pattern + // using Odd = 0 and Even = 1. For example, 5 is represented by: + // + // Odd Even Even Odd Odd Even + // in binary: + // 0 1 1 0 0 1 == 0x19 + // + class var + FIRST_DIGIT_ENCODINGS: TArray; + decodeMiddleCounters: TArray; + + /// + /// Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded + /// digits in a barcode, determines the implicitly encoded first digit and adds it to the + /// result string. + /// + /// string to insert decoded first digit into + /// int whose bits indicates the pattern of odd/even L/G patterns used to + /// encode digits + /// -1 if first digit cannot be determined + class function determineFirstDigit(const resultString: TStringBuilder; + const lgPatternFound: Integer): Boolean; static; + + class procedure InitializeClass; static; + class procedure FinalizeClass; static; + protected + public + + /// + /// Subclasses override this to decode the portion of a barcode between the start + /// and end guard patterns. + /// + /// row of black/white values to search + /// start/end offset of start guard pattern + /// to append decoded chars to + /// + /// horizontal offset of first pixel after the "middle" that was decoded or -1 if decoding could not complete successfully + /// + class function DecodeMiddle(const row: IBitArray; + const startRange: TArray; const resultString: TStringBuilder) + : Integer; override; + + + + /// + /// Get the format of this decoder. + /// The 1D format. + /// + function BarcodeFormat: TBarcodeFormat; override; + end; + +implementation + +{ TEAN13Reader } + +class function TEAN13Reader.DecodeMiddle(const row: IBitArray; + const startRange: TArray; + const resultString: TStringBuilder): Integer; +var + bestMatch: Integer; + counter: Integer; + ending: Integer; + counters, middleRange: TArray; + rowOffset, x, lgPatternFound: 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 < 6) and (rowOffset < ending)) do + begin + if (not decodeDigit(row, counters, rowOffset, 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 (5 - x)); + Inc(x); + end; + + if (not determineFirstDigit(resultString, lgPatternFound)) then + exit; + + middleRange := findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); + if (middleRange = nil) then + exit; + rowOffset := middleRange[1]; + + x := 0; + while ((x < 6) and (rowOffset < ending)) do + begin + if (not decodeDigit(row, counters, rowOffset, L_PATTERNS, bestMatch)) then + exit; + resultString.Append(IntToStr(bestMatch)); + for counter in counters do + Inc(rowOffset, counter); + Inc(x); + end; + + Result := rowOffset; +end; + +function TEAN13Reader.BarcodeFormat: TBarcodeFormat; +begin + Result := TBarcodeFormat.EAN_13; +end; + +class function TEAN13Reader.determineFirstDigit(const resultString + : TStringBuilder; const lgPatternFound: Integer): Boolean; +var + d: Integer; +begin + Result := false; + for d := 0 to Pred(10) do + begin + if (lgPatternFound = FIRST_DIGIT_ENCODINGS[d]) then + begin + resultString.Insert(0, IntToStr(d)); + Result := true; + break; + end; + end; +end; + +class procedure TEAN13Reader.InitializeClass; +begin + FIRST_DIGIT_ENCODINGS := TArray.Create($00, $0B, $0D, $0E, $13, $19, + $1C, $15, $16, $1A); + SetLength(decodeMiddleCounters, 4); +end; + +class procedure TEAN13Reader.FinalizeClass; +begin + FIRST_DIGIT_ENCODINGS := nil; + decodeMiddleCounters := nil; +end; + +initialization + +TEAN13Reader.InitializeClass; + +finalization + +TEAN13Reader.FinalizeClass; + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EAN8Reader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EAN8Reader.pas new file mode 100644 index 0000000..64b7cf7 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EAN8Reader.pas @@ -0,0 +1,148 @@ +{ + * 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 Authors: dswitkin@google.com (Daniel Switkin), Sean Owen and + * alasdair@google.com (Alasdair Mackintosh) + * + * Delphi Implementation by E. Spelt +} + +unit ZXing.OneD.EAN8Reader; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + System.Math, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.OneD.UPCEANReader, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat; + +type + /// + ///

Implements decoding of the EAN-8 format.

+ ///
+ TEAN8Reader = class(TUPCEANReader) + + private + class var DecodeMiddleCounters: TArray; + + class procedure DoInitialize(); + class procedure DoFinalize(); + public + class function DecodeMiddle(const row: IBitArray; + const startRange: TArray; const resultString: TStringBuilder) + : Integer; override; + + function BarcodeFormat: TBarcodeFormat; override; + end; + +implementation + +function TEAN8Reader.BarcodeFormat: TBarcodeFormat; +begin + result := TBarcodeFormat.EAN_8; +end; + +class procedure TEAN8Reader.DoFinalize; +begin + DecodeMiddleCounters := nil; +end; + +class procedure TEAN8Reader.DoInitialize; +begin + SetLength(DecodeMiddleCounters, 4); +end; + +class function TEAN8Reader.DecodeMiddle(const row: IBitArray; + const startRange: TArray; + const resultString: TStringBuilder): Integer; +var + ending, rowOffset, x, bestMatch: Integer; + counter: Integer; + counters, middleRange: TArray; +begin + counters := self.DecodeMiddleCounters; + counters[0] := 0; + counters[1] := 0; + counters[2] := 0; + counters[3] := 0; + ending := row.Size; + rowOffset := startRange[1]; + x := 0; + while (((x < 4) and (rowOffset < ending))) do + begin + if (not TUPCEANReader.decodeDigit(row, counters, rowOffset, + TUPCEANReader.L_PATTERNS, bestMatch)) then + begin + result := -1; + exit + end; + + resultString.Append(IntToStr(bestMatch)); + + for counter in counters do + begin + inc(rowOffset, counter) + end; + inc(x) + end; + + middleRange := TUPCEANReader.findGuardPattern(row, rowOffset, true, + TUPCEANReader.MIDDLE_PATTERN); + if (middleRange = nil) then + begin + result := -1; + exit + end; + + rowOffset := middleRange[1]; + x := 0; + while (((x < 4) and (rowOffset < ending))) do + begin + if (not TUPCEANReader.decodeDigit(row, counters, rowOffset, + TUPCEANReader.L_PATTERNS, bestMatch)) then + begin + result := -1; + exit + end; + + resultString.Append(IntToStr(bestMatch)); + for counter in counters do + begin + inc(rowOffset, counter) + end; + + inc(x) + end; + + result := rowOffset; + +end; + +initialization + +TEAN8Reader.DoInitialize; + +finalization + +TEAN8Reader.DoFinalize; + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EANManufacturerOrgSupport.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EANManufacturerOrgSupport.pas new file mode 100644 index 0000000..72a49ee --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.EANManufacturerOrgSupport.pas @@ -0,0 +1,230 @@ +{ + * Copyright 2010 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.OneD.EANManufacturerOrgSupport; + +interface + +uses + System.SysUtils, + System.Classes, + System.Generics.Collections, + System.Math, + ZXing.OneD.UPCEANExtension2Support, + ZXing.OneD.UPCEANExtension5Support, + ZXing.Reader, + ZXing.BinaryBitmap, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultMetadataType, + ZXing.ResultPoint, + ZXing.Common.BitArray, + ZXing.Common.Detector.MathUtils; + +type + // + /// Records EAN prefix to GS1 Member Organization, where the member organization + /// correlates strongly with a country. This is an imperfect means of identifying + /// a country of origin by EAN-13 barcode value. See + /// + /// http://en.wikipedia.org/wiki/List_of_GS1_country_codes. + /// + TEANManufacturerOrgSupport = class sealed + private + var + ranges: TList>; + countryIdentifiers: TStringList; + + procedure add(const range: TArray; const id: string); + procedure initIfNeeded; + public + constructor Create; + destructor Destroy; override; + + function lookupCountryIdentifier(const productCode: String): String; + end; + +implementation + +{ TEANManufacturerOrgSupport } + +constructor TEANManufacturerOrgSupport.Create; +begin + ranges := TList < TArray < Integer >>.Create; + countryIdentifiers := TStringList.Create; +end; + +destructor TEANManufacturerOrgSupport.Destroy; +begin + countryIdentifiers.Free; + ranges.Free; + inherited; +end; + +function TEANManufacturerOrgSupport.lookupCountryIdentifier(const productCode + : String): String; +var + i, prefix, max: Integer; + range: TArray; + start, ending: Integer; +begin + Result := ''; + + initIfNeeded; + prefix := Integer.Parse(productCode.Substring(0, 3)); + max := ranges.Count; + for i := 0 to Pred(max) do + begin + range := ranges[i]; + start := range[0]; + if (prefix < start) then + exit; + if (Length(range) = 1) then + ending := start + else + ending := range[1]; + if (prefix <= ending) then + begin + Result := countryIdentifiers[i]; + break; + end; + end; +end; + +procedure TEANManufacturerOrgSupport.add(const range: TArray; + const id: string); +begin + ranges.add(range); + countryIdentifiers.add(id); +end; + +procedure TEANManufacturerOrgSupport.initIfNeeded; +begin + if (ranges.Count = 0) then + begin + add(TArray.Create(0, 19), 'US/CA'); + add(TArray.Create(30, 39), 'US'); + add(TArray.Create(60, 139), 'US/CA'); + add(TArray.Create(300, 379), 'FR'); + add(TArray.Create(380), 'BG'); + add(TArray.Create(383), 'SI'); + add(TArray.Create(385), 'HR'); + add(TArray.Create(387), 'BA'); + add(TArray.Create(400, 440), 'DE'); + add(TArray.Create(450, 459), 'JP'); + add(TArray.Create(460, 469), 'RU'); + add(TArray.Create(471), 'TW'); + add(TArray.Create(474), 'EE'); + add(TArray.Create(475), 'LV'); + add(TArray.Create(476), 'AZ'); + add(TArray.Create(477), 'LT'); + add(TArray.Create(478), 'UZ'); + add(TArray.Create(479), 'LK'); + add(TArray.Create(480), 'PH'); + add(TArray.Create(481), 'BY'); + add(TArray.Create(482), 'UA'); + add(TArray.Create(484), 'MD'); + add(TArray.Create(485), 'AM'); + add(TArray.Create(486), 'GE'); + add(TArray.Create(487), 'KZ'); + add(TArray.Create(489), 'HK'); + add(TArray.Create(490, 499), 'JP'); + add(TArray.Create(500, 509), 'GB'); + add(TArray.Create(520), 'GR'); + add(TArray.Create(528), 'LB'); + add(TArray.Create(529), 'CY'); + add(TArray.Create(531), 'MK'); + add(TArray.Create(535), 'MT'); + add(TArray.Create(539), 'IE'); + add(TArray.Create(540, 549), 'BE/LU'); + add(TArray.Create(560), 'PT'); + add(TArray.Create(569), 'IS'); + add(TArray.Create(570, 579), 'DK'); + add(TArray.Create(590), 'PL'); + add(TArray.Create(594), 'RO'); + add(TArray.Create(599), 'HU'); + add(TArray.Create(600, 601), 'ZA'); + add(TArray.Create(603), 'GH'); + add(TArray.Create(608), 'BH'); + add(TArray.Create(609), 'MU'); + add(TArray.Create(611), 'MA'); + add(TArray.Create(613), 'DZ'); + add(TArray.Create(616), 'KE'); + add(TArray.Create(618), 'CI'); + add(TArray.Create(619), 'TN'); + add(TArray.Create(621), 'SY'); + add(TArray.Create(622), 'EG'); + add(TArray.Create(624), 'LY'); + add(TArray.Create(625), 'JO'); + add(TArray.Create(626), 'IR'); + add(TArray.Create(627), 'KW'); + add(TArray.Create(628), 'SA'); + add(TArray.Create(629), 'AE'); + add(TArray.Create(640, 649), 'FI'); + add(TArray.Create(690, 695), 'CN'); + add(TArray.Create(700, 709), 'NO'); + add(TArray.Create(729), 'IL'); + add(TArray.Create(730, 739), 'SE'); + add(TArray.Create(740), 'GT'); + add(TArray.Create(741), 'SV'); + add(TArray.Create(742), 'HN'); + add(TArray.Create(743), 'NI'); + add(TArray.Create(744), 'CR'); + add(TArray.Create(745), 'PA'); + add(TArray.Create(746), 'DO'); + add(TArray.Create(750), 'MX'); + add(TArray.Create(754, 755), 'CA'); + add(TArray.Create(759), 'VE'); + add(TArray.Create(760, 769), 'CH'); + add(TArray.Create(770), 'CO'); + add(TArray.Create(773), 'UY'); + add(TArray.Create(775), 'PE'); + add(TArray.Create(777), 'BO'); + add(TArray.Create(779), 'AR'); + add(TArray.Create(780), 'CL'); + add(TArray.Create(784), 'PY'); + add(TArray.Create(785), 'PE'); + add(TArray.Create(786), 'EC'); + add(TArray.Create(789, 790), 'BR'); + add(TArray.Create(800, 839), 'IT'); + add(TArray.Create(840, 849), 'ES'); + add(TArray.Create(850), 'CU'); + add(TArray.Create(858), 'SK'); + add(TArray.Create(859), 'CZ'); + add(TArray.Create(860), 'YU'); + add(TArray.Create(865), 'MN'); + add(TArray.Create(867), 'KP'); + add(TArray.Create(868, 869), 'TR'); + add(TArray.Create(870, 879), 'NL'); + add(TArray.Create(880), 'KR'); + add(TArray.Create(885), 'TH'); + add(TArray.Create(888), 'SG'); + add(TArray.Create(890), 'IN'); + add(TArray.Create(893), 'VN'); + add(TArray.Create(896), 'PK'); + add(TArray.Create(899), 'ID'); + add(TArray.Create(900, 919), 'AT'); + add(TArray.Create(930, 939), 'AU'); + add(TArray.Create(940, 949), 'AZ'); + add(TArray.Create(955), 'MY'); + add(TArray.Create(958), 'MO'); + end; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.ITFReader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.ITFReader.pas new file mode 100644 index 0000000..05d162c --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.ITFReader.pas @@ -0,0 +1,497 @@ +{ + * 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: kevin.osullivan@sita.aero, SITA Lab. + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.OneD.ITFReader; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + Math, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat, + ZXing.Helpers; + +type + /// + ///

Implements decoding of the ITF format, or Interleaved Two of Five.

+ /// + ///

This Reader will scan ITF barcodes of certain lengths only. + /// At the moment it reads length 6, 8, 10, 12, 14, 16, 18, 20, 24, 44 and 48 as these have appeared "in the wild". Not all + /// lengths are scanned, especially shorter ones, to avoid false positives. This in turn is due to a lack of + /// required checksum function.

+ /// + ///

The checksum is optional and is not applied by this Reader. The consumer of the decoded + /// value will have to apply a checksum if required.

+ /// + ///

http://en.wikipedia.org/wiki/Interleaved_2_of_5 + /// is a great reference for Interleaved 2 of 5 information.

+ ///
+ TITFReader = class(TOneDReader) + const + LARGEST_DEFAULT_ALLOWED_LENGTH: Integer = 14; + N: Integer = 1; + W: Integer = 3; + private + + class var PATTERNS: TArray>; + class var END_PATTERN_REVERSED: TArray; + class var MAX_AVG_VARIANCE: Integer; + class var MAX_INDIVIDUAL_VARIANCE: Integer; + class var DEFAULT_ALLOWED_LENGTHS: TArray; + + class var + START_PATTERN: TArray; + narrowLineWidth: Integer; + + class function decodeDigit(counters: TArray; + out bestMatch: Integer): boolean; static; + function decodeEnd(row: IBitArray): TArray; + class function skipWhiteSpace(row: IBitArray): Integer; static; + class function findGuardPattern(row: IBitArray; rowOffset: Integer; + pattern: TArray): TArray; static; + function validateQuietZone(row: IBitArray; startPattern: Integer): boolean; + function decodeStart(row: IBitArray): TArray; + class function decodeMiddle(row: IBitArray; + payloadStart, payloadEnd: Integer; SBResult: TStringBuilder) + : boolean; static; + class procedure ClassInit(); + public + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; override; + end; + +implementation + +uses + ZXing.Common.Detector.MathUtils; + +{ TITFReader } + +class procedure TITFReader.ClassInit(); +begin + MAX_AVG_VARIANCE := Floor(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.42); + MAX_INDIVIDUAL_VARIANCE := Floor(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.78); + + DEFAULT_ALLOWED_LENGTHS := [6, 8, 10, 12, 14]; + + START_PATTERN := [N, N, N, N]; + END_PATTERN_REVERSED := [N, N, W]; + + PATTERNS := [[N, N, W, W, N], // 0 + [W, N, N, N, W], // 1 + [N, W, N, N, W], // 2 + [W, W, N, N, N], // 3 + [N, N, W, N, W], // 4 + [W, N, W, N, N], // 5 + [N, W, W, N, N], // 6 + [N, N, N, W, W], // 7 + [W, N, N, W, N], // 8 + [N, W, N, W, N]]; // 9 +end; + +function TITFReader.decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; +var + allowedLength: Integer; + startRange: TArray; + endRange: TArray; + stringResult: string; + allowedLengths: TArray; + maxAllowedLength: Integer; + len: Integer; + lengthOK: boolean; + SBResult: TStringBuilder; + resultPointCallback: TResultPointCallback; + obj: TObject; + resultPoints: TArray; + resultPointLeft, + resultPointRight: IResultPoint; +begin + startRange := decodeStart(row); + if (startRange = nil) then + begin + Exit(nil); + end; + + endRange := self.decodeEnd(row); + if (endRange = nil) then + begin + Exit(nil); + end; + + SBResult := TStringBuilder.Create(20); + if (not decodeMiddle(row, startRange[1], endRange[0], SBResult)) then + begin + FreeAndNil(sbResult); + Exit(nil); + end; + stringResult := SBResult.ToString(); + FreeAndNil(sbResult); + + allowedLengths := nil; + maxAllowedLength := LARGEST_DEFAULT_ALLOWED_LENGTH; + if ((hints <> nil) and hints.ContainsKey(ZXing.DecodeHintType.ALLOWED_LENGTHS)) then + begin + allowedLengths := TArray(hints[ZXing.DecodeHintType.ALLOWED_LENGTHS]); + maxAllowedLength := 0 + end; + + if (allowedLengths = nil) then + begin + allowedLengths := DEFAULT_ALLOWED_LENGTHS; + maxAllowedLength := LARGEST_DEFAULT_ALLOWED_LENGTH; + end; + + len := Length(stringResult); + lengthOK := (len > LARGEST_DEFAULT_ALLOWED_LENGTH); + if (not lengthOK) then + begin + + for allowedLength in allowedLengths do + begin + + if (len = allowedLength) then + begin + lengthOK := true; + break; + end; + + if (allowedLength > maxAllowedLength) then + begin + maxAllowedLength := allowedLength; + end; + + end; + + if ((not lengthOK) and (len > maxAllowedLength)) then + begin + lengthOK := true; + end; + + if (not lengthOK) then + begin + Exit(nil); + end + + end; + + resultPointLeft := TResultPointHelpers.CreateResultPoint(startRange[1], rowNumber); + resultPointRight := TResultPointHelpers.CreateResultPoint(endRange[0], rowNumber); + resultPoints := [resultPointLeft, resultPointRight]; + + resultPointCallback := nil; // had to add this initialization because the following if/else construct does not assign a value + // for all possible cases. Being resultPointCallback a local variable it is not initialized by default to null, + // so you could get unpredictable results + + + if ((hints = nil) or + (not hints.ContainsKey(TDecodeHintType.NEED_RESULT_POINT_CALLBACK))) + then + resultPointCallback := nil + else + begin + obj := hints[TDecodeHintType.NEED_RESULT_POINT_CALLBACK]; + if (obj is TResultPointEventObject) + then + resultPointCallback := TResultPointEventObject(obj).Event; + end; + + if Assigned(resultPointCallback) then + begin + resultPointCallback(resultPointLeft); + resultPointCallback(resultPointRight); + end; + + Result := TReadResult.Create(stringResult, nil, resultPoints, + TBarcodeFormat.ITF); +end; + +class function TITFReader.decodeDigit(counters: TArray; + out bestMatch: Integer): boolean; +var + bestVariance: Integer; + max: Integer; + i: Integer; + pattern: TArray; + variance: Integer; +begin + bestVariance := MAX_AVG_VARIANCE; + bestMatch := -1; + max := Length(PATTERNS); + i := 0; + while ((i < max)) do + begin + pattern := PATTERNS[i]; + + variance := PatternMatchVariance(counters, pattern, + MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) then + begin + bestVariance := variance; + bestMatch := i + end; + + inc(i) + end; + + Result := (bestMatch >= 0); + +end; + +function TITFReader.decodeStart(row: IBitArray): TArray; +var + endStart: Integer; + startPattern: TArray; +begin + endStart := skipWhiteSpace(row); + if (endStart < 0) then + begin + Exit(nil); + end; + + startPattern := findGuardPattern(row, endStart, START_PATTERN); + if (startPattern = nil) then + begin + Exit(nil); + end; + + narrowLineWidth := TMathUtils.Asr(startPattern[1] - startPattern[0], 2); + if (not validateQuietZone(row, startPattern[0])) then + begin + Exit(nil); + end; + + Result := startPattern; +end; + +class function TITFReader.decodeMiddle(row: IBitArray; + payloadStart, payloadEnd: Integer; SBResult: TStringBuilder): boolean; +var + bestMatch: Integer; + counterDigit: Integer; + counterDigitPair: TArray; + counterBlack: TArray; + counterWhite: TArray; + k: Integer; + twoK: Integer; + +begin + SetLength(counterDigitPair, 10); + SetLength(counterBlack, 5); + SetLength(counterWhite, 5); + + while ((payloadStart < payloadEnd)) do + begin + if (not RecordPattern(row, payloadStart, counterDigitPair)) then + begin + Exit(false); + end; + + k := 0; + while ((k < 5)) do + begin + twoK := (k shl 1); + counterBlack[k] := counterDigitPair[twoK]; + counterWhite[k] := counterDigitPair[(twoK + 1)]; + inc(k) + end; + + if (not decodeDigit(counterBlack, bestMatch)) then // @(bestMatch))) then + begin + Exit(false); + end; + SBResult.Append(char($30 + bestMatch)); + + if (not decodeDigit(counterWhite, bestMatch)) then // @(bestMatch))) then + begin + Exit(false); + end; + + SBResult.Append(char($30 + bestMatch)); + + for counterDigit in counterDigitPair do + begin + inc(payloadStart, counterDigit); + end + end; + + Result := true; +end; + +function TITFReader.decodeEnd(row: IBitArray): TArray; +var + endStart: Integer; + endPattern: TArray; + temp: Integer; +begin + row.reverse; + endStart := skipWhiteSpace(row); + if (endStart < 0) then + begin + Exit(nil); + end; + + // !! + endPattern := findGuardPattern(row, endStart, END_PATTERN_REVERSED); + if (endPattern = nil) then + begin + row.reverse; + Exit(nil); + end; + + if (not validateQuietZone(row, endPattern[0])) then + begin + row.reverse; + Exit(nil); + end; + + temp := endPattern[0]; + endPattern[0] := row.Size - endPattern[1]; + endPattern[1] := row.Size - temp; + row.reverse; + + Result := endPattern; +end; + +class function TITFReader.findGuardPattern(row: IBitArray; rowOffset: Integer; + pattern: TArray): TArray; +var + patternLength: Integer; + counters: TArray; + width: Integer; + isWhite: boolean; + counterPosition: Integer; + patternStart: Integer; + x: Integer; +begin + patternLength := Length(pattern); + counters := TArray.Create(); + SetLength(counters, patternLength); + width := row.Size; + isWhite := false; + + counterPosition := 0; + patternStart := rowOffset; + x := rowOffset; + + while ((x < width)) do + begin + + if (row[x] xor isWhite) then + begin + inc(counters[counterPosition]); + end + else + begin + + if (counterPosition = (patternLength - 1)) then + begin + + if (PatternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < + MAX_AVG_VARIANCE) then + begin + Result := [patternStart, x]; + Exit(Result); + end; + inc(patternStart, (counters[0] + counters[1])); + + counters := TArray.CopyInSameArray(counters, 2, patternLength - 2); + + counters[(patternLength - 2)] := 0; + counters[(patternLength - 1)] := 0; + dec(counterPosition); + + end + else + begin + inc(counterPosition); + end; + + counters[counterPosition] := 1; + isWhite := not isWhite + + end; + + inc(x); + end; + + Result := nil; + +end; + +class function TITFReader.skipWhiteSpace(row: IBitArray): Integer; +var + width: Integer; + endStart: Integer; +begin + width := row.Size; + endStart := row.getNextSet(0); + if (endStart = width) then + begin + Result := -1; + end + else + begin + Result := endStart; + end + +end; + +function TITFReader.validateQuietZone(row: IBitArray; + startPattern: Integer): boolean; +var + quietCount: Integer; + i: Integer; +begin + quietCount := (self.narrowLineWidth * 10); + if (quietCount >= startPattern) then + begin + quietCount := startPattern; + end; + + i := (startPattern - 1); + while (((quietCount > 0) and (i >= 0))) do + begin + if (row[i]) then + begin + break; + end; + dec(quietCount); + dec(i) + end; + if (quietCount <> 0) then + begin + Exit(false); + end; + + Result := true; + +end; + +initialization + +TITFReader.ClassInit(); + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.OneDReader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.OneDReader.pas new file mode 100644 index 0000000..eee0c97 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.OneDReader.pas @@ -0,0 +1,499 @@ +{ + * 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 Authors: dswitkin@google.com (Daniel Switkin) and Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.OneD.OneDReader; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + Math, + ZXing.Reader, + ZXing.BinaryBitmap, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultMetadataType, + ZXing.ResultPoint, + ZXing.Common.BitArray, + ZXing.Common.Detector.MathUtils; + +type + /// + /// Encapsulates functionality and implementation that is common to all families + /// of one-dimensional barcodes. + /// + TOneDReader = class(TInterfacedObject, IReader) + private + /// + /// We're going to examine rows from the middle outward, searching alternately above and below the + /// middle, and farther out each time. rowStep is the number of rows between each successive + /// attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then + /// middle + rowStep, then middle - (2 * rowStep), etc. + /// rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily + /// decided that moving up and down by about 1/16 of the image is pretty good; we try more of the + /// image if "trying harder". + /// + /// The image to decode + /// Any hints that were requested + /// The contents of the decoded barcode + function doDecode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; + class procedure InitializeClass; static; + protected + class var INTEGER_MATH_SHIFT: Integer; + class var PATTERN_MATCH_RESULT_SCALE_FACTOR: Integer; + + /// + /// Determines how closely a set of observed counts of runs of black/white values matches a given + /// target pattern. This is reported as the ratio of the total variance from the expected pattern + /// proportions across all pattern elements, to the length of the pattern. + /// + /// observed counters + /// expected pattern + /// The most any counter can differ before we give up + /// ratio of total variance between counters and pattern compared to total pattern size, + /// where the ratio has been multiplied by 256. So, 0 means no variance (perfect match); 256 means + /// the total variance between counters and patterns equals the pattern length, higher values mean + /// even more variance + class function patternMatchVariance(counters, pattern: TArray; + maxIndividualVariance: Integer): Integer; static; + + /// + /// Records the pattern in reverse. + /// + /// The row. + /// The start. + /// The counters. + /// + class function RecordPatternInReverse(row: IBitArray; start: Integer; + counters: TArray): Boolean; Static; + + /// + /// Records the size of successive runs of white and black pixels in a row, starting at a given point. + /// The values are recorded in the given array, and the number of runs recorded is equal to the size + /// of the array. If the row starts on a white pixel at the given start point, then the first count + /// recorded is the run of white pixels starting from that point; likewise it is the count of a run + /// of black pixels if the row begin on a black pixels at that point. + /// + /// row to count from + /// offset into row to start at + /// array into which to record counts + class function recordPattern(row: IBitArray; start: Integer; + counters: TArray; numCounters: Integer): Boolean; + overload; static; + public + /// + /// Resets any internal state the implementation has after a decode, to prepare it + /// for reuse. + /// + procedure reset(); virtual; + /// + /// Locates and decodes a barcode in some format within an image. + /// + /// image of barcode to decode + /// + /// String which the barcode encodes + /// + function decode(const image: TBinaryBitmap): TReadResult; overload; + /// + /// Locates and decodes a barcode in some format within an image. This method also accepts + /// hints, each possibly associated to some data, which may help the implementation decode. + /// Note that we don't try rotation without the try harder flag, even if rotation was supported. + /// + /// image of barcode to decode + /// passed as a from + /// to arbitrary data. The + /// meaning of the data depends upon the hint type. The implementation may or may not do + /// anything with these hints. + /// + /// String which the barcode encodes + /// + function decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; + overload; virtual; + + /// + /// Records the size of successive runs of white and black pixels in a row, starting at a given point. + /// The values are recorded in the given array, and the number of runs recorded is equal to the size + /// of the array. If the row starts on a white pixel at the given start point, then the first count + /// recorded is the run of white pixels starting from that point; likewise it is the count of a run + /// of black pixels if the row begin on a black pixels at that point. + /// + /// row to count from + /// offset into row to start at + /// array into which to record counts + class function recordPattern(row: IBitArray; start: Integer; + counters: TArray): Boolean; overload; static; + + /// + /// Attempts to decode a one-dimensional barcode format given a single row of + /// an image. + /// + /// row number from top of the row + /// the black/white pixel data of the row + /// decode hints + /// + /// containing encoded string and start/end of barcode + /// + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; + virtual; abstract; + end; + +implementation + +{ TOneDReader } + +function TOneDReader.decode(const image: TBinaryBitmap): TReadResult; +begin + Result := decode(image, nil); +end; + +class procedure TOneDReader.InitializeClass(); +begin + INTEGER_MATH_SHIFT := 8; + PATTERN_MATCH_RESULT_SCALE_FACTOR := (1 shl INTEGER_MATH_SHIFT); +end; + +function TOneDReader.decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; +var + tryHarder, tryHarderWithoutRotation: Boolean; + rotatedImage: TBinaryBitmap; + metadata: TResultMetadata; + orientation, height, i, l: Integer; + points: TArray; + +begin + Result := doDecode(image, hints); + if (Result = nil) then + begin + Exit; + end; + + tryHarder := (hints <> nil) and + (hints.ContainsKey(ZXing.DecodeHintType.TRY_HARDER)); + + tryHarderWithoutRotation := (hints <> nil) and + (hints.ContainsKey(ZXing.DecodeHintType.TRY_HARDER_WITHOUT_ROTATION)); + + if (tryHarder and ((not tryHarderWithoutRotation) and image.RotateSupported)) + then + begin + rotatedImage := image.rotateCounterClockwise(); + Result := doDecode(rotatedImage, hints); + if (Result = nil) then + begin + Exit; + end; + + // Record that we found it rotated 90 degrees CCW / 270 degrees CW + metadata := Result.ResultMetadata; + orientation := 270; + if ((metadata <> nil) and metadata.ContainsKey + (ZXing.ResultMetadataType.orientation)) then + begin + // But if we found it reversed in doDecode(), add in that result here: + orientation := + (orientation + (metadata[ZXing.ResultMetadataType.orientation] + as IIntegerMetadata).Value) mod 360; + end; + + Result.putMetadata(ZXing.ResultMetadataType.orientation, + TResultMetadata.CreateIntegerMetadata(orientation)); + // Update result points + points := Result.ResultPoints; + if (points <> nil) then + begin + height := rotatedImage.height; + l := Length(points) - 1; + for i := 0 to l do + begin + points[i] := TResultPointHelpers.CreateResultPoint + (height - points[i].Y - 1, points[i].X); + end; + end; + + end; + +end; + +function TOneDReader.doDecode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; + +var + attempt, X, rowNumber, rowStepsAboveOrBelow, width, height, middle, rowStep, + maxLines: Integer; + row: IBitArray; + isAbove, hadResultPointCallBack: Boolean; + ReadResult: TReadResult; + points: TArray; + obj: TObject; + needsCallBack : boolean; +begin + needsCallBack := (hints <> nil) and (hints.ContainsKey(ZXing.DecodeHintType.NEED_RESULT_POINT_CALLBACK)); + width := image.width; + height := image.height; + row := TBitArrayHelpers.CreateBitArray(width); + // row is a interfaced object: we don't need to free it explicitly + + middle := TMathUtils.Asr(height, 1); + + rowStep := 5; + maxLines := height; // Look at the whole image, not just the center + + for X := 0 to maxLines - 1 do + begin + // Scanning from the middle out. Determine which row we're looking at next: + rowStepsAboveOrBelow := TMathUtils.Asr((X + 1), 1); + isAbove := (X and $01) = 0; // i.e. is x even? + + if (not isAbove) then + begin + rowStepsAboveOrBelow := rowStepsAboveOrBelow * -1; + end; + rowNumber := middle + rowStep * rowStepsAboveOrBelow; + + if ((rowNumber < 0) or (rowNumber >= height)) then + begin + // Oops, if we run off the top or bottom, stop + break; + end; + + // Estimate black point for this row and load it: + row := image.getBlackRow(rowNumber, row); + if (row = nil) then + begin + continue; + end; + + // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to + // handle decoding upside down barcodes. + // for attempt := 0 to (attempt < 2) do + for attempt := 0 to 1 do + begin + + hadResultPointCallBack := false; + if (attempt = 1) then + begin + // trying again? + row.Reverse(); + + + // This means we will only ever draw result points *once* in the life of this method + // since we want to avoid drawing the wrong points after flipping the row, and, + // don't want to clutter with noise from every single row scan -- just the scans + // that start on the center line. + + if needsCallBack then + begin + hints.TryGetValue + (ZXing.DecodeHintType.NEED_RESULT_POINT_CALLBACK, obj); + hints.Remove(ZXing.DecodeHintType.NEED_RESULT_POINT_CALLBACK); + hadResultPointCallBack := true; + end; + + end; + + // Look for a barcode + ReadResult := decodeRow(rowNumber, row, hints); + if hadResultPointCallBack then + begin + hints.Add(ZXing.DecodeHintType.NEED_RESULT_POINT_CALLBACK, obj); + end; + + if (ReadResult = nil) then + begin + continue; + end; + + // We found our barcode + if (attempt = 1) then + begin + // But it was upside down, so note that + // ReadResult.putMetadata(ResultMetadataType.orientation, TObject(180)); + // And remember to flip the result points horizontally. + points := ReadResult.ResultPoints; + if (points <> nil) then + begin + points[0] := TResultPointHelpers.CreateResultPoint + (width - points[0].X - 1, points[0].Y); + points[1] := TResultPointHelpers.CreateResultPoint + (width - points[1].X - 1, points[1].Y); + end; + + end; + + Exit(ReadResult); + + end; // loop + + end; + + Result := nil; +end; + +class function TOneDReader.patternMatchVariance(counters, + pattern: TArray; maxIndividualVariance: Integer): Integer; +var + scaledPattern, variance, counter, totalVariance, X, unitBarWidth, i, + patternLength, numCounters, total: Integer; +begin + Result := High(Integer); + + numCounters := Length(counters); + total := 0; + patternLength := 0; + for i := 0 to numCounters - 1 do + begin + total := total + counters[i]; + patternLength := patternLength + pattern[i]; + end; + + if (total < patternLength) then + // If we don't even have one pixel per unit of bar width, assume this is too small + // to reliably match, so fail: + Exit; + + // We're going to fake floating-point math in integers. We just need to use more bits. + // Scale up patternLength so that intermediate values below like scaledCounter will have + // more "significant digits" + unitBarWidth := (total shl INTEGER_MATH_SHIFT) div patternLength; + maxIndividualVariance := + TMathUtils.Asr((maxIndividualVariance * unitBarWidth), INTEGER_MATH_SHIFT); + + totalVariance := 0; + for X := 0 to numCounters - 1 do + begin + counter := counters[X] shl INTEGER_MATH_SHIFT; + scaledPattern := pattern[X] * unitBarWidth; + + if (counter > scaledPattern) then + variance := counter - scaledPattern + else + variance := scaledPattern - counter; + + if (variance > maxIndividualVariance) then + Exit; + + totalVariance := totalVariance + variance; + end; + + Result := totalVariance div total; +end; + +class function TOneDReader.recordPattern(row: IBitArray; start: Integer; + counters: TArray): Boolean; +begin + Result := recordPattern(row, start, counters, Length(counters)); +end; + +class function TOneDReader.recordPattern(row: IBitArray; start: Integer; + counters: TArray; numCounters: Integer): Boolean; + +var + i, counterPosition, idx, ending: Integer; + isWhite: Boolean; + +begin + for idx := 0 to numCounters - 1 do + begin + counters[idx] := 0; + end; + + ending := row.Size; + + if (start >= ending) then + begin + Result := false; + Exit; + end; + + isWhite := not row[start]; + counterPosition := 0; + i := start; + while (i < ending) do + begin + if (row[i] xor isWhite) then + begin // that is, exactly one is true + inc(counters[counterPosition]); + end + else + begin + inc(counterPosition); + if (counterPosition = numCounters) then + begin + break; + end + else + begin + counters[counterPosition] := 1; + isWhite := not isWhite; + end; + end; + inc(i); + end; + + // If we read fully the last section of pixels and filled up our counters -- or filled + // the last counter but ran off the side of the image, OK. Otherwise, a problem. + Result := ((counterPosition = numCounters) or + ((counterPosition = (numCounters - 1)) and (i = ending))); + +end; + +class function TOneDReader.RecordPatternInReverse(row: IBitArray; + start: Integer; counters: TArray): Boolean; + +var + numTransitionsLeft: Integer; + last: Boolean; + +begin + // This could be more efficient I guess + numTransitionsLeft := Length(counters); + last := row[start]; + while ((start > 0) and (numTransitionsLeft >= 0)) do + begin + dec(start); + if (row[start] <> last) then + begin + dec(numTransitionsLeft); + last := not last; + end; + end; + + if (numTransitionsLeft >= 0) then + begin + Result := false; + Exit; + end; + Result := recordPattern(row, start + 1, counters); +end; + +procedure TOneDReader.reset; +begin + // do nothing +end; + +initialization + +TOneDReader.InitializeClass(); + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCAReader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCAReader.pas new file mode 100644 index 0000000..f680557 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCAReader.pas @@ -0,0 +1,140 @@ +unit ZXing.OneD.UPCAReader; +{ + * 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 Authors: Sean Owen + * Delphi Implementation by E. Spelt +} + +interface + +uses + System.SysUtils, + System.Generics.Collections, + Math, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.BinaryBitmap, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat, + ZXing.Helpers, + ZXing.OneD.EAN13Reader, + ZXing.OneD.UPCEANReader; + +type + + TUPCAReader = class(TUPCEANReader) + private + class var EAN13Reader: TUPCEANReader; + class function maybeReturnResult(pResult: TReadResult): TReadResult; static; + class procedure DoInitialize(); + class procedure DoFinalize(); + protected + + public + class function DecodeMiddle(const row: IBitArray; + const startRange: TArray; const resultString: TStringBuilder) + : Integer; override; + + function decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; override; + + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; + overload; override; + + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const startGuardRange: TArray; + const hints: TDictionary): TReadResult; + reintroduce; overload; + + function BarcodeFormat: TBarcodeFormat; override; + end; + +implementation + +{ TUPCAReader } + +class procedure TUPCAReader.DoFinalize; +begin + EAN13Reader.Free; +end; + +class procedure TUPCAReader.DoInitialize; +begin + EAN13Reader := TEAN13Reader.Create(); +end; + +function TUPCAReader.decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; +begin + result := TUPCAReader.maybeReturnResult(self.EAN13Reader.decode(image, hints)) +end; + +class function TUPCAReader.DecodeMiddle(const row: IBitArray; + const startRange: TArray; + const resultString: TStringBuilder): Integer; +begin + result := self.EAN13Reader.DecodeMiddle(row, startRange, resultString) +end; + +function TUPCAReader.decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; +begin + result := TUPCAReader.maybeReturnResult(self.EAN13Reader.decodeRow(rowNumber, + row, hints)) +end; + +function TUPCAReader.decodeRow(const rowNumber: Integer; const row: IBitArray; + const startGuardRange: TArray; + const hints: TDictionary): TReadResult; +begin + result := TUPCAReader.maybeReturnResult + (self.EAN13Reader.doDecodeRow(rowNumber, row, startGuardRange, hints)) +end; + +function TUPCAReader.BarcodeFormat: TBarcodeFormat; +begin + result := TBarcodeFormat.UPC_A; +end; + +class function TUPCAReader.maybeReturnResult(pResult: TReadResult): TReadResult; +begin + if not Assigned(pResult) then + Exit(nil); + +{$ZEROBASEDSTRINGS ON} + if (copy(pResult.text, 0, 1) = '0') then + begin + pResult.text := copy(pResult.text, 2, length(pResult.text)); + pResult.BarcodeFormat := TBarcodeFormat.UPC_A; + end; +{$ZEROBASEDSTRINGS OFF} + result := pResult; + +end; + +initialization + +TUPCAReader.DoInitialize; + +finalization + +TUPCAReader.DoFinalize; + + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtension2Support.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtension2Support.pas new file mode 100644 index 0000000..0e8a8c6 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtension2Support.pas @@ -0,0 +1,194 @@ +{ + * 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.UPCEANExtension2Support; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + System.Math, + ZXing.Reader, + ZXing.BarcodeFormat, + ZXing.BinaryBitmap, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultMetadataType, + ZXing.ResultPoint, + ZXing.Common.BitArray; + +type + /// + /// @see UPCEANExtension5Support + /// + TUPCEANExtension2Support = class sealed + private + class var + decodeMiddleCounters : TArray; + decodeRowStringBuffer : TStringBuilder; + + class procedure InitializeClass; static; + class procedure FinalizeClass; static; + + class function decodeMiddle(const row: IBitArray; + const startRange: TArray; + const resultString: TStringBuilder): Integer; + + /// + /// Parses the extension string. + /// + /// raw content of extension + /// formatted interpretation of raw content as a {@link TMap} mapping + class function parseExtensionString(const raw: String): TResultMetadata; static; + public + class function decodeRow(const rowNumber: Integer; const row: IBitArray; + const extensionStartRange: TArray): TReadResult; + end; + +implementation + +uses + ZXing.OneD.UPCEANReader; + +{ TUPCEANExtension2Support } + +class procedure TUPCEANExtension2Support.InitializeClass; +begin + decodeMiddleCounters := TArray.Create(0, 0, 0, 0); + decodeRowStringBuffer := TStringBuilder.Create; +end; + +class procedure TUPCEANExtension2Support.FinalizeClass; +begin + decodeMiddleCounters := nil; + decodeRowStringBuffer.Free; +end; + +class function TUPCEANExtension2Support.decodeRow(const rowNumber: Integer; + const row: IBitArray; const extensionStartRange: TArray): TReadResult; +var + res : TStringBuilder; + ending : Integer; + resultString : String; + extensionResult : TReadResult; + extensionData : TResultMetadata; + resultPoints : TArray; +begin + Result := nil; + + res := decodeRowStringBuffer; + res.Length := 0; + ending := decodeMiddle(row, extensionStartRange, res); + if (ending < 0) + then + exit; + + resultString := res.ToString; + extensionData := TUPCEANExtension2Support.parseExtensionString(resultString); + + resultPoints := TArray.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 TUPCEANExtension2Support.decodeMiddle(const row: IBitArray; + const startRange: TArray; const resultString: TStringBuilder): Integer; +var + bestMatch: Integer; + counter: Integer; + ending: Integer; + counters : TArray; + rowOffset, x, + checkParity: Integer; +begin + Result := -1; + + counters := decodeMiddleCounters; + counters[0] := 0; + counters[1] := 0; + counters[2] := 0; + counters[3] := 0; + ending := row.Size; + rowOffset := startRange[1]; + checkParity := 0; + x := 0; + while ((x < 2) 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 + checkParity := checkParity or (1 shl (1 - x)); + + if (x <> 1) then + begin + // Read off separator if not last + rowOffset := row.getNextSet(rowOffset); + rowOffset := row.getNextUnset(rowOffset); + end; + Inc(x); + end; + + if (resultString.Length <> 2) + then + exit; + + if ((Integer.Parse(resultString.ToString) mod 4) <> checkParity) + then + exit; + + Result := rowOffset; +end; + +class function TUPCEANExtension2Support.parseExtensionString(const raw: String): TResultMetadata; +var + dictionary1: TResultMetadata; +begin + Result := nil; + + if (Length(raw) <> 2) + then + exit; + + dictionary1 := TResultMetadata.Create; + dictionary1.Add(ZXing.ResultMetadataType.ISSUE_NUMBER, TResultMetaData.CreateStringMetadata(raw)); + Result := dictionary1; +end; + +initialization + TUPCEANExtension2Support.InitializeClass; +finalization + TUPCEANExtension2Support.FinalizeClass; +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtension5Support.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtension5Support.pas new file mode 100644 index 0000000..f825e4c --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtension5Support.pas @@ -0,0 +1,311 @@ +{ + * 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; + decodeMiddleCounters : TArray; + decodeRowStringBuffer : TStringBuilder; + + class procedure InitializeClass; static; + class procedure FinalizeClass; static; + + class function decodeMiddle(const row: IBitArray; + const startRange: TArray; + const resultString: TStringBuilder): Integer; + + class function extensionChecksum(const s: string): Integer; static; + + class function determineCheckDigit(const lgPatternFound: Integer; + var checkDigit: Integer): Boolean; static; + + /// + /// Parses the extension string. + /// + /// raw content of extension + /// formatted interpretation of raw content as a {@link TMap} mapping + /// one {@link TResultMetadataType} to appropriate value, or {@code nil} if not known + 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): TReadResult; + end; + +implementation + +uses + ZXing.OneD.UPCEANReader; + +{ TUPCEANExtension2Support } + +class procedure TUPCEANExtension5Support.InitializeClass; +begin + CHECK_DIGIT_ENCODINGS := TArray.Create($18, $14, $12, $11, $0C, + $06, $03, $0A, $09, $05); + decodeMiddleCounters := TArray.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): TReadResult; +var + res : TStringBuilder; + ending : Integer; + resultString : String; + extensionData : TResultMetadata; + resultPoints : TArray; + 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.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; const resultString: TStringBuilder): Integer; +var + bestMatch: Integer; + counter: Integer; + ending: Integer; + counters : TArray; + 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. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtensionSupport.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtensionSupport.pas new file mode 100644 index 0000000..99be557 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANExtensionSupport.pas @@ -0,0 +1,99 @@ +{ + * 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.UPCEANExtensionSupport; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + System.Math, + ZXing.OneD.UPCEANExtension2Support, + ZXing.OneD.UPCEANExtension5Support, + ZXing.Reader, + ZXing.BinaryBitmap, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultMetadataType, + ZXing.ResultPoint, + ZXing.Common.BitArray, + ZXing.Common.Detector.MathUtils; + +type + TUPCEANExtensionSupport = class sealed + private + class var + EXTENSION_START_PATTERN : TArray; + + twoSupport : TUPCEANExtension2Support; + fiveSupport : TUPCEANExtension5Support; + + class procedure InitializeClass; static; + class procedure FinalizeClass; static; + public + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const rowOffset: Integer): TReadResult; + end; + +implementation + +uses + ZXing.OneD.UPCEANReader; + +{ TUPCEANExtensionSupport } + +class procedure TUPCEANExtensionSupport.InitializeClass(); +begin + EXTENSION_START_PATTERN := TArray.Create(1, 1, 2); + twoSupport := TUPCEANExtension2Support.Create(); + fiveSupport := TUPCEANExtension5Support.Create(); +end; + +class procedure TUPCEANExtensionSupport.FinalizeClass(); +begin + EXTENSION_START_PATTERN := nil; + twoSupport.Free; + fiveSupport.Free; +end; + +function TUPCEANExtensionSupport.decodeRow(const rowNumber: Integer; + const row: IBitArray; const rowOffset: Integer): TReadResult; +var + extensionStartRange: TArray; + res : TReadResult; +begin + Result := nil; + + extensionStartRange := TUPCEANReader.findGuardPattern(row, rowOffset, + false, EXTENSION_START_PATTERN); + if (extensionStartRange = nil) + then + exit; + res := fiveSupport.decodeRow(rowNumber, row, extensionStartRange); + if (res = nil) + then + res := twoSupport.decodeRow(rowNumber, row, extensionStartRange); + Result := res; +end; + +initialization + TUPCEANExtensionSupport.InitializeClass; +finalization + TUPCEANExtensionSupport.FinalizeClass; +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANReader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANReader.pas new file mode 100644 index 0000000..2e5d0e5 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEANReader.pas @@ -0,0 +1,592 @@ +{ + * 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 Authors: dswitkin@google.com (Daniel Switkin), Sean Owen and + * alasdair@google.com (Alasdair Mackintosh) + * Delphi Implementation by K. Gossens +} + +unit ZXing.OneD.UPCEANReader; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + System.Math, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.OneD.UPCEANExtensionSupport, + ZXing.OneD.EANManufacturerOrgSupport, + ZXing.ResultMetadataType, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat; + +type + /// + ///

Encapsulates functionality and implementation that is common to UPC and EAN families + /// of one-dimensional barcodes.

+ ///
+ TUPCEANReader = class abstract(TOneDReader) + private + decodeRowStringBuffer: TStringBuilder; + extensionReader: TUPCEANExtensionSupport; + eanManSupport: TEANManufacturerOrgSupport; + + /// + /// + /// row of black/white values to search + /// position to start search + /// if true, indicates that the pattern specifies white/black/white/... + /// pixel counts, otherwise, it is interpreted as black/white/black/... + /// pattern of counts of number of black and white pixels that are being + /// searched for as a pattern + /// array of counters, as long as pattern, to re-use + /// start/end horizontal offset of guard pattern, as an array of two ints + class function findGuardPattern(const row: IBitArray; rowOffset: Integer; + const whiteFirst: Boolean; const pattern: TArray; + counters: TArray): TArray; overload; + + /// + /// Computes the UPC/EAN checksum on a string of digits, and reports + /// whether the checksum is correct or not. + /// + /// string of digits to check + /// true iff string of digits passes the UPC/EAN checksum algorithm + class function checkStandardUPCEANChecksum(const s: String) + : Boolean; static; + + class procedure InitializeClass; static; + class procedure FinalizeClass; static; + protected + class var + // These two values are critical for determining how permissive the decoding will be. + // We've arrived at these values through a lot of trial and error. Setting them any higher + // lets false positives creep in quickly. + MAX_AVG_VARIANCE: Integer; + MAX_INDIVIDUAL_VARIANCE: Integer; + + /// + /// Start/end guard pattern. + /// + START_END_PATTERN: TArray; + + /// + /// Pattern marking the middle of a UPC/EAN pattern, separating the two halves. + /// + MIDDLE_PATTERN: TArray; + + /// + /// "Odd", or "L" patterns used to encode UPC/EAN digits. + /// + L_PATTERNS: TArray>; + + /// + /// Decodes the end. + /// + /// The row. + /// The end start. + /// + class function decodeEnd(const row: IBitArray; const endStart: Integer) + : TArray; virtual; + + /// + /// + /// string of digits to check + /// see + class function checkChecksum(const s: String): Boolean; virtual; + public + class var + /// + /// As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. + /// + L_AND_G_PATTERNS: TArray>; + + /// + /// Initializes a new instance of the class. + /// + constructor Create; virtual; + destructor Destroy; override; + + /// + /// Subclasses override this to decode the portion of a barcode between the start + /// and end guard patterns. + /// + /// row of black/white values to search + /// start/end offset of start guard pattern + /// to append decoded chars to + /// horizontal offset of first pixel after the "middle" that was decoded or -1 if decoding could not complete successfully + class function DecodeMiddle(const row: IBitArray; + const startRange: TArray; const resultString: TStringBuilder) + : Integer; virtual; abstract; + + /// + /// Get the format of this decoder. + /// + /// The 1D format. + function BarcodeFormat: TBarcodeFormat; virtual; abstract; + + class function findStartGuardPattern(const row: IBitArray) + : TArray; static; + + class function findGuardPattern(const row: IBitArray; + const rowOffset: Integer; const whiteFirst: Boolean; + const pattern: TArray): TArray; overload; + + /// + /// Attempts to decode a single UPC/EAN-encoded digit. + /// + /// row of black/white values to decode + /// the counts of runs of observed black/white/black/... values + /// horizontal offset to start decoding from + /// the set of patterns to use to decode -- sometimes different encodings + /// for the digits 0-9 are used, and this indicates the encodings for 0 to 9 that should + /// be used + /// horizontal offset of first pixel beyond the decoded digit + class function decodeDigit(const row: IBitArray; + const counters: TArray; const rowOffset: Integer; + const patterns: TArray>; var digit: Integer): Boolean; + + /// + ///

Attempts to decode a one-dimensional barcode format given a single row of + /// an image.

+ ///
+ /// row number from top of the row + /// the black/white pixel data of the row + /// decode hints + /// + /// containing encoded string and start/end of barcode or null, if an error occurs or barcode cannot be found + /// + function decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; + overload; override; + + /// + ///

Like decodeRow(int, BitArray, java.util.Map), but + /// allows caller to inform method about where the UPC/EAN start pattern is + /// found. This allows this to be computed once and reused across many implementations.

+ ///
+ /// row index into the image + /// encoding of the row of the barcode image + /// start/end column where the opening start pattern was found + /// optional hints that influence decoding + /// encapsulating the result of decoding a barcode in the row + function DoDecodeRow(const rowNumber: Integer; const row: IBitArray; + const startGuardRange: TArray; + const hints: TDictionary): TReadResult; + + end; + +implementation + +{ TUPCEANReader } + +constructor TUPCEANReader.Create; +begin + inherited; + + decodeRowStringBuffer := TStringBuilder.Create(20); + extensionReader := TUPCEANExtensionSupport.Create; + eanManSupport := TEANManufacturerOrgSupport.Create; +end; + +destructor TUPCEANReader.Destroy; +begin + eanManSupport.Free; + extensionReader.Free; + decodeRowStringBuffer.Free; + inherited; +end; + +class procedure TUPCEANReader.InitializeClass; +var + i, j: Integer; + widths, reversedWidths: TArray; +begin + MAX_AVG_VARIANCE := + Trunc(TOneDReader.PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.48); + MAX_INDIVIDUAL_VARIANCE := + Trunc(TOneDReader.PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7); + + START_END_PATTERN := TArray.Create(1, 1, 1); + MIDDLE_PATTERN := TArray.Create(1, 1, 1, 1, 1); + + L_PATTERNS := TArray < TArray < Integer >> + .Create(TArray.Create(3, 2, 1, 1), // 0 + TArray.Create(2, 2, 2, 1), // 1 + TArray.Create(2, 1, 2, 2), // 2 + TArray.Create(1, 4, 1, 1), // 3 + TArray.Create(1, 1, 3, 2), // 4 + TArray.Create(1, 2, 3, 1), // 5 + TArray.Create(1, 1, 1, 4), // 6 + TArray.Create(1, 3, 1, 2), // 7 + TArray.Create(1, 2, 1, 3), // 8 + TArray.Create(3, 1, 1, 2) // 9 + ); + + L_AND_G_PATTERNS := L_PATTERNS; + SetLength(L_AND_G_PATTERNS, 20); + + // Move(L_PATTERNS[0], L_AND_G_PATTERNS[0], 10); + for i := 10 to Pred(20) do + begin + widths := L_PATTERNS[(i - 10)]; + reversedWidths := TArray.Create(); + SetLength(reversedWidths, Length(widths)); + for j := 0 to Pred(Length(widths)) do + reversedWidths[j] := widths[((Length(widths) - j) - 1)]; + L_AND_G_PATTERNS[i] := reversedWidths; + end; +end; + +class procedure TUPCEANReader.FinalizeClass; +begin + START_END_PATTERN := nil; + MIDDLE_PATTERN := nil; + L_PATTERNS := nil; + L_AND_G_PATTERNS := nil; + +end; + +class function TUPCEANReader.checkChecksum(const s: String): Boolean; +begin + Result := checkStandardUPCEANChecksum(s); +end; + +class function TUPCEANReader.checkStandardUPCEANChecksum + (const s: String): Boolean; +var + len, sum, i, digit, ZeroInt: Integer; +begin +{$ZEROBASEDSTRINGS ON} + Result := false; + + len := Length(s); + if (len = 0) then + exit; + + sum := 0; + ZeroInt := Ord('0'); + i := (len - 2); + while ((i >= 0)) do + begin + digit := Ord(s[i]) - ZeroInt; + if ((digit < 0) or (digit > 9)) then + exit; + Inc(sum, digit); + Dec(i, 2); + end; + sum := (sum * 3); + i := (len - 1); + while ((i >= 0)) do + begin + digit := Ord(s[i]) - ZeroInt; + if ((digit < 0) or (digit > 9)) then + exit; + Inc(sum, digit); + Dec(i, 2); + end; + +{$ZEROBASEDSTRINGS OFF} + Result := ((sum mod 10) = 0); +end; + +class function TUPCEANReader.decodeEnd(const row: IBitArray; + const endStart: Integer): TArray; +begin + Result := findGuardPattern(row, endStart, false, START_END_PATTERN); +end; + +class function TUPCEANReader.findStartGuardPattern(const row: IBitArray) + : TArray; +var + foundStart: Boolean; + startRange, counters: TArray; + nextStart, start, quietStart, idx, l: Integer; +begin + Result := nil; + + foundStart := false; + startRange := nil; + nextStart := 0; + counters := TArray.Create(); + l := Length(START_END_PATTERN); + SetLength(counters, l); + while (not foundStart) do + begin + for idx := 0 to l - 1 do + counters[idx] := 0; + startRange := findGuardPattern(row, nextStart, false, START_END_PATTERN, + counters); + if (startRange = nil) then + exit; + start := startRange[0]; + nextStart := startRange[1]; + // Make sure there is a quiet zone at least as big as the start pattern before the barcode. + // If this check would run off the left edge of the image, do not accept this barcode, + // as it is very likely to be a false positive. + quietStart := start - (nextStart - start); + if (quietStart >= 0) then + foundStart := row.isRange(quietStart, start, false); + end; + + counters:=nil; + Result := startRange; +end; + +class function TUPCEANReader.findGuardPattern(const row: IBitArray; + const rowOffset: Integer; const whiteFirst: Boolean; + const pattern: TArray): TArray; +var + counters: TArray; +begin + counters := TArray.Create(); + SetLength(counters, Length(pattern)); + Result := findGuardPattern(row, rowOffset, whiteFirst, pattern, counters); + counters:=nil; +end; + +class function TUPCEANReader.findGuardPattern(const row: IBitArray; + rowOffset: Integer; const whiteFirst: Boolean; const pattern: TArray; + counters: TArray): TArray; +var + patternLength, width, x: Integer; + isWhite: Boolean; + counterPosition, patternStart: Integer; + curCounter: TArray; +begin + Result := nil; + + patternLength := Length(pattern); + width := row.Size; + isWhite := whiteFirst; + if whiteFirst then + rowOffset := row.getNextUnset(rowOffset) + else + rowOffset := row.getNextSet(rowOffset); + + counterPosition := 0; + patternStart := rowOffset; + for x := rowOffset to Pred(width) do + begin + if (row[x] xor isWhite) then + Inc(counters[counterPosition]) + else + begin + if (counterPosition = (patternLength - 1)) then + begin + if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < + MAX_AVG_VARIANCE) then + begin + Result := TArray.Create(patternStart, x); + break; + end; + Inc(patternStart, (counters[0] + counters[1])); + curCounter := TArray.Create(); + SetLength(curCounter, Length(counters)); + TArray.Copy(counters, curCounter, 2, 0, (patternLength - 2)); + { curCounter[patternLength - 2] := 0; + curCounter[patternLength - 1] := 0; } + counters := curCounter; + Dec(counterPosition); + end + else + Inc(counterPosition); + counters[counterPosition] := 1; + isWhite := not isWhite; + end; + end; +end; + +class function TUPCEANReader.decodeDigit(const row: IBitArray; + const counters: TArray; const rowOffset: Integer; + const patterns: TArray>; var digit: Integer): Boolean; +var + bestVariance, variance, i, max: Integer; + pattern: TArray; +begin + Result := false; + + digit := -1; + if (not TOneDReader.recordPattern(row, rowOffset, counters)) then + exit; + + bestVariance := TUPCEANReader.MAX_AVG_VARIANCE; // worst variance we'll accept + max := Length(patterns); + for i := 0 to Pred(max) do + begin + pattern := patterns[i]; + variance := TOneDReader.patternMatchVariance(counters, pattern, + TUPCEANReader.MAX_INDIVIDUAL_VARIANCE); + if (variance < bestVariance) then + begin + bestVariance := variance; + digit := i; + end; + end; + + Result := (digit >= 0); +end; + +function TUPCEANReader.decodeRow(const rowNumber: Integer; const row: IBitArray; + const hints: TDictionary): TReadResult; +var + startRange: TArray; +begin + startRange := findStartGuardPattern(row); + if startRange = nil then + exit(nil); + + try + Result := DoDecodeRow(rowNumber, row, startRange, hints); + except + result := nil; + end; + +end; + +function TUPCEANReader.DoDecodeRow(const rowNumber: Integer; + const row: IBitArray; + + const startGuardRange: TArray; + const hints: TDictionary): TReadResult; +var + len: Integer; + res: TStringBuilder; + resultString: String; + endStart, ending, quietEnd: Integer; + endRange: TArray; + resultPoints: TArray; + left, right: Single; + resultPointCallback: TResultPointCallback; + obj: TObject; + resPoint: IResultPoint; + decodeResult, extensionResult: TReadResult; + format: TBarcodeFormat; + allowedExtensions: TArray; + valid: Boolean; + extensionLength: Integer; + countryID: String; +begin + Result := nil; + resultPointCallback := nil; + + if ((hints <> nil) and + (hints.ContainsKey(TDecodeHintType.NEED_RESULT_POINT_CALLBACK))) then + begin + obj := hints[TDecodeHintType.NEED_RESULT_POINT_CALLBACK]; + if (obj is TResultPointEventObject) then + resultPointCallback := TResultPointEventObject(obj).Event; + end; + + res := decodeRowStringBuffer; + res.Length := 0; + endStart := DecodeMiddle(row, startGuardRange, res); + if (endStart < 0) then + exit; + + if Assigned(resultPointCallback) then + begin + resPoint := TResultPointHelpers.CreateResultPoint(endStart, rowNumber); + resultPointCallback(resPoint); + end; + + endRange := decodeEnd(row, endStart); + if (endRange = nil) then + exit; + + if Assigned(resultPointCallback) then + begin + resPoint := TResultPointHelpers.CreateResultPoint + ((endRange[0] + endRange[1]) div 2, rowNumber); + resultPointCallback(resPoint); + end; + + ending := endRange[1]; + quietEnd := (ending + (ending - endRange[0])); + if ((quietEnd >= row.Size) or not row.isRange(ending, quietEnd, false)) then + exit; + + resultString := res.ToString; + if (Length(resultString) < 8) then + exit; + if (not checkChecksum(resultString)) then + exit; + left := ((startGuardRange[1] + startGuardRange[0]) div 2); + right := ((endRange[1] + endRange[0]) div 2); + format := BarcodeFormat; + resultPoints := TArray.Create + (TResultPointHelpers.CreateResultPoint(left, rowNumber), + TResultPointHelpers.CreateResultPoint(right, rowNumber)); + + decodeResult := TReadResult.Create(resultString, nil, resultPoints, format); + extensionResult := extensionReader.decodeRow(rowNumber, row, endRange[1]); + if (extensionResult <> nil) then + begin + decodeResult.putMetadata(TResultMetadataType.UPC_EAN_EXTENSION, + TResultMetaData.CreateStringMetadata(extensionResult.Text)); + decodeResult.putAllMetadata(extensionResult.ResultMetadata); + decodeResult.addResultPoints(extensionResult.resultPoints); + extensionLength := Length(extensionResult.Text); + extensionResult.Free; + + if (hints <> nil) and + (hints.ContainsKey(TDecodeHintType.ALLOWED_EAN_EXTENSIONS)) then + allowedExtensions := TArray + (hints[TDecodeHintType.ALLOWED_EAN_EXTENSIONS]) + else + allowedExtensions := nil; + + if (allowedExtensions <> nil) then + begin + valid := false; + + for len in allowedExtensions do + begin + if (extensionLength = len) then + begin + valid := true; + break; + end; + end; + if (not valid) then + exit; + end + end; + + case format of + TBarcodeFormat.EAN_13, TBarcodeFormat.UPC_A: + begin + countryID := eanManSupport.lookupCountryIdentifier(resultString); + if (countryID <> '') then + decodeResult.putMetadata(TResultMetadataType.POSSIBLE_COUNTRY, + TResultMetaData.CreateStringMetadata(countryID)); + end; + end; + + Result := decodeResult; +end; + +initialization + +TUPCEANReader.InitializeClass; + +finalization + +TUPCEANReader.FinalizeClass; + +end. diff --git a/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEReader.pas b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEReader.pas new file mode 100644 index 0000000..4205a00 --- /dev/null +++ b/android-client/ThirdParty/ZXing/1D Barcodes/ZXing.OneD.UPCEReader.pas @@ -0,0 +1,235 @@ +unit ZXing.OneD.UPCEReader; +{ + * 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 Authors: Sean Owen + * Delphi Implementation by E. Spelt +} + +interface + +uses + System.SysUtils, + System.Generics.Collections, + Math, + ZXing.OneD.OneDReader, + ZXing.Common.BitArray, + ZXing.BinaryBitmap, + ZXing.ReadResult, + ZXing.DecodeHintType, + ZXing.ResultPoint, + ZXing.BarcodeFormat, + ZXing.Helpers, + ZXing.OneD.EAN13Reader, + ZXing.OneD.UPCEANReader; + +type + + T2DIntArray = TArray>; + + TUPCEReader = class(TUPCEANReader) + private + class var decodeMiddleCounters: TArray; + class var MIDDLE_END_PATTERN: TArray; + class var NUMSYS_AND_CHECK_DIGIT_PATTERNS: T2DIntArray; + + class procedure DoInitialize(); + class procedure DoFinalize(); + class function determineNumSysAndCheckDigit(resultString: TStringBuilder; + lgPatternFound: Integer): boolean; static; + + protected + + class function checkChecksum(const s: string): boolean; override; + class function decodeEnd(const row: IBitArray; const endStart: Integer) + : TArray; override; + + public + class function DecodeMiddle(const row: IBitArray; + const startRange: TArray; const res: TStringBuilder) + : Integer; override; + + public + class function convertUPCEtoUPCA(upce: string): string; static; + + function BarcodeFormat: TBarcodeFormat; override; + end; + +implementation + +{ TUPCEReader } + +class function TUPCEReader.determineNumSysAndCheckDigit + (resultString: TStringBuilder; lgPatternFound: Integer): boolean; +var + numSys, d: Integer; +begin + numSys := 0; + while ((numSys <= 1)) do + begin + d := 0; + while ((d < 10)) do + begin + if (lgPatternFound = TUPCEReader.NUMSYS_AND_CHECK_DIGIT_PATTERNS + [numSys][d]) then + begin + resultString.Insert(0, Char($30 + numSys) ); + resultString.Append(char($30 + d)); + begin + Result := true; + exit + end + end; + inc(d) + end; + inc(numSys) + end; + + Result := false; +end; + +class function TUPCEReader.checkChecksum(const s: string): boolean; +begin + Result := inherited checkChecksum(TUPCEReader.convertUPCEtoUPCA(s)) +end; + +class function TUPCEReader.convertUPCEtoUPCA(upce: string): string; +var + upceChars: string; + res: TStringBuilder; + lastChar: char; +begin + upceChars := upce.Substring(1, 6); + res := TStringBuilder.Create(12); + res.Append(upce.Chars[0]); + lastChar := upceChars.Chars[5]; + case lastChar of + '0', '1', '2': + begin + res.Append(upceChars, 0, 2); + res.Append(lastChar); + res.Append('0000'); + res.Append(upceChars, 2, 3); + end; + '3': + begin + res.Append(upceChars, 0, 3); + res.Append('00000'); + res.Append(upceChars, 3, 2); + end; + '4': + begin + res.Append(upceChars, 0, 4); + res.Append('00000'); + res.Append(upceChars.Chars[4]); + end; + else + begin + res.Append(upceChars, 0, 5); + res.Append('0000'); + res.Append(lastChar); + end; + end; + + res.Append(upce.Chars[7]); + Result := res.ToString; + res.Free; +end; + +class function TUPCEReader.decodeEnd(const row: IBitArray; + const endStart: Integer): TArray; +begin + Result := TUPCEANReader.findGuardPattern(row, endStart, true, + TUPCEReader.MIDDLE_END_PATTERN); +end; + +class function TUPCEReader.DecodeMiddle(const row: IBitArray; + const startRange: TArray; const res: TStringBuilder): Integer; +var + bestMatch: Integer; + counter, ending, lgPatternFound, rowOffset, x: Integer; + counters: TArray; +begin + + counters := self.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 < 6) and (rowOffset < ending)) do + begin + if (not TUPCEANReader.decodeDigit(row, counters, rowOffset, + TUPCEANReader.L_AND_G_PATTERNS, bestMatch)) then + begin + exit(-1); + end; + + res.Append(Char(ord('0') + bestMatch mod 10)); + + for counter in counters do + begin + inc(rowOffset, counter) + end; + + if (bestMatch >= 10) then + lgPatternFound := lgPatternFound or (1 shl (5 - x)); + + inc(x) + end; + + if (not TUPCEReader.determineNumSysAndCheckDigit(res, lgPatternFound)) then + begin + exit(-1); + end; + + Result := rowOffset; +end; + +function TUPCEReader.BarcodeFormat: TBarcodeFormat; +begin + Result := TBarcodeFormat.UPC_E; +end; + +class procedure TUPCEReader.DoInitialize; +begin + MIDDLE_END_PATTERN := TArray.Create(1, 1, 1, 1, 1, 1); + NUMSYS_AND_CHECK_DIGIT_PATTERNS := + T2DIntArray.Create(TArray.Create($38, $34, 50, $31, $2C, $26, $23, + $2A, $29, $25), TArray.Create(7, 11, 13, 14, $13, $19, $1C, $15, + $16, $1A)); + decodeMiddleCounters := TArray.Create(0,0,0,0); +end; + +class procedure TUPCEReader.DoFinalize; +begin + MIDDLE_END_PATTERN := nil; + NUMSYS_AND_CHECK_DIGIT_PATTERNS := nil; + decodeMiddleCounters := nil; +end; + +initialization + +TUPCEReader.DoInitialize; + +finalization + +TUPCEReader.DoFinalize; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.BitMatrixParser.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.BitMatrixParser.pas new file mode 100644 index 0000000..7345050 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.BitMatrixParser.pas @@ -0,0 +1,564 @@ +{ + * 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.BitMatrixParser; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + ZXing.DecodeHintType, + ZXing.Common.BitMatrix, + ZXing.QrCode.Internal.FormatInformation, + ZXing.Common.Detector.MathUtils, + ZXing.Datamatrix.Internal.Version; + +type + TBitMatrixParser = class sealed + private + mappingBitMatrix: TBitMatrix; + readMappingMatrix: TBitMatrix; + Fversion: TVersion; + + /// + ///

Reads a bit of the mapping matrix accounting for boundary wrapping.

+ /// + /// Row to read in the mapping matrix + /// Column to read in the mapping matrix + /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// value of the given bit in the mapping matrix + ///
+ function readModule(row, column, numRows, numColumns: Integer): Boolean; + + /// + ///

Reads the 8 bits of the standard Utah-shaped pattern.

+ /// + ///

See ISO 16022:2006, 5.8.1 Figure 6

+ /// + /// Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern + /// Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern + /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the utah shape + ///
+ function readUtah(row, column, numRows, numColumns: Integer): Integer; + + /// + ///

Reads the 8 bits of the special corner condition 1.

+ /// + ///

See ISO 16022:2006, Figure F.3

+ /// + /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the Corner condition 1 + ///
+ function readCorner1(numRows, numColumns: Integer): Integer; + + /// + ///

Reads the 8 bits of the special corner condition 2.

+ /// + ///

See ISO 16022:2006, Figure F.4

+ /// + /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the Corner condition 2 + ///
+ function readCorner2(numRows, numColumns: Integer): Integer; + + /// + ///

Reads the 8 bits of the special corner condition 3.

+ /// + ///

See ISO 16022:2006, Figure F.5

+ /// + /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the Corner condition 3 + ///
+ function readCorner3(numRows, numColumns: Integer): Integer; + + /// + ///

Reads the 8 bits of the special corner condition 4.

+ /// + ///

See ISO 16022:2006, Figure F.6

+ /// + /// Number of rows in the mapping matrix + /// Number of columns in the mapping matrix + /// byte from the Corner condition 4 + ///
+ function readCorner4(numRows, numColumns: Integer): Integer; + + /// + ///

Creates the version object based on the dimension of the original bit matrix from + /// the datamatrix code.

+ /// + ///

See ISO 16022:2006 Table 7 - ECC 200 symbol attributes

+ /// + /// Original including alignment patterns + /// encapsulating the Data Matrix Code's "version" + /// if the dimensions of the mapping matrix are not valid + /// Data Matrix dimensions. + ///
+ function readVersion(BitMatrix: TBitMatrix): TVersion; + public + /// {@link TBitMatrix} to parse + /// ReaderException if dimension is not >= 21 and 1 mod 4 + constructor Create(const BitMatrix: TBitMatrix); + + + /// + ///

Extracts the data region from a that contains + /// alignment patterns.

+ /// + /// Original with alignment patterns + /// BitMatrix that has the alignment patterns removed + ///
+ function extractDataRegion(BitMatrix: TBitMatrix): TBitMatrix; + + /// + ///

Reads the bits in the representing the mapping matrix (No alignment patterns) + /// in the correct order in order to reconstitute the codewords bytes contained within the + /// Data Matrix Code.

+ /// + /// bytes encoded within the Data Matrix Code + /// if the exact number of bytes expected is not read + ///
+ function readCodewords: TArray; + destructor Destroy; override; + + property Version: TVersion read Fversion; + end; + +implementation + +{ TBitMatrixParser } + +constructor TBitMatrixParser.Create(const BitMatrix: TBitMatrix); +var + dimension: Integer; +begin + dimension := BitMatrix.Height; + if (((dimension >= 8) and (dimension <= 144)) and ((dimension and $01) = 0)) + then + begin + self.Fversion := readVersion(BitMatrix); + if (self.Version <> nil) then + begin + self.mappingBitMatrix := extractDataRegion(BitMatrix); + self.readMappingMatrix := TBitMatrix.Create(self.mappingBitMatrix.Width, + self.mappingBitMatrix.Height) + end; + end; +end; + +destructor TBitMatrixParser.Destroy; +begin + self.mappingBitMatrix.Free; + self.readMappingMatrix.Free; + inherited; +end; + + + +function TBitMatrixParser.readVersion(BitMatrix: TBitMatrix): TVersion; +begin + Result := TVersion.getVersionForDimensions(BitMatrix.Height, BitMatrix.Width); +end; + +function TBitMatrixParser.readCodewords: TArray; +var + resultOffset, row, column, numRows, numColumns: Integer; + corner1Read, corner2Read, corner3Read, corner4Read: Boolean; +begin + Result := TArray.Create(); + SetLength(Result, Version.TotalCodewords); + resultOffset := 0; + + row := 4; + column := 0; + + numRows := self.mappingBitMatrix.Height; + numColumns := self.mappingBitMatrix.Width; + + corner1Read := false; + corner2Read := false; + corner3Read := false; + corner4Read := false; + + // Read all of the codewords + while ((row < numRows) or (column < numColumns)) do + begin + // Check the four corner cases + if ((row = numRows) and (column = 0) and (not corner1Read)) then + begin + Result[resultOffset] := Byte(readCorner1(numRows, numColumns)); + Inc(resultOffset); + Dec(row, 2); + Inc(column, 2); + corner1Read := true; + end + else + begin + if ((row = (numRows - 2)) and (column = 0) and ((numColumns and $03) <> 0) + and (not corner2Read)) then + begin + Result[resultOffset] := Byte(readCorner2(numRows, numColumns)); + Inc(resultOffset); + Dec(row, 2); + Inc(column, 2); + corner2Read := true; + end + else + begin + if ((row = (numRows + 4)) and (column = 2) and + ((numColumns and $07) = 0) and (not corner3Read)) then + begin + Result[resultOffset] := Byte(readCorner3(numRows, numColumns)); + Inc(resultOffset); + Dec(row, 2); + Inc(column, 2); + corner3Read := true; + end + else + begin + if ((row = (numRows - 2)) and (column = 0) and + ((numColumns and $07) = 4) and (not corner4Read)) then + begin + Result[resultOffset] := Byte(readCorner4(numRows, numColumns)); + Inc(resultOffset); + Dec(row, 2); + Inc(column, 2); + corner4Read := true; + end + else + begin + // Sweep upward diagonally to the right + while ((row >= 0) and (column < numColumns)) do + begin + if ((row < numRows) and (column >= 0) and + (not readMappingMatrix[column, row])) then + begin + Result[resultOffset] := + Byte(readUtah(row, column, numRows, numColumns)); + Inc(resultOffset); + end; + Dec(row, 2); + Inc(column, 2) + end; + Inc(row); + Inc(column, 3); + + // Sweep downward diagonally to the left + while ((row < numRows) and (column >= 0)) do + begin + if ((row >= 0) and (column < numColumns) and + (not readMappingMatrix[column, row])) then + begin + Result[resultOffset] := + Byte(readUtah(row, column, numRows, numColumns)); + Inc(resultOffset); + end; + Inc(row, 2); + Dec(column, 2) + end; + Inc(row, 3); + Inc(column) + end; + end; + end; + end; + end; + + if (resultOffset <> Version.TotalCodewords) then + Result := nil; +end; + +function TBitMatrixParser.readModule(row, column, numRows, + numColumns: Integer): Boolean; +begin + // Adjust the row and column indices based on boundary wrapping + if (row < 0) then + begin + Inc(row, numRows); + Inc(column, (4 - ((numRows + 4) and $07))) + end; + if (column < 0) then + begin + Inc(column, numColumns); + Inc(row, (4 - ((numColumns + 4) and $07))) + end; + readMappingMatrix[column, row] := true; + + Result := mappingBitMatrix[column, row]; +end; + +function TBitMatrixParser.readUtah(row, column, numRows, + numColumns: Integer): Integer; +var + currentByte: Byte; +begin + currentByte := 0; + if (readModule((row - 2), (column - 2), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((row - 2), (column - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((row - 1), (column - 2), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((row - 1), (column - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((row - 1), column, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(row, (column - 2), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(row, (column - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(row, column, numRows, numColumns)) then + currentByte := (currentByte or 1); + + Result := currentByte; +end; + +function TBitMatrixParser.readCorner1(numRows, numColumns: Integer): Integer; +var + currentByte: Byte; +begin + currentByte := 0; + if (readModule((numRows - 1), 0, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((numRows - 1), 1, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((numRows - 1), 2, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 2), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(1, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(2, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(3, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + Result := currentByte; +end; + +function TBitMatrixParser.readCorner2(numRows, numColumns: Integer): Integer; +var + currentByte: Byte; +begin + currentByte := 0; + if (readModule((numRows - 3), 0, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((numRows - 2), 0, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((numRows - 1), 0, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 4), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 3), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 2), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(1, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + Result := currentByte; +end; + +function TBitMatrixParser.readCorner3(numRows, numColumns: Integer): Integer; +var + currentByte: Byte; +begin + currentByte := 0; + if (readModule((numRows - 1), 0, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((numRows - 1), (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 3), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 2), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(1, (numColumns - 3), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(1, (numColumns - 2), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(1, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + Result := currentByte; +end; + +function TBitMatrixParser.readCorner4(numRows, numColumns: Integer): Integer; +var + currentByte: Byte; +begin + currentByte := 0; + if (readModule((numRows - 3), 0, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((numRows - 2), 0, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule((numRows - 1), 0, numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (self.readModule(0, (numColumns - 2), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(0, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(1, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(2, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + currentByte := (currentByte shl 1); + if (readModule(3, (numColumns - 1), numRows, numColumns)) then + currentByte := (currentByte or 1); + + Result := currentByte; +end; + +function TBitMatrixParser.extractDataRegion(BitMatrix: TBitMatrix): TBitMatrix; +var + i, j, symbolSizeRows, dataRegionSizeRows, + dataRegionSizeColumns, numDataRegionsRow, numDataRegionsColumn, + sizeDataRegionRow, sizeDataRegionColumn, dataRegionRow, dataRegionRowOffset, + dataRegionColumn, dataRegionColumnOffset, readRowOffset, writeRowOffset, + readColumnOffset, writeColumnOffset: Integer; + bitMatrixWithoutAlignment: TBitMatrix; +begin + symbolSizeRows := Version.symbolSizeRows; + + if (BitMatrix.Height <> symbolSizeRows) then + raise EArgumentException.Create + ('Dimension of bitMarix must match the version size'); + + dataRegionSizeRows := Version.dataRegionSizeRows; + dataRegionSizeColumns := Version.dataRegionSizeColumns; + + numDataRegionsRow := (symbolSizeRows div dataRegionSizeRows); + numDataRegionsColumn := (Version.symbolSizeColumns div dataRegionSizeColumns); + + sizeDataRegionRow := (numDataRegionsRow * dataRegionSizeRows); + sizeDataRegionColumn := (numDataRegionsColumn * dataRegionSizeColumns); + + bitMatrixWithoutAlignment := TBitMatrix.Create(sizeDataRegionColumn, + sizeDataRegionRow); + + for dataRegionRow := 0 to Pred(numDataRegionsRow) do + begin + dataRegionRowOffset := (dataRegionRow * dataRegionSizeRows); + for dataRegionColumn := 0 to Pred(numDataRegionsColumn) do + begin + dataRegionColumnOffset := (dataRegionColumn * dataRegionSizeColumns); + for i := 0 to Pred(dataRegionSizeRows) do + begin + readRowOffset := (dataRegionRow * (dataRegionSizeRows + 2)) + 1 + i; + writeRowOffset := (dataRegionRowOffset + i); + for j := 0 to Pred(dataRegionSizeColumns) do + begin + readColumnOffset := + (dataRegionColumn * (dataRegionSizeColumns + 2)) + 1 + j; + if (BitMatrix[readColumnOffset, readRowOffset]) then + begin + writeColumnOffset := (dataRegionColumnOffset + j); + bitMatrixWithoutAlignment[writeColumnOffset, + writeRowOffset] := true; + end; + end; + end; + end; + end; + + Result := bitMatrixWithoutAlignment; + +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.DataBlock.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.DataBlock.pas new file mode 100644 index 0000000..7b87ab5 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.DataBlock.pas @@ -0,0 +1,179 @@ +{ + * 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.DataBlock; + +interface + +uses + System.SysUtils, + ZXing.Datamatrix.Internal.Version; + +type + /// + ///

Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into + /// multiple blocks, each of which is a unit of data and error-correction codewords. Each + /// is represented by an instance of this class.

+ ///
+ TDataBlock = class sealed + private + Fcodewords: TArray; + FNumDataCodewords: Integer; + public + constructor Create(const Acodewords: TArray; + const ANumDataCodewords: Integer); + destructor Destroy;override; + + class function getDataBlocks(rawCodewords: TArray; + version: TVersion): TArray; + + property codewords: TArray read Fcodewords; + property NumDataCodewords: Integer read FNumDataCodewords; + end; + +implementation + +{ TDataBlock } + +constructor TDataBlock.Create(const Acodewords: TArray; + const ANumDataCodewords: Integer); +begin + FnumDataCodewords := AnumDataCodewords; + Fcodewords := Acodewords; +end; + +destructor TDataBlock.Destroy; +begin + Fcodewords := nil; + inherited; +end; + +class function TDataBlock.getDataBlocks(rawCodewords: TArray; + version: TVersion): TArray; +var + i, j: Integer; + ecBlock : TVersion.TECB; + ecBlocks : TVersion.TECBlocks; + totalBlocks : Integer; + ecBlockArray : TArray; + byteArray : TArray; + numResultBlocks, + numDataCodewords, + numBlockCodewords, + longerBlocksTotalCodewords, + //shorterBlocksTotalCodewords + longerBlocksNumDataCodewords, + shorterBlocksNumDataCodewords, + rawCodewordsOffset, + numLongerBlocks, + max, + iOffset, + jOffset : Integer; + specialVersion: Boolean; +begin + // Figure out the number and size of data blocks used by this version + ecBlocks := version.ecBlocks; + + // First count the total number of data blocks + totalBlocks := 0; + ecBlockArray := ecBlocks.ECBBlocksValue; + for ecBlock in ecBlockArray do + begin + inc(totalBlocks, ecBlock.Count) + end; + + // Now establish DataBlocks of the appropriate size and number of data codewords + result := TArray.Create(); + SetLength(result, totalBlocks); + numResultBlocks := 0; + + for ecBlock in ecBlockArray do + begin + for i := 0 to Pred(ecBlock.Count) do + begin + numDataCodewords := ecBlock.DataCodewords; + numBlockCodewords := (ecBlocks.ECCodewords + numDataCodewords); + byteArray := TArray.Create(); + SetLength(byteArray, numBlockCodewords); + result[numResultBlocks] := TDataBlock.Create(byteArray, numDataCodewords); + Inc(numResultBlocks); + end + end; + + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 less byte. Figure out where these start. + // TODO: There is only one case where there is a difference for Data Matrix for size 144 + longerBlocksTotalCodewords := Length(result[0].codewords); + //shorterBlocksTotalCodewords := (longerBlocksTotalCodewords - 1); + + longerBlocksNumDataCodewords := (longerBlocksTotalCodewords - ecBlocks.ECCodewords); + shorterBlocksNumDataCodewords := (longerBlocksNumDataCodewords - 1); + // The last elements of result may be 1 element shorter for 144 matrix + // first fill out as many elements as all of them have minus 1 + rawCodewordsOffset := 0; + for i := 0 to Pred(shorterBlocksNumDataCodewords) do + begin + for j := 0 to Pred(numResultBlocks) do + begin + result[j].codewords[i] := rawCodewords[rawCodewordsOffset]; + Inc(rawCodewordsOffset); + end; + end; + + // Fill out the last data block in the longer ones + specialVersion := (version.versionNumber = 24); + if specialVersion + then + numLongerBlocks := 8 + else + numLongerBlocks := numResultBlocks; + for j := 0 to Pred(numLongerBlocks) do + begin + result[j].codewords[(longerBlocksNumDataCodewords - 1)] := rawCodewords[rawCodewordsOffset]; + Inc(rawCodewordsOffset); + end; + + // Now add in error correction blocks + max := Length(result[0].codewords); + for i := longerBlocksNumDataCodewords to Pred(max) do + begin + for j := 0 to Pred(numResultBlocks) do + begin + if (specialVersion) + then + jOffset := (j + 8) mod numResultBlocks + else + jOffset := j; + + if (specialVersion and (jOffset > 7)) + then + iOffset := (i - 1) + else + iOffset := i; + result[jOffset].codewords[iOffset] := rawCodewords[rawCodewordsOffset]; + Inc(rawCodewordsOffset); + end; + end; + + if (not (rawCodewordsOffset = Length(rawCodewords))) + then + raise EArgumentException.Create('Arguments error'); +end; + +end. \ No newline at end of file diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.DecodedBitStreamParser.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.DecodedBitStreamParser.pas new file mode 100644 index 0000000..0c9be18 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.DecodedBitStreamParser.pas @@ -0,0 +1,903 @@ +{ + * 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 Authors: bbrown@google.com (Brian Brown) and Sean Owen + * Delphi Implementation by K. Gossens +} + +unit ZXing.Datamatrix.Internal.DecodedBitStreamParser; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + ZXing.DecoderResult, + ZXing.ByteSegments, + ZXing.BitSource; + +type + /// + ///

Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes + /// in one Data Matrix Code. This class decodes the bits back into text.

+ /// + ///

See ISO 16022:2006, 5.2.1 - 5.2.9.2

+ ///
+ TDecodedBitStreamParser = class abstract + type + TMode = (PAD_ENCODE, // Not really a mode + ASCII_ENCODE, C40_ENCODE, TEXT_ENCODE, ANSIX12_ENCODE, EDIFACT_ENCODE, + BASE256_ENCODE); + private + class var C40_BASIC_SET_CHARS, C40_SHIFT2_SET_CHARS, TEXT_BASIC_SET_CHARS, + TEXT_SHIFT2_SET_CHARS, TEXT_SHIFT3_SET_CHARS: TArray; + + class procedure InitializeClass; + class procedure FinalizeClass; + + class function decodeC40Segment(bits: TBitSource; + res: TStringBuilder): boolean; + class function decodeTextSegment(bits: TBitSource; + res: TStringBuilder): boolean; + class function decodeAnsiX12Segment(bits: TBitSource; + res: TStringBuilder): boolean; + class function decodeEdifactSegment(bits: TBitSource; + res: TStringBuilder): boolean; + class function decodeBase256Segment(bits: TBitSource; res: TStringBuilder; + byteSegments:IByteSegments ): boolean; + class function decodeAsciiSegment(bits: TBitSource; res: TStringBuilder; + resultTrailer: TStringBuilder; var mode: TMode): boolean; + class procedure parseTwoBytes(firstByte: Integer; secondByte: Integer; + result: TArray); + class function unrandomize255State(randomizedBase256Codeword: Integer; + base256CodewordPosition: Integer): Integer; + public + class function decode(bytes: TArray): TDecoderResult; + end; + +implementation + +{ TDecodedBitStreamParser } + +class function TDecodedBitStreamParser.decode(bytes: TArray) + : TDecoderResult; +var + bits: TBitSource; + res, resultTrailer: TStringBuilder; + byteSegments: IByteSegments; + mode: TMode; + +begin + bits := TBitSource.Create(bytes); + res := TStringBuilder.Create(100); + resultTrailer := TStringBuilder.Create(0); + byteSegments := ByteSegmentsCreate; + + try + + byteSegments.Add(TArray.Create()); // TODO (KG): Validation + mode := TMode.ASCII_ENCODE; + while ((mode <> TMode.PAD_ENCODE) and (bits.available() > 0)) do + begin + if (mode = TMode.ASCII_ENCODE) then + begin + if (not TDecodedBitStreamParser.decodeAsciiSegment(bits, res, + resultTrailer, mode)) then + begin + result := nil; // this line was totally missing. I assume the correct thing is to set result = nil. + exit; + end; + end + else + begin + case mode of + TMode.C40_ENCODE: + begin + if (not TDecodedBitStreamParser.decodeC40Segment(bits, res)) then + begin + result := nil; + exit; + end; + end; + TMode.TEXT_ENCODE: + begin + if (not TDecodedBitStreamParser.decodeTextSegment(bits, res)) then + begin + result := nil; + exit; + end; + end; + TMode.ANSIX12_ENCODE: + begin + if (not TDecodedBitStreamParser.decodeAnsiX12Segment(bits, res)) + then + begin + result := nil; + exit; + end; + end; + TMode.EDIFACT_ENCODE: + begin + if (not TDecodedBitStreamParser.decodeEdifactSegment(bits, res)) + then + begin + result := nil; + exit; + end; + end; + TMode.BASE256_ENCODE: + begin + if (not TDecodedBitStreamParser.decodeBase256Segment(bits, res, + byteSegments)) then + begin + result := nil; + exit; + end; + end; + else + begin + result := nil; + exit; + end; + end; + + mode := TMode.ASCII_ENCODE; + end; + end; + + if (resultTrailer.Length > 0) then + res.Append(resultTrailer.ToString); + + if (byteSegments.Count = 0) then + result := TDecoderResult.Create(bytes, res.ToString, nil, '') + else + result := TDecoderResult.Create(bytes, res.ToString, byteSegments, ''); + + finally + bits.Free; + res.Free; + resultTrailer.Free; +// +// for i := 0 to byteSegments.Count - 1 do +// begin +// +// end; +// +// byteSegments.Free; + end; + +end; + +/// +/// See ISO 16022:2006, 5.2.7 +/// +class function TDecodedBitStreamParser.decodeAnsiX12Segment(bits: TBitSource; + res: TStringBuilder): boolean; +var + i: Integer; + cValues: TArray; + firstByte: Integer; + cValue: Integer; +begin + // Three ANSI X12 values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + + cValues := TArray.Create(0, 0, 0); + while (bits.available() > 0) do + begin + // If there is only one byte left then it will be encoded as ASCII + if (bits.available = 8) then + begin + result := true; + exit; + end; + firstByte := bits.readBits(8); + if (firstByte = 254) then + begin + // Unlatch codeword + result := true; + exit; + end; + + TDecodedBitStreamParser.parseTwoBytes(firstByte, bits.readBits(8), cValues); + + for i := 0 to 2 do + begin + cValue := cValues[i]; + case cValue of + 0: + begin + // X12 segment terminator + res.Append(#13); + end; + 1: + begin + // X12 segment separator * + res.Append('*'); + end; + 2: + begin + // X12 sub-element separator > + res.Append('>'); + end; + 3: + begin + // space + res.Append(' '); + end; + else + begin + if (cValue < 14) then + // 0 - 9 + res.Append(Char(cValue + 44)) + else if (cValue < 40) then + // A - Z + res.Append(Char(cValue + 51)) + else + begin + result := false; + exit; + end; + end; + end; + end; + end;; + + result := true; +end; + +/// +/// See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 +/// +class function TDecodedBitStreamParser.decodeAsciiSegment(bits: TBitSource; + res: TStringBuilder; resultTrailer: TStringBuilder; var mode: TMode): boolean; +var + oneByte: Integer; + upperShift: boolean; + value: Byte; +begin + upperShift := false; + mode := TMode.ASCII_ENCODE; + + while (bits.available() > 0) do + begin + oneByte := bits.readBits(8); + if (oneByte = 0) then + begin + result := false; + exit; + end + else + begin + if (oneByte <= 128) then + begin + // ASCII data (ASCII value + 1) + if (upperShift) then + begin + Inc(oneByte, 128); + // upperShift := false; + end; + res.Append(Char(oneByte - 1)); + mode := TMode.ASCII_ENCODE; + + result := true; + exit; + end + else + begin + if (oneByte = 129) then + begin + // Pad + mode := TMode.PAD_ENCODE; + result := true; + exit; + end + else + begin + if (oneByte <= 229) then + begin + // 2-digit data 00-99 (Numeric Value + 130) + value := (oneByte - 130); + if (value < 10) then + // pad with '0' for single digit values + res.Append('0'); + res.Append(value); + end + else + begin + if (oneByte = 230) then + begin + // Latch to C40 encodation + mode := TMode.C40_ENCODE; + result := true; + exit; + end + else + begin + if (oneByte = 231) then + begin + // Latch to Base 256 encodation + mode := TMode.BASE256_ENCODE; + result := true; + exit; + end + else + begin + if (oneByte = 232) then + begin + // FNC1 + res.Append(Char(29)); // translate as ASCII 29 + end + else + begin + if ((oneByte = 233) or (oneByte = 234)) then + begin + // Structured Append, Reader Programming + // Ignore these symbols for now + // throw EReaderException.Instance; + end + else + begin + if (oneByte = 235) then + begin + // Upper Shift (shift to Extended ASCII) + upperShift := true; + end + else + begin + if (oneByte = 236) then + begin + // 05 Macro + res.Append('[)>' + #$001E05 + #$001D); + res.Insert(0, #$001E + #$0004); + end + else + begin + if (oneByte = 237) then + begin + // 06 Macro + res.Append('[)>' + #$001E06 + #$001D); + res.Insert(0, #$001E + #$0004); + end + else + begin + if (oneByte = 238) then + begin + // Latch to ANSI X12 encodation + mode := TMode.ANSIX12_ENCODE; + result := true; + exit; + end + else + begin + if (oneByte = 239) then + begin + // Latch to Text encodation + mode := TMode.TEXT_ENCODE; + result := true; + exit; + end + else + begin + if (oneByte = 240) then + begin + mode := TMode.EDIFACT_ENCODE; + result := true; + exit; + end + else + begin + if (oneByte = 241) then + begin + // ECI Character + // TODO: I think we need to support ECI + // throw TReaderException.Instance; + // Ignore this symbol for now + end + else if (oneByte >= 242) then + begin + // Not to be used in ASCII encodation + // ... but work around encoders that end with 254, latch back to ASCII + if ((oneByte <> 254) or (bits.available() <> 0)) then + begin + result := false; + exit; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + + mode := TMode.ASCII_ENCODE; + result := true; +end; + +/// +/// See ISO 16022:2006, 5.2.9 and Annex B, B.2 +/// +class function TDecodedBitStreamParser.decodeBase256Segment(bits: TBitSource; + res: TStringBuilder; byteSegments: IByteSegments ): boolean; +var + i, Count, codewordPosition, d1: Integer; + bytes: TArray; +begin + // Figure out how long the Base 256 Segment is. + codewordPosition := (1 + bits.ByteOffset); // position is 1-indexed + d1 := TDecodedBitStreamParser.unrandomize255State(bits.readBits(8), + codewordPosition); + Inc(codewordPosition); + if (d1 = 0) then + // Read the remainder of the symbol + Count := (bits.available div 8) + else if (d1 < 250) then + Count := d1 + else + begin + Count := ((250 * (d1 - 249)) + TDecodedBitStreamParser.unrandomize255State + (bits.readBits(8), codewordPosition)); + Inc(codewordPosition); + end; + + // We're seeing NegativeArraySizeException errors from users. + if (Count < 0) then + begin + result := false; + exit; + end; + + bytes := TArray.Create(); + SetLength(bytes, Count); + + for i := 0 to Pred(Count) do + begin + // Have seen this particular error in the wild, such as at + // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2 + if (bits.available() < 8) then + begin + result := false; + exit; + end; + bytes[i] := Byte(TDecodedBitStreamParser.unrandomize255State + (bits.readBits(8), codewordPosition)); + Inc(codewordPosition); + end; + byteSegments.Add(bytes); + try + res.Append(TEncoding.GetEncoding('ISO-8859-1').GetString(bytes)) + except + on uee: Exception do + raise EInvalidOpException.Create + ('Platform does not support required encoding: ' + uee.Message) + end; + + result := true; +end; + +/// +/// See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 +/// +class function TDecodedBitStreamParser.decodeC40Segment(bits: TBitSource; + res: TStringBuilder): boolean; +var + i: Integer; + c40char: Char; + cValues: TArray; + upperShift: boolean; + shift: Integer; + firstByte: Byte; + cValue: Integer; +begin + // Three C40 values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + // TODO: The Upper Shift with C40 doesn't work in the 4 value scenario all the time + upperShift := false; + + cValues := TArray.Create(0, 0, 0); + shift := 0; + + while (bits.available() > 0) do + begin + // If there is only one byte left then it will be encoded as ASCII + if (bits.available() = 8) then + begin + result := true; + exit; + end; + firstByte := bits.readBits(8); + if (firstByte = 254) then + begin + // Unlatch codeword + result := true; + exit; + end; + + TDecodedBitStreamParser.parseTwoBytes(firstByte, bits.readBits(8), cValues); + + for i := 0 to 2 do + begin + cValue := cValues[i]; + case shift of + 0: + begin + if (cValue < 3) then + shift := (cValue + 1) + else + begin + if (cValue < Length(C40_BASIC_SET_CHARS)) then + begin + c40char := C40_BASIC_SET_CHARS[cValue]; + if (upperShift) then + begin + res.Append(Char(c40char) + Char(128)); + upperShift := false; + end + else + res.Append(c40char); + end + else + begin + result := false; + exit; + end; + end; + end; + 1: + begin + if (upperShift) then + begin + res.Append(Char(cValue) + Char(128)); + upperShift := false; + end + else + res.Append(Char(cValue)); + shift := 0; + end; + 2: + begin + if (cValue < Length(C40_SHIFT2_SET_CHARS)) then + begin + c40char := C40_SHIFT2_SET_CHARS[cValue]; + if (upperShift) then + begin + res.Append(Char(c40char) + Char(128)); + upperShift := false; + end + else + res.Append(c40char); + end + else + begin + if (cValue = 27) then + // FNC1 + res.Append(Char(29)) // translate as ASCII 29 + else if (cValue = 30) then + // Upper Shift + upperShift := true + else + begin + result := false; + exit; + end; + end; + shift := 0; + end; + 3: + begin + if (upperShift) then + begin + res.Append(Char(cValue + 254)); + upperShift := false; + end + else + res.Append(Char(cValue + 96)); + shift := 0; + end; + else + begin + result := false; + exit; + end; + end; + end; + end; + + result := true; +end; + +/// +/// See ISO 16022:2006, 5.2.8 and Annex C Table C.3 +/// +class function TDecodedBitStreamParser.decodeEdifactSegment(bits: TBitSource; + res: TStringBuilder): boolean; +var + i: Integer; + edifactValue: Integer; + bitsLeft: Integer; +begin + while (bits.available() > 0) do + begin + // If there is only two or less bytes left then it will be encoded as ASCII + if (bits.available() <= 16) then + begin + result := true; + exit; + end; + + for i := 0 to 3 do + begin + edifactValue := bits.readBits(6); + + // Check for the unlatch character + if (edifactValue = $1F) then + begin + // 011111 + // Read rest of byte, which should be 0, and stop + bitsLeft := (8 - bits.BitOffset); + if (not bitsLeft = 8) then + bits.readBits(bitsLeft); + + result := true; + exit; + end; + + if ((edifactValue and $20) = 0) then + begin + // no 1 in the leading (6th) bit + edifactValue := (edifactValue or $40); + // Add a leading 01 to the 6 bit binary value + end; + res.Append(Char(edifactValue)); + end; + end; + + result := true; +end; + +/// +/// See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 +/// +class function TDecodedBitStreamParser.decodeTextSegment(bits: TBitSource; + res: TStringBuilder): boolean; +var + textChar: Char; + cValues: TArray; + upperShift: boolean; + i, shift: Integer; + firstByte: Integer; + cValue: Integer; +begin + // Three Text values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + // TODO: The Upper Shift with Text doesn't work in the 4 value scenario all the time + upperShift := false; + + cValues := TArray.Create(0, 0, 0); + shift := 0; + + while (bits.available() > 0) do + begin + // If there is only one byte left then it will be encoded as ASCII + if (bits.available() = 8) then + begin + result := true; + exit; + end; + + firstByte := bits.readBits(8); + if (firstByte = 254) then + begin + // Unlatch codeword + result := true; + exit; + end; + + TDecodedBitStreamParser.parseTwoBytes(firstByte, bits.readBits(8), cValues); + + for i := 0 to 2 do + begin + cValue := cValues[i]; + + case (shift) of + 0: + begin + if (cValue < 3) then + shift := (cValue + 1) + else + begin + if (cValue < Length(TEXT_BASIC_SET_CHARS)) then + begin + textChar := TEXT_BASIC_SET_CHARS[cValue]; + if (upperShift) then + begin + res.Append(Char(textChar) + Char(128)); + upperShift := false; + end + else + res.Append(textChar); + end + else + begin + result := false; + exit; + end; + end; + end; + 1: + begin + if (upperShift) then + begin + res.Append(Char(cValue + 128)); + upperShift := false; + end + else + res.Append(Char(cValue)); + shift := 0; + end; + 2: + begin + // Shift 2 for Text is the same encoding as C40 + if (cValue < Length(TEXT_SHIFT2_SET_CHARS)) then + begin + textChar := TEXT_SHIFT2_SET_CHARS[cValue]; + if (upperShift) then + begin + res.Append(Char(textChar) + Char(128)); + upperShift := false; + end + else + res.Append(textChar); + end + else + begin + if (cValue = 27) then + // FNC1 + res.Append(Char(29)) // translate as ASCII 29 + else if (cValue = 30) then + // Upper Shift + upperShift := true + else + begin + result := false; + exit; + end; + end; + shift := 0; + end; + 3: + begin + if (cValue < Length(TEXT_SHIFT3_SET_CHARS)) then + begin + textChar := TEXT_SHIFT3_SET_CHARS[cValue]; + if (upperShift) then + begin + res.Append(Char(textChar) + Char(128)); + upperShift := false; + end + else + res.Append(textChar); + shift := 0; + end + else + begin + result := false; + exit; + end; + end; + else + begin + result := false; + exit; + end; + end; + end; + end; + + result := true; +end; + +class procedure TDecodedBitStreamParser.parseTwoBytes(firstByte: Integer; + secondByte: Integer; result: TArray); +var + fullBitValue, temp: Integer; +begin + fullBitValue := (((firstByte shl 8) + secondByte) - 1); + temp := (fullBitValue div $640); + result[0] := temp; + dec(fullBitValue, (temp * $640)); + temp := (fullBitValue div 40); + result[1] := temp; + result[2] := (fullBitValue - (temp * 40)) +end; + +/// +/// See ISO 16022:2006, Annex B, B.2 +/// +class function TDecodedBitStreamParser.unrandomize255State + (randomizedBase256Codeword: Integer; + base256CodewordPosition: Integer): Integer; +var + pseudoRandomNumber: Integer; + tempVariable: Integer; +begin + pseudoRandomNumber := (((149 * base256CodewordPosition) mod 255) + 1); + tempVariable := (randomizedBase256Codeword - pseudoRandomNumber); + if (tempVariable >= 0) then + result := tempVariable + else + result := (tempVariable + 256); +end; + +class procedure TDecodedBitStreamParser.InitializeClass; +begin + /// + /// See ISO 16022:2006, Annex C Table C.1 + /// The C40 Basic Character Set (*'s used for placeholders for the shift values) + /// + C40_BASIC_SET_CHARS := TArray.Create('*', '*', '*', ' ', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z'); + + C40_SHIFT2_SET_CHARS := TArray.Create('!', '"', '#', '$', '%', '&', + '''', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', + '@', '[', '\', ']', '^', '_'); + + /// + /// See ISO 16022:2006, Annex C Table C.2 + /// The Text Basic Character Set (*'s used for placeholders for the shift values) + /// + TEXT_BASIC_SET_CHARS := TArray.Create('*', '*', '*', ' ', '0', '1', '2', + '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z'); + + // Shift 2 for Text is the same encoding as C40 + TEXT_SHIFT2_SET_CHARS := C40_SHIFT2_SET_CHARS; + + TEXT_SHIFT3_SET_CHARS := TArray.Create('`', 'A', 'B', 'C', 'D', 'E', + 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', ''); +end; + +class procedure TDecodedBitStreamParser.FinalizeClass; +begin + C40_BASIC_SET_CHARS := nil; + C40_SHIFT2_SET_CHARS := nil; + TEXT_BASIC_SET_CHARS := nil; + TEXT_SHIFT2_SET_CHARS := nil; + TEXT_SHIFT3_SET_CHARS := nil; +end; + +initialization + +TDecodedBitStreamParser.InitializeClass; + +finalization + +TDecodedBitStreamParser.FinalizeClass; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.Decoder.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.Decoder.pas new file mode 100644 index 0000000..c55c02b --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.Decoder.pas @@ -0,0 +1,229 @@ +{ + * 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. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.Version.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.Version.pas new file mode 100644 index 0000000..aeffebe --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.Datamatrix.Internal.Version.pas @@ -0,0 +1,290 @@ +{ + * 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.Internal.Version; + +interface + +uses + System.SysUtils, + ZXing.Common.BitMatrix, + ZXing.QrCode.Internal.FormatInformation, + ZXing.Common.Detector.MathUtils; + +type + /// + /// The Version object encapsulates attributes about a particular + /// size Data Matrix Code. + /// + TVersion = class sealed + + type + /// + ///

Encapsualtes the parameters for one error-correction block in one symbol version. + /// This includes the number of data codewords, and the number of times a block with these + /// parameters is used consecutively in the Data Matrix code version's format.

+ ///
+ TECB = class + private + Fcount: Integer; + FdataCodewords: Integer; + public + constructor Create(count: Integer; dataCodewords: Integer); + + property count: Integer read Fcount; + property dataCodewords: Integer read FdataCodewords; + end; + + /// + ///

Encapsulates a set of error-correction blocks in one symbol version. Most versions will + /// use blocks of differing sizes within one version, so, this encapsulates the parameters for + /// each set of blocks. It also holds the number of error-correction codewords per block since it + /// will be the same across all blocks within one version.

+ ///
+ TECBlocks = class + private + _ecBlocksValue: TArray; + _ecCodewords: Integer; + public + property ECBBlocksValue: TArray read _ecBlocksValue; + property ECCodewords: Integer read _ecCodewords; + + constructor Create(ECCodewords: Integer; ecBlocks: TECB); overload; + constructor Create(ECCodewords: Integer; ecBlocks1: TECB; + ecBlocks2: TECB); overload; + destructor Destroy; override; + end; + + private + FdataRegionSizeColumns: Integer; + FdataRegionSizeRows: Integer; + FecBlocks: TECBlocks; + FsymbolSizeColumns: Integer; + FsymbolSizeRows: Integer; + FtotalCodewords: Integer; + FversionNumber: Integer; + + class var buildVersions: TArray; + class procedure ClassInit; static; + class procedure ClassFinal; static; + class function GetBuildVersions: TArray; static; + + constructor Create(versionNumber, symbolSizeRows, symbolSizeColumns, + dataRegionSizeRows, dataRegionSizeColumns: Integer; ecBlocks: TECBlocks); + + public + destructor Destroy; override; + function ToString: string; override; + class function getVersionForDimensions(numRows: Integer; + numColumns: Integer): TVersion; + + property dataRegionSizeColumns: Integer read FdataRegionSizeColumns; + property dataRegionSizeRows: Integer read FdataRegionSizeRows; + property ecBlocks: TECBlocks read FecBlocks; + property symbolSizeColumns: Integer read FsymbolSizeColumns; + property symbolSizeRows: Integer read FsymbolSizeRows; + property totalCodewords: Integer read FtotalCodewords; + property versionNumber: Integer read FversionNumber; + end; + +implementation + +{ TVersion.TECB } + +constructor TVersion.TECB.Create(count, dataCodewords: Integer); +begin + self.Fcount := count; + self.FdataCodewords := dataCodewords; +end; + +{ TVersion.TECBlocks } + +constructor TVersion.TECBlocks.Create(ECCodewords: Integer; ecBlocks: TECB); +begin + self._ecCodewords := ECCodewords; + self._ecBlocksValue := TArray.Create(ecBlocks); +end; + +constructor TVersion.TECBlocks.Create(ECCodewords: Integer; ecBlocks1: TECB; + ecBlocks2: TECB); +begin + self._ecCodewords := ECCodewords; + self._ecBlocksValue := TArray.Create(ecBlocks1, ecBlocks2); +end; + +destructor TVersion.TECBlocks.Destroy; +var + ecb: TECB; + i: Integer; + +begin + + for i := 0 to Length(_ecBlocksValue) - 1 do + begin + ecb := _ecBlocksValue[i]; + FreeAndNil(ecb); + end; + + _ecBlocksValue := nil; + inherited; +end; + +{ TVersion } + +class procedure TVersion.ClassInit(); +begin + TVersion.buildVersions := TVersion.GetBuildVersions; +end; + +class procedure TVersion.ClassFinal(); +var + Version: TVersion; +begin + + for Version in TVersion.buildVersions do + begin + Version.Free; + end; + + TVersion.buildVersions := nil; +end; + +constructor TVersion.Create(versionNumber, symbolSizeRows, symbolSizeColumns, + dataRegionSizeRows, dataRegionSizeColumns: Integer; ecBlocks: TECBlocks); +var + ecBlock: TECB; + total: Integer; + ECCodewords: Integer; +begin + self.FversionNumber := versionNumber; + self.FsymbolSizeRows := symbolSizeRows; + self.FsymbolSizeColumns := symbolSizeColumns; + self.FdataRegionSizeRows := dataRegionSizeRows; + self.FdataRegionSizeColumns := dataRegionSizeColumns; + self.FecBlocks := ecBlocks; + total := 0; + ECCodewords := ecBlocks.ECCodewords; + + for ecBlock in ecBlocks.ECBBlocksValue do + begin + Inc(total, (ecBlock.count * (ecBlock.dataCodewords + ECCodewords))) + end; + + self.FtotalCodewords := total; +end; + +destructor TVersion.Destroy; +begin + + FreeAndNil(FecBlocks); + + inherited; +end; + +/// +/// See ISO 16022:2006 5.5.1 Table 7 +/// + +class function TVersion.GetBuildVersions: TArray; +begin + Result := TArray.Create(TVersion.Create(1, 10, 10, 8, 8, + TECBlocks.Create(5, TECB.Create(1, 3))), TVersion.Create(2, 12, 12, 10, 10, + TECBlocks.Create(7, TECB.Create(1, 5))), TVersion.Create(3, 14, 14, 12, 12, + TECBlocks.Create(10, TECB.Create(1, 8))), TVersion.Create(4, $10, $10, 14, + 14, TECBlocks.Create(12, TECB.Create(1, 12))), TVersion.Create(5, $12, $12, + $10, $10, TECBlocks.Create(14, TECB.Create(1, $12))), + TVersion.Create(6, 20, 20, $12, $12, TECBlocks.Create($12, + TECB.Create(1, $16))), TVersion.Create(7, $16, $16, 20, 20, + TECBlocks.Create(20, TECB.Create(1, 30))), TVersion.Create(8, $18, $18, $16, + $16, TECBlocks.Create($18, TECB.Create(1, $24))), + TVersion.Create(9, $1A, $1A, $18, $18, TECBlocks.Create($1C, + TECB.Create(1, $2C))), TVersion.Create(10, $20, $20, 14, 14, + TECBlocks.Create($24, TECB.Create(1, $3E))), TVersion.Create(11, $24, $24, + $10, $10, TECBlocks.Create($2A, TECB.Create(1, $56))), + TVersion.Create(12, 40, 40, $12, $12, TECBlocks.Create($30, + TECB.Create(1, $72))), TVersion.Create(13, $2C, $2C, 20, 20, + TECBlocks.Create($38, TECB.Create(1, $90))), TVersion.Create(14, $30, $30, + $16, $16, TECBlocks.Create($44, TECB.Create(1, $AE))), + TVersion.Create(15, $34, $34, $18, $18, TECBlocks.Create($2A, + TECB.Create(2, $66))), TVersion.Create($10, $40, $40, 14, 14, + TECBlocks.Create($38, TECB.Create(2, 140))), TVersion.Create($11, $48, $48, + $10, $10, TECBlocks.Create($24, TECB.Create(4, $5C))), + TVersion.Create($12, 80, 80, $12, $12, TECBlocks.Create($30, + TECB.Create(4, $72))), TVersion.Create($13, $58, $58, 20, 20, + TECBlocks.Create($38, TECB.Create(4, $90))), TVersion.Create(20, $60, $60, + $16, $16, TECBlocks.Create($44, TECB.Create(4, $AE))), + TVersion.Create($15, $68, $68, $18, $18, TECBlocks.Create($38, + TECB.Create(6, $88))), TVersion.Create($16, 120, 120, $12, $12, + TECBlocks.Create($44, TECB.Create(6, $AF))), TVersion.Create($17, $84, $84, + 20, 20, TECBlocks.Create($3E, TECB.Create(8, $A3))), + TVersion.Create($18, $90, $90, $16, $16, TECBlocks.Create($3E, + TECB.Create(8, $9C), TECB.Create(2, $9B))), TVersion.Create($19, 8, $12, 6, + $10, TECBlocks.Create(7, TECB.Create(1, 5))), TVersion.Create($1A, 8, $20, + 6, 14, TECBlocks.Create(11, TECB.Create(1, 10))), + TVersion.Create($1B, 12, $1A, 10, $18, TECBlocks.Create(14, + TECB.Create(1, $10))), TVersion.Create($1C, 12, $24, 10, $10, + TECBlocks.Create($12, TECB.Create(1, $16))), TVersion.Create($1D, $10, $24, + 14, $10, TECBlocks.Create($18, TECB.Create(1, $20))), + TVersion.Create(30, $10, $30, 14, $16, TECBlocks.Create($1C, + TECB.Create(1, $31)))); +end; + +/// +///

Deduces version information from Data Matrix dimensions.

+/// +/// Number of rows in modules +/// Number of columns in modules +/// Version for a Data Matrix Code of those dimensions +/// if dimensions do correspond to a valid Data Matrix size +///
+class function TVersion.getVersionForDimensions(numRows: Integer; + numColumns: Integer): TVersion; +var + Version: TVersion; +begin + Result := nil; + + if (((numRows and $01) = 0) and ((numColumns and $01) = 0)) then + begin + for Version in TVersion.buildVersions do + begin + if ((Version.symbolSizeRows = numRows) and + (Version.symbolSizeColumns = numColumns)) then + begin + Result := Version; + break; + end; + end; + end; +end; + +function TVersion.ToString: string; +begin + Result := versionNumber.ToString(); +end; + +Initialization + +TVersion.ClassInit(); + +Finalization + +TVersion.ClassFinal(); + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.BitMatrixParser.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.BitMatrixParser.pas new file mode 100644 index 0000000..dcb03fc --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.BitMatrixParser.pas @@ -0,0 +1,361 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.BitMatrixParser; + +interface + +uses + SysUtils, + Generics.Collections, + ZXing.DecodeHintType, + ZXing.Common.BitMatrix, + ZXing.QrCode.Internal.Version, + ZXing.QrCode.Internal.FormatInformation, + ZXing.Common.Detector.MathUtils, + ZXing.QrCode.Internal.DataMask; + +type + TBitMatrixParser = class + private + BitMatrix: TBitMatrix; + mirrored: boolean; + parsedVersion: TVersion; + + function copyBit(const i, j, versionBits: Integer): Integer; + public + parsedFormatInfo: TFormatInformation; + + constructor Create(const BitMatrix: TBitMatrix); + + /// {@link TBitMatrix} to parse + /// ReaderException if dimension is not >= 21 and 1 mod 4 + class function createBitMatrixParser( + const bitMatrix: TBitMatrix): TBitMatrixParser; static; + + (** Mirror the bit matrix in order to attempt a second reading. *) + procedure mirror; + + (** + * Revert the mask removal done while reading the code words. The bit matrix should revert to its original state. + *) + procedure remask; + (** + * Prepare the parser for a mirrored operation. + * This flag has effect only on the {@link #readFormatInformation()} and the + * {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the + * {@link #mirror()} method should be called. + * + * @param mirror Whether to read version and format information mirrored. + *) + procedure setMirror(const mirror: Boolean); + + ///

Reads format information from one of its two locations within the QR Code.

+ /// + ///
+ /// {@link FormatInformation} encapsulating the QR Code's format info + /// + /// ReaderException if both format information locations cannot be parsed as + /// the valid encoding of format information + /// + function readFormatInformation: TFormatInformation; + + ///

Reads version information from one of its two locations within the QR Code.

+ /// + ///
+ /// {@link Version} encapsulating the QR Code's version + /// + /// ReaderException if both version information locations cannot be parsed as + /// the valid encoding of version information + /// + function readVersion: TVersion; + + //

Reads the bits in the {@link BitMatrix} representing the finder pattern in the + // correct order in order to reconstruct the codewords bytes contained within the + /// QR Code.

+ /// + ///
+ /// bytes encoded within the QR Code + /// + /// ReaderException if the exact number of bytes expected is not read + function readCodewords: TArray; + end; + +implementation + +{ TBitMatrixParser } + +constructor TBitMatrixParser.Create(const bitMatrix: TBitMatrix); +begin + // Should only be called from createBitMatrixParser with the important checks before + Self.bitMatrix := BitMatrix; +end; + +class function TBitMatrixParser.createBitMatrixParser( + const bitMatrix: TBitMatrix): TBitMatrixParser; +var + dimension: Integer; +begin + dimension := BitMatrix.Height; + if ((dimension < 21) and ((dimension and $03) <> 1)) + then + Result := nil + else + Result := TBitMatrixParser.Create(bitMatrix); +end; + +function TBitMatrixParser.copyBit(const i, j, versionBits: Integer): Integer; +var + bit: Boolean; +begin + if (mirrored) + then + bit := BitMatrix[j, i] + else + bit := BitMatrix[i, j]; + + if (bit) + then + Result := ((versionBits shl 1) or $1) + else + Result := (versionBits shl 1); +end; + +procedure TBitMatrixParser.mirror; +var + x, y: Integer; +begin + for x := 0 to Pred(bitMatrix.width) do + for y := (x + 1) to Pred(bitMatrix.height) do + if (bitMatrix[x, y] <> bitMatrix[y, x]) then + begin + bitMatrix.flip(y, x); + bitMatrix.flip(x, y); + end; +end; + +function TBitMatrixParser.readCodewords: TArray; +var + formatInfo: TFormatInformation; + dimension, resultOffset, + currentByte, bitsRead, + j, i, count, col: Integer; + functionPattern: TBitMatrix; + readingUp: boolean; + Version: TVersion; + DataMask: TDataMask; +begin + Result := nil; + + formatInfo := readFormatInformation; + if (formatInfo = nil) + then + exit; + + Version := readVersion; + if (Version = nil) + then + exit; + + // Get the data mask for the format used in this QR Code. This will exclude + // some bits from reading as we wind through the bit matrix. + DataMask := TDataMask.forReference(formatInfo.DataMask); + dimension := bitMatrix.Height; + DataMask.unmaskBitMatrix(BitMatrix, dimension); + + functionPattern := Version.buildFunctionPattern; + + try + readingUp := true; + Result := TArray.Create(); + SetLength(Result, version.TotalCodewords); + resultOffset := 0; + currentByte := 0; + bitsRead := 0; + j := (dimension - 1); + // Read columns in pairs, from right to left + while ((j > 0)) do + begin + if (j = 6) + then + // Skip whole column with vertical alignment pattern; + // saves time and makes the other code proceed more cleanly + Dec(j); + // Read alternatingly from bottom to top then top to bottom + for count := 0 to Pred(dimension) do + begin + if (readingUp) + then + i := ((dimension - 1) - count) + else + i := count; + for col := 0 to Pred(2) do + begin + // Ignore bits covered by the function pattern + if (not functionPattern[(j - col), i]) then + begin + // Read a bit + Inc(bitsRead); + currentByte := (currentByte shl 1); + if (bitMatrix[(j - col), i]) + then + currentByte := (currentByte or 1); + // If we've made a whole byte, save it off + if (bitsRead = 8) then + begin +// if resultoffset > high(Result) then +// raise EProgrammerNotFound.CreateFmt('resultoffset %d> high(Result) %d',[resultOffset,high(Result)]) +// else if resultoffset < 0 then +// raise EProgrammerNotFound.CreateFmt('resultoffset %d<0!',[resultOffset]); + + if (resultoffset>=0) and (resultoffset <= high(Result)) then // minchiata aggiunta da carlo + Result[resultOffset] := Byte(currentByte); + + Inc(resultOffset); + bitsRead := 0; + currentByte := 0; + end + end; + end; + end; + readingUp := not readingUp; // readingUp = !readingUp; // switch directions + Dec(j, 2); + end; + + if (resultOffset <> version.TotalCodewords) + then + Result := nil; + finally + FreeAndNil(functionPattern); + end; +end; + +function TBitMatrixParser.readFormatInformation: TFormatInformation; +var + formatInfoBits1, + formatInfoBits2, + dimension, + i, j, jMin: Integer; +begin + if (Self.parsedFormatInfo <> nil) then + begin + Result := Self.parsedFormatInfo; + exit; + end; + + // Read top-left format info bits + formatInfoBits1 := 0; + for i := 0 to Pred(6) do + formatInfoBits1 := self.copyBit(i, 8, formatInfoBits1); + // .. and skip a bit in the timing pattern ... + formatInfoBits1 := self.copyBit(7, 8, formatInfoBits1); + formatInfoBits1 := self.copyBit(8, 8, formatInfoBits1); + formatInfoBits1 := self.copyBit(8, 7, formatInfoBits1); + // .. and skip a bit in the timing pattern ... + for j := 5 downto 0 do + formatInfoBits1 := self.copyBit(8, j, formatInfoBits1); + // Read the top-right/bottom-left pattern too + dimension := Self.bitMatrix.Height; + formatInfoBits2 := 0; + jMin := (dimension - 7); + for j := (dimension - 1) downto jMin do + formatInfoBits2 := self.copyBit(8, j, formatInfoBits2); + for i := (dimension - 8) to Pred(dimension) do + formatInfoBits2 := self.copyBit(i, 8, formatInfoBits2); + + parsedFormatInfo := TFormatInformation.DecodeFormatInformation(formatInfoBits1, formatInfoBits2); + + if (parsedFormatInfo <> nil) + then + Result := Self.parsedFormatInfo + else + Result := nil; +end; + +function TBitMatrixParser.readVersion: TVersion; +var + dimension, + provisionalVersion, + versionBits, + i, j, ijMin: Integer; +begin + if (Self.parsedVersion <> nil) then + begin + Result := Self.parsedVersion; + exit; + end; + + dimension := Self.bitMatrix.Height; + provisionalVersion := TMathUtils.Asr((dimension - 17), 2); + if (provisionalVersion <= 6) then + begin + Result := TVersion.getVersionForNumber(provisionalVersion); + exit; + end; + + // Read top-right version info: 3 wide by 6 tall + versionBits := 0; + ijMin := (dimension - 11); + for j := 5 downto 0 do + for i := (dimension - 9) downto ijMin do + versionBits := Self.copyBit(i, j, versionBits); + + parsedVersion := TVersion.decodeVersionInformation(versionBits); + if ((parsedVersion <> nil) and + (parsedVersion.DimensionForVersion = dimension)) then + begin + Result := parsedVersion; + exit; + end; + + // Hmm, failed. Try bottom left: 6 wide by 3 tall + versionBits := 0; + for i := 5 downto 0 do + for j := (dimension - 9) downto ijMin do + versionBits := self.copyBit(i, j, versionBits); + + parsedVersion := TVersion.decodeVersionInformation(versionBits); + if ((parsedVersion <> nil) and + (parsedVersion.DimensionForVersion = dimension)) + then + Result := self.parsedVersion + else + Result := nil; +end; + +procedure TBitMatrixParser.remask; +var + dimension: Integer; +begin + if (parsedFormatInfo <> nil) then + begin + dimension := bitMatrix.Height; + TDataMask.forReference(parsedFormatInfo.DataMask) + .unmaskBitMatrix(bitMatrix, dimension); + end; +end; + +procedure TBitMatrixParser.setMirror(const mirror: Boolean); +begin + Self.parsedVersion := nil; + Self.parsedFormatInfo := nil; + Self.mirrored := mirror; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DataBlock.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DataBlock.pas new file mode 100644 index 0000000..3a08611 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DataBlock.pas @@ -0,0 +1,187 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.DataBlock; + +interface + +uses + System.SysUtils, + ZXing.QrCode.Internal.Version, + ZXing.QrCode.Internal.ErrorCorrectionLevel; + +type + ///

Encapsulates a block of data within a QR Code. QR Codes may split their data into + /// multiple blocks, each of which is a unit of data and error-correction codewords. Each + /// is represented by an instance of this class.

+ ///
+ TDataBlock = class sealed + private + Fcodewords: TArray; + FnumDataCodewords: Integer; + public + constructor Create(const codewords: TArray; + const NumDataCodewords: Integer); + destructor Destroy; override; + + ///

When QR Codes use multiple data blocks, they are actually interleaved. + /// That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This + /// method will separate the data into original blocks.

+ /// + ///
+ /// bytes as read directly from the QR Code + /// + /// version of the QR Code + /// + /// error-correction level of the QR Code + /// + /// {@link TDataBlock}s containing original bytes, "de-interleaved" from representation in the + /// QR Code + /// + class function getDataBlocks(const rawCodewords: TArray; + const version: TVersion; const ecLevel: TErrorCorrectionLevel): TArray; static; + + property codewords : TArray read Fcodewords; + property numDataCodewords : Integer read FnumDataCodewords; + end; + +implementation + +{ TDataBlock } + +constructor TDataBlock.Create(const codewords: TArray; + const numDataCodewords: Integer); +begin + Fcodewords := codewords; + FnumDataCodewords := numDataCodewords; +end; + +destructor TDataBlock.Destroy; +begin + Fcodewords := nil; + inherited; +end; + +class function TDataBlock.getDataBlocks(const rawCodewords: TArray; + const version: TVersion; const ecLevel: TErrorCorrectionLevel): TArray; +var + numResultBlocks, + shorterBlocksTotalCodewords, + longerBlocksStartAt, + shorterBlocksNumDataCodewords, + max, i, j, + totalBlocks, + numBlockCodewords, + iOffset, + rawCodewordsOffset, + NumDataCodewords: Integer; + ecBlock: Tversion.TECB; + ecBlocks: Tversion.TECBlocks; + ecBlockArray: TArray; + numBlockCodewordsBytes: TArray; + +begin + if (Length(rawCodewords) <> Version.TotalCodewords) + then + raise EArgumentException.Create('Invalid arguments'); + + // Figure out the number and size of data blocks used by this version and + // error correction level + ecBlocks := version.getECBlocksForLevel(ecLevel); + + // First count the total number of data blocks + totalBlocks := 0; + ecBlockArray := ecBlocks.getECBlocks; + + for ecBlock in ecBlockArray do + Inc(totalBlocks, ecBlock.Count); + + // Now establish DataBlocks of the appropriate size and number of data codewords + Result := TArray.Create(); + SetLength(result, totalBlocks); + numResultBlocks := 0; + for ecBlock in ecBlockArray do + begin + for i := 0 to Pred(ecBlock.count) do + begin + numDataCodewords := ecBlock.DataCodewords; + numBlockCodewords := ecBlocks.ECCodewordsPerBlock + numDataCodewords; + + numBlockCodewordsBytes := TArray.Create(); + SetLength(numBlockCodewordsBytes, numBlockCodewords); + + Result[numResultBlocks] := TDataBlock.Create(numBlockCodewordsBytes, numDataCodewords); + Inc(numResultBlocks); + end + end; + + numBlockCodewordsBytes := nil; + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 more byte. Figure out where these start. + shorterBlocksTotalCodewords := Length(Result[0].codewords); + longerBlocksStartAt := Length(result) - 1; + while ((longerBlocksStartAt >= 0)) do + begin + if (Length(Result[longerBlocksStartAt].codewords) = shorterBlocksTotalCodewords) + then + break; + Dec(longerBlocksStartAt); + end; + Inc(longerBlocksStartAt); + + shorterBlocksNumDataCodewords := (shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock); + // The last elements of result may be 1 element longer; + // first fill out as many elements as all of them have + rawCodewordsOffset := 0; + for i := 0 to Pred(shorterBlocksNumDataCodewords) do + begin + for j := 0 to Pred(numResultBlocks) do + begin + Result[j].codewords[i] := rawCodewords[rawCodewordsOffset]; + Inc(rawCodewordsOffset); + end; + end; + // Fill out the last data block in the longer ones + for j := longerBlocksStartAt to Pred(numResultBlocks) do + begin + result[j].codewords[shorterBlocksNumDataCodewords] := + rawCodewords[rawCodewordsOffset]; + Inc(rawCodewordsOffset); + end; + // Now add in error correction blocks + max := Length(result[0].codewords); + + for i := shorterBlocksNumDataCodewords to Pred(max) do + begin + for j := 0 to Pred(numResultBlocks) do + begin + if (j < longerBlocksStartAt) + then + iOffset := i + else + iOffset := i + 1; + + Result[j].codewords[iOffset] := rawCodewords[rawCodewordsOffset]; + Inc(rawCodewordsOffset); + end; + end; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DataMask.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DataMask.pas new file mode 100644 index 0000000..4efb1ff --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DataMask.pas @@ -0,0 +1,226 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.DataMask; + +interface + +uses + SysUtils, + ZXing.Common.BitMatrix, + ZXing.Common.Detector.MathUtils; + +type + ///

Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations + /// of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix, + /// including areas used for finder patterns, timing patterns, etc. These areas should be unused + /// after the point they are unmasked anyway.

+ /// + ///

Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position + /// and j is row position. In fact, as the text says, i is row position and j is column position.

+ ///
+ TDataMask = class abstract + private + /// See ISO 18004:2006 6.8.1 + class var DATA_MASKS: TArray; + + class procedure InitializeClass; + class procedure FinalizeClass; + + function isMasked(const i, j: Integer): Boolean; virtual; abstract; + public + /// a value between 0 and 7 indicating one of the eight possible + /// data mask patterns a QR Code may use + /// + /// {@link DataMask} encapsulating the data mask pattern + /// + class function forReference(const reference: Integer): TDataMask; static; + + ///

Implementations of this method reverse the data masking process applied to a QR Code and + /// make its bits ready to read.

+ ///
+ /// representation of QR Code bits + /// + /// dimension of QR Code, represented by bits, being unmasked + /// + procedure unmaskBitMatrix(const bits: TBitMatrix; const dimension: Integer); + end; + + /// 000: mask bits for which (x + y) mod 2 == 0 + TDataMask000 = class(TDataMask) + private + function isMasked(const i, j: Integer): Boolean; override; + end; + + /// 001: mask bits for which x mod 2 == 0 + TDataMask001 = class sealed(TDataMask) + private + function isMasked(const i, j: Integer): Boolean; override; + end; + + /// 010: mask bits for which y mod 3 == 0 + TDataMask010 = class sealed(TDataMask) + private + function isMasked(const i, j: Integer): Boolean; override; + end; + + /// 011: mask bits for which (x + y) mod 3 == 0 + TDataMask011 = class sealed(TDataMask) + private + function isMasked(const i, j: Integer): Boolean; override; + end; + + /// 100: mask bits for which (x/2 + y/3) mod 2 == 0 + TDataMask100 = class sealed(TDataMask) + private + function isMasked(const i, j: Integer): Boolean; override; + end; + + /// 101: mask bits for which xy mod 2 + xy mod 3 == 0 + TDataMask101 = class sealed(TDataMask) + private + function isMasked(const i, j: Integer): Boolean; override; + end; + + /// 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 + TDataMask110 = class sealed(TDataMask) + private + function isMasked(const i, j: Integer): Boolean; override; + end; + + /// 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 + TDataMask111 = class sealed(TDataMask) + private + function isMasked(const i, j: Integer): Boolean; override; + end; + +implementation + +{ TDataMask } + +class procedure TDataMask.InitializeClass; +begin + TDataMask.DATA_MASKS := TArray.Create(TDataMask000.Create, + TDataMask001.Create, + TDataMask010.Create, + TDataMask011.Create, + TDataMask100.Create, + TDataMask101.Create, + TDataMask110.Create, + TDataMask111.Create); +end; + +class procedure TDataMask.FinalizeClass; +var + dam: TDataMask; +begin + for dam in TDataMask.DATA_MASKS do + dam.Free; + DATA_MASKS := nil; +end; + +class function TDataMask.forReference(const reference: Integer): TDataMask; +begin + if ((reference < 0) or (reference > 7)) + then + raise EArgumentException.Create('Invalid arguments'); + + Result := TDataMask.DATA_MASKS[reference]; +end; + +procedure TDataMask.unmaskBitMatrix(const bits: TBitMatrix; + const dimension: Integer); +var + i, j: Integer; +begin + for i := 0 to Pred(dimension) do + for j := 0 to Pred(dimension) do + if (self.isMasked(i, j)) + then + bits.flip(j, i); +end; + +{ TDataMask000 } + +function TDataMask000.isMasked(const i, j: Integer): Boolean; +begin + Result := ((i + j) and $01) = 0; +end; + +{ TDataMask001 } + +function TDataMask001.isMasked(const i, j: Integer): Boolean; +begin + Result := (i and $01) = 0; +end; + +{ TDataMask010 } + +function TDataMask010.isMasked(const i, j: Integer): Boolean; +begin + Result := (j mod 3) = 0; +end; + +{ TDataMask011 } + +function TDataMask011.isMasked(const i, j: Integer): Boolean; +begin + Result := (((i + j) mod 3) = 0) +end; + +{ TDataMask100 } + +function TDataMask100.isMasked(const i, j: Integer): Boolean; +begin + Result := (( TMathUtils.Asr(UInt32(i),1) + (j div 3)) and $01) = 0; +end; + +{ TDataMask101 } + +function TDataMask101.isMasked(const i, j: Integer): Boolean; +var + temp: Integer; +begin + temp := (i * j); + Result := ((temp and $01) + (temp mod 3)) = 0; +end; + +{ TDataMask110 } + +function TDataMask110.isMasked(const i, j: Integer): Boolean; +var + temp: Integer; +begin + temp := (i * j); + Result := (((temp and $01) + (temp mod 3)) and 1) = 0; +end; + +{ TDataMask111 } + +function TDataMask111.isMasked(const i, j: Integer): Boolean; +begin + Result := ((((i + j) and $01) + ((i * j) mod 3)) and $01) = 0; +end; + +initialization + TDataMask.InitializeClass; +finalization + TDataMask.FinalizeClass; +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DecodedBitStreamParser.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DecodedBitStreamParser.pas new file mode 100644 index 0000000..d3bf6f8 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.DecodedBitStreamParser.pas @@ -0,0 +1,587 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.DecodedBitStreamParser; + +interface + +uses + ZXing.BitSource, + SysUtils, + ZXing.DecodeHintType, + Generics.Collections, + ZXing.QrCode.Internal.ErrorCorrectionLevel, + ZXing.QrCode.Internal.Version, + ZXing.DecoderResult, + ZXing.CharacterSetECI, + ZXing.StringUtils, + ZXing.ByteSegments, + ZXing.QrCode.Internal.Mode, + ZXing.Common.Detector.MathUtils; + +type + ///

QR Codes can encode text as bits in one of several modes, and can use multiple modes + /// in one QR Code. This class decodes the bits back into text.

+ /// + ///

See ISO 18004:2006, 6.4.3 - 6.4.7

+ ///
+ TDecodedBitStreamParser = class abstract + private + /// + /// See ISO 18004:2006, 6.4.4 Table 5 + /// + class var ALPHANUMERIC_CHARS: TArray; + + const + GB2312_SUBSET: Integer = 1; + + class procedure InitializeClass; + class procedure FinalizeClass; + + class function decodeAlphanumericSegment(const bits: TBitSource; + const res: TStringBuilder; count: Integer; + const fc1InEffect: Boolean): Boolean; static; + + class function decodeByteSegment(const bits: TBitSource; + const res: TStringBuilder; count: Integer; + const currentCharacterSetECI: TCharacterSetECI; + const byteSegments: IByteSegments; + const hints: TDictionary): Boolean; static; + + /// + /// See specification GBT 18284-2000 + /// + /// The bits. + /// The result. + /// The count. + /// + class function decodeHanziSegment(const bits: TBitSource; + const res: TStringBuilder; count: Integer): Boolean; static; + + class function decodeKanjiSegment(const bits: TBitSource; + const res: TStringBuilder; count: Integer): boolean; static; + + class function decodeNumericSegment(const bits: TBitSource; + const res: TStringBuilder; count: Integer): Boolean; static; + + class function parseECIValue(const bits: TBitSource): Integer; static; + class function toAlphaNumericChar(const value: Integer): Char; static; + public + class function decode(const bytes: TArray; const version: TVersion; + const ecLevel: TErrorCorrectionLevel; + const hints: TDictionary): TDecoderResult; static; + end; + +implementation + +{ TDecodedBitStreamParser } + +class procedure TDecodedBitStreamParser.InitializeClass; +begin + ALPHANUMERIC_CHARS := TArray.Create('0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', + '$', '%', '*', '+', '-', '.', '/', ':'); +end; + +class procedure TDecodedBitStreamParser.FinalizeClass; +begin + ALPHANUMERIC_CHARS := nil; +end; + +class function TDecodedBitStreamParser.decode(const bytes: TArray; + const version: TVersion; const ecLevel: TErrorCorrectionLevel; + const hints: TDictionary): TDecoderResult; +var + Mode: TMode; + bits: TBitSource; + byteSegments: IByteSegments; + fc1InEffect: Boolean; + symbolSequence, + parityData, + count, value, + countHanzi, subSet: Integer; + currentCharacterSetECI: TCharacterSetECI; + ecstring,s: String; + res: TStringBuilder; +begin + Result := nil; + + bits := TBitSource.Create(bytes); + res := TStringBuilder.Create(50); + byteSegments := ByteSegmentsCreate(); + byteSegments.Capacity := 1; + symbolSequence := -1; + parityData := -1; + try + try + currentCharacterSetECI := nil; + fc1InEffect := false; + repeat + // While still another segment to read... + if (bits.available < 4) + then + // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here + Mode := TMode.TERMINATOR + else + begin + try + Mode := TMode.forBits(bits.readBits(4)); // mode is encoded by 4 bits + except + on E: EArgumentException do + exit; + end; + end; + + if (Mode <> TMode.TERMINATOR) then + begin + if ((Mode = TMode.FNC1_FIRST_POSITION) or + (Mode = TMode.FNC1_SECOND_POSITION)) then + begin + // We do little with FNC1 except alter the parsed result a bit according to the spec + fc1InEffect := true; + end else + begin + if (Mode = TMode.STRUCTURED_APPEND) then + begin + if (bits.available() < 16) + then + exit; + // not really supported; but sequence number and parity is added later to the result metadata + // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue + symbolSequence := bits.readBits(8); + parityData := bits.readBits(8); + end else + begin + if (Mode = TMode.ECI) then + begin + // Count doesn't apply to ECI + value := parseECIValue(bits); + currentCharacterSetECI := TCharacterSetECI.getCharacterSetECIByValue(value); + if (currentCharacterSetECI = nil) + then + exit; + end else + begin + // First handle Hanzi mode which does not start with character count + if (Mode = TMode.HANZI) then + begin + // chinese mode contains a sub set indicator right after mode indicator + subSet := bits.readBits(4); + countHanzi := bits.readBits(Mode.getCharacterCountBits(version)); + if (subSet = GB2312_SUBSET) then + begin + if (not TDecodedBitStreamParser.decodeHanziSegment(bits, + res, countHanzi)) + then + exit; + end; + end else + begin + // "Normal" QR code modes: + // How many characters will follow, encoded in this mode? + count := bits.readBits(Mode.getCharacterCountBits(version)); + if (Mode = TMode.NUMERIC) then + begin + if (not TDecodedBitStreamParser.decodeNumericSegment(bits, + res, count)) + then + exit; + end else + begin + if (Mode = TMode.ALPHANUMERIC) then + begin + if (not TDecodedBitStreamParser. + decodeAlphanumericSegment(bits, res, count, fc1InEffect)) + then + exit; + end else + begin + if (Mode = TMode.BYTE) then + begin + if (not TDecodedBitStreamParser. + decodeByteSegment(bits, res, count, + currentCharacterSetECI, byteSegments, hints)) + then + exit; + end else + begin + if (Mode <> TMode.KANJI) then + begin + if (not TDecodedBitStreamParser. + decodeKanjiSegment(bits, res, count)) + then + exit; + end else exit; + end; + end; + end; + end; + end; + end; + end; + end; + until (Mode = TMode.TERMINATOR) + except + on E: EArgumentException do + exit; + end; + + if (byteSegments.count = 0) + then + byteSegments := nil; + + if (ecLevel = nil) + then + ecstring := '' + else + ecstring := ecLevel.toString(); + + s:= res.toString.Replace(#13+#10, #10).Replace(#10, #13); + Result := TDecoderResult.Create(bytes, s, byteSegments, ecstring, symbolSequence, + parityData); + finally + // FreeAndNil(byteSegments); + + res.Clear(); + + FreeAndNil(res); + FreeAndNil(bits); + end; + + end; + +class function TDecodedBitStreamParser.decodeAlphanumericSegment( + const bits: TBitSource; const res: TStringBuilder; count: Integer; + const fc1InEffect: Boolean): Boolean; +var + start, i, nextTwoCharsBits: Integer; + charArray: TArray; +begin + Result := false; + // Read two characters at a time + start := res.Length; + while ((count > 1)) do + begin + if (bits.available < 11) + then + exit; + + nextTwoCharsBits := bits.readBits(11); + res.Append(TDecodedBitStreamParser.toAlphaNumericChar + ((nextTwoCharsBits div 45))); + res.Append(TDecodedBitStreamParser.toAlphaNumericChar + ((nextTwoCharsBits mod 45))); + Dec(count, 2); + end; + + if (count = 1) then + begin + // special case: one character left + if (bits.available < 6) + then + exit; + res.Append(TDecodedBitStreamParser.toAlphaNumericChar(bits.readBits(6))) + end; + + // See section 6.4.8.1, 6.4.8.2 + if (fc1InEffect) then + begin + // We need to massage the result a bit if in an FNC1 mode: + for i := start to Pred(res.Length) do + begin + if (res.Chars[i] = '%') then + begin + if ((i < (res.Length - 1)) and (res.Chars[(i + 1)] = '%')) + then + // %% is rendered as % + res.Remove((i + 1), 1) + else + begin + // In alpha mode, % should be converted to FNC1 separator 0x1D + res.Remove(i, 1); + charArray := TArray.Create(Char($1D)); + res.Insert(i, charArray); + end; + end; + end; + end; + + Result := true; +end; + +class function TDecodedBitStreamParser.decodeByteSegment(const bits: TBitSource; + const res: TStringBuilder; count: Integer; + const currentCharacterSetECI: TCharacterSetECI; + const byteSegments: IByteSegments; + const hints: TDictionary): Boolean; +var + Enc:TEncoding; + encodingS, s: string; + readBytes: TArray; + i: Integer; +begin + Result := false; + // Don't crash trying to read more bits than we have available. + if ((count shl 3) > bits.available) + then + exit; + + readBytes := TArray.Create(); + SetLength(readBytes, count); + for i := 0 to Pred(count) do + readBytes[i] := Byte(bits.readBits(8)); + + if (currentCharacterSetECI = nil) + then + // The spec isn't clear on this mode; see + // section 6.4.5: t does not say which encoding to assuming + // upon decoding. I have seen ISO-8859-1 used as well as + // Shift_JIS -- without anything like an ECI designator to + // give a hint. + encodingS := TStringUtils.guessEncoding(readBytes, hints) + else + encodingS := currentCharacterSetECI.EncodingName; + + try + enc := TEncoding.GetEncoding(encodingS); + try + s := enc.GetString(readBytes, 0, Length(readBytes)); + res.Append(s); + finally + FreeAndNil(enc); + end; + except + on E: Exception do + exit; + end; + + byteSegments.Add(readBytes); + result := true; +end; + +class function TDecodedBitStreamParser.decodeHanziSegment( + const bits: TBitSource; const res: TStringBuilder; count: Integer): Boolean; +var + buffer: TArray; + offset, twoBytes, + assembledTwoBytes: Integer; +begin + Result := false; + // Don't crash trying to read more bits than we have available. + if ((count * 13) > bits.available) + then + exit; + + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as GB2312 afterwards + buffer := TArray.Create(); + SetLength(buffer, 2 * count); + offset := 0; + + while ((count > 0)) do + begin + // Each 13 bits encodes a 2-byte character + twoBytes := bits.readBits(13); + assembledTwoBytes := (((twoBytes div $60) shl 8) or (twoBytes mod $60)); + if (assembledTwoBytes < $00A00) + then + // In the 0xA1A1 to 0xAAFE range + Inc(assembledTwoBytes, $0A1A1) + else + // In the 0xB0A1 to 0xFAFE range + Inc(assembledTwoBytes, $0A6A1); + + buffer[offset] := Byte(TMathUtils.Asr(assembledTwoBytes, 8) and $FF); + buffer[(offset + 1)] := Byte(assembledTwoBytes and $FF); + Inc(offset, 2); + Dec(count); + end; + + try + res.Append(Tencoding.GetEncoding(TStringUtils.GB2312).GetString(buffer, 0, + Length(buffer))) + except + on E: Exception do + exit; + end; + Result := true; +end; + +class function TDecodedBitStreamParser.decodeKanjiSegment( + const bits: TBitSource; const res: TStringBuilder; count: Integer): Boolean; +var + buffer: TArray; + twoBytes, offset, + assembledTwoBytes: Integer; +begin + Result := false; + // Don't crash trying to read more bits than we have available. + if ((count * 13) > bits.available) + then + exit; + + // Each character will require 2 bytes. Read the characters as 2-byte pairs + // and decode as Shift_JIS afterwards + buffer := TArray.Create(); + SetLength(buffer, 2 * count); + offset := 0; + + while ((count > 0)) do + begin + // Each 13 bits encodes a 2-byte character + twoBytes := bits.readBits(13); + assembledTwoBytes := (((twoBytes div $0C0) shl 8) or (twoBytes mod $0C0)); + if (assembledTwoBytes < $1F00) + then + // In the 0x8140 to 0x9FFC range + Inc(assembledTwoBytes, $08140) + else + Inc(assembledTwoBytes, $0C140); + buffer[offset] := Byte( TMathUtils.Asr(assembledTwoBytes,8)); + buffer[(offset + 1)] := Byte(assembledTwoBytes); + Inc(offset, 2); + Dec(count); + end; + + try + res.Append(Tencoding.GetEncoding(TStringUtils.SHIFT_JIS).GetString(buffer, + 0, Length(buffer))) + except + on E: Exception do + exit; + end; + Result := true; +end; + +class function TDecodedBitStreamParser.decodeNumericSegment( + const bits: TBitSource; const res: TStringBuilder; count: Integer): Boolean; +var + threeDigitsBits, + twoDigitsBits, + digitBits: Integer; +begin + Result := false; + // Read three digits at a time + while ((count >= 3)) do + begin + if (bits.available < 10) + then + exit; + threeDigitsBits := bits.readBits(10); + if (threeDigitsBits >= 1000) + then + exit; + res.Append(TDecodedBitStreamParser.toAlphaNumericChar + ((threeDigitsBits div 100))); + res.Append(TDecodedBitStreamParser.toAlphaNumericChar + (((threeDigitsBits div 10) mod 10))); + res.Append(TDecodedBitStreamParser.toAlphaNumericChar + ((threeDigitsBits mod 10))); + Dec(count, 3) + end; + + if (count = 2) then + begin + // Two digits left over to read, encoded in 7 bits + if (bits.available < 7) + then + exit; + + twoDigitsBits := bits.readBits(7); + if (twoDigitsBits >= 100) + then + exit; + + res.Append(TDecodedBitStreamParser.toAlphaNumericChar + ((twoDigitsBits div 10))); + res.Append(TDecodedBitStreamParser.toAlphaNumericChar + ((twoDigitsBits mod 10))); + end else + begin + if (count = 1) then + begin + // One digit left over to read + if (bits.available < 4) + then + exit; + + digitBits := bits.readBits(4); + if (digitBits >= 10) + then + exit; + + res.Append(TDecodedBitStreamParser.toAlphaNumericChar(digitBits)) + end; + end; + + Result := true; +end; + +class function TDecodedBitStreamParser.parseECIValue( + const bits: TBitSource): Integer; +var + firstByte, + secondByte, + SecondThirdBytes: Integer; +begin + firstByte := bits.readBits(8); + + if ((firstByte and $80) = 0) then + begin + // just one byte + Result := (firstByte and $7F); + exit; + end; + + if ((firstByte and $C0) = $80) then + begin + // two bytes + secondByte := bits.readBits(8); + Result := (((firstByte and $3F) shl 8) or secondByte); + exit; + end; + + if ((firstByte and $E0) = $C0) then + begin + // three bytes + SecondThirdBytes := bits.readBits(16); + Result := (((firstByte and $1F) shl 16) or SecondThirdBytes); + exit; + end; + + raise EArgumentException.Create('Bad ECI bits starting with byte ' + + firstByte.toString()); +end; + +class function TDecodedBitStreamParser.toAlphaNumericChar( + const value: Integer): Char; +begin + if (value >= Length(ALPHANUMERIC_CHARS)) + then + raise Exception.Create('Format exception'); + + Result := ALPHANUMERIC_CHARS[value]; +end; + +initialization + TDecodedBitStreamParser.InitializeClass; +finalization + TDecodedBitStreamParser.FinalizeClass; +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Decoder.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Decoder.pas new file mode 100644 index 0000000..dcde16d --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Decoder.pas @@ -0,0 +1,278 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E.Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.Decoder; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + ZXing.DecodeHintType, + ZXing.Common.BitMatrix, + ZXing.QrCode.Internal.BitMatrixParser, + ZXing.DecoderResult, + ZXing.Common.ReedSolomon.ReedSolomonDecoder, + ZXing.Common.ReedSolomon.GenericGF, + ZXing.QrCode.Internal.QRCodeDecoderMetaData, + ZXing.QrCode.Internal.Version, + ZXing.QrCode.Internal.FormatInformation, + ZXing.QrCode.Internal.ErrorCorrectionLevel, + ZXing.QrCode.Internal.DataBlock, + ZXing.QrCode.Internal.DecodedBitStreamParser; + +type + /// + ///

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

+ ///
+ TQRDecoder = class + private + rsDecoder: TReedSolomonDecoder; + /// + ///

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 correctErrors(const codewordBytes: TArray; + const numDataCodewords: Integer): Boolean; + + function decode(const parser: TBitMatrixParser; + const hints: TDictionary) + : TDecoderResult; overload; + public + /// + /// Initializes a new instance of the class. + /// + constructor Create; + destructor Destroy; override; + + /// + ///

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

+ ///
+ /// booleans representing white/black QR Code modules + /// decoding hints that should be used to influence decoding + /// + /// text and bytes encoded within the QR Code + /// + function decode(const image: TArray>; + const hints: TDictionary) + : TDecoderResult; overload; + + /// + ///

Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.

+ ///
+ /// booleans representing white/black QR Code modules + /// decoding hints that should be used to influence decoding + /// + /// text and bytes encoded within the QR Code + /// + function decode(const bits: TBitMatrix; + const hints: TDictionary) + : TDecoderResult; overload; + end; + +implementation + +{ TQRDecoder } +constructor TQRDecoder.Create; +begin + rsDecoder := TReedSolomonDecoder.Create(TGenericGF.QR_CODE_FIELD_256); +end; + +destructor TQRDecoder.Destroy; +begin + FreeAndNil(rsDecoder); + inherited; +end; + +function TQRDecoder.correctErrors(const codewordBytes: TArray; + const numDataCodewords: Integer): Boolean; +var + i, numCodewords, numECCodewords: Integer; + codewordsInts: TArray; +begin + Result := false; + + numCodewords := Length(codewordBytes); + // First read into an array of ints + codewordsInts := TArray.Create(); + SetLength(codewordsInts, numCodewords); + for i := 0 to Pred(numCodewords) do + codewordsInts[i] := (codewordBytes[i] and $FF); + numECCodewords := Length(codewordBytes) - numDataCodewords; + + if (not rsDecoder.decode(codewordsInts, numECCodewords)) then + exit; + + // 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 + codewordBytes[i] := Byte(codewordsInts[i]); + + Result := true; +end; + +function TQRDecoder.decode(const image: TArray>; + const hints: TDictionary): TDecoderResult; +var + dimension, i, j: Integer; + bits: TBitMatrix; +begin + dimension := Length(image); + bits := TBitMatrix.Create(dimension); + try + for i := 0 to Pred(dimension) do + for j := 0 to Pred(dimension) do + bits[j, i] := image[i][j]; + + Result := decode(bits, hints); + finally + bits.Free; + end; +end; + +function TQRDecoder.decode(const bits: TBitMatrix; + const hints: TDictionary): TDecoderResult; +var + parser: TBitMatrixParser; +begin + Result := nil; + + // Construct a parser and read version, error-correction level + parser := TBitMatrixParser.createBitMatrixParser(bits); + if Assigned(parser) then + begin + try + Result := decode(parser, hints); + if (Result = nil) then + begin + // Revert the bit matrix + parser.remask; + + // Will be attempting a mirrored reading of the version and format info. + parser.setMirror(true); + + // Preemptively read the version. + if (parser.readVersion = nil) then + exit; + + // Preemptively read the format information. + if (parser.readFormatInformation = nil) then + exit; + + (* + * Since we're here, this means we have successfully detected some kind + * of version and format information when mirrored. This is a good sign, + * that the QR code may be mirrored, and we should try once more with a + * mirrored content. + *) + // Prepare for a mirrored reading. + parser.mirror; + + Result := decode(parser, hints); + + if (Result <> nil) then + // Success! Notify the caller that the code was mirrored. + Result.Other := TQRCodeDecoderMetaData.Create(true); + end; + finally + parser.Free; + end; + end; +end; + +function TQRDecoder.decode(const parser: TBitMatrixParser; + const hints: TDictionary): TDecoderResult; +var + DataBlock: TDataBlock; + dataBlocks: TArray; + Version: TVersion; + formatInfo: TFormatInformation; + ecLevel: TErrorCorrectionLevel; + codeWords, resultBytes, codewordBytes: TArray; + totalBytes, resultOffset, i, numDataCodewords: Integer; +begin + Result := nil; + + Version := parser.readVersion; + if (Version = nil) then + exit; + + formatInfo := parser.readFormatInformation; + if (formatInfo = nil) then + exit; + + ecLevel := formatInfo.ErrorCorrectionLevel; + + // Read codewords + codeWords := parser.readCodewords; + if (codeWords = nil) then + begin + FreeAndNil(formatInfo); + exit; + end; + + // Separate into data blocks + dataBlocks := TDataBlock.getDataBlocks(codeWords, Version, ecLevel); + + // Count total number of data bytes + totalBytes := 0; + for DataBlock in dataBlocks do + Inc(totalBytes, DataBlock.numDataCodewords); + + resultBytes := TArray.Create(); + SetLength(resultBytes, totalBytes); + try + + resultOffset := 0; + + // Error-correct and copy data blocks together into a stream of bytes + for DataBlock in dataBlocks do + begin + codewordBytes := DataBlock.codeWords; + numDataCodewords := DataBlock.numDataCodewords; + if (not self.correctErrors(codewordBytes, numDataCodewords)) then + begin + exit(nil); + end; + + for i := 0 to Pred(numDataCodewords) do + begin + resultBytes[resultOffset] := codewordBytes[i]; + Inc(resultOffset); + end; + end; + + // Decode the contents of that stream of bytes + Result := TDecodedBitStreamParser.decode(resultBytes, Version, + ecLevel, hints); + + finally + for DataBlock in dataBlocks do + DataBlock.Free; + FreeAndNil(formatInfo); + end; + +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.ErrorCorrectionLevel.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.ErrorCorrectionLevel.pas new file mode 100644 index 0000000..f64c7ff --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.ErrorCorrectionLevel.pas @@ -0,0 +1,149 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.ErrorCorrectionLevel; + +interface + +uses SysUtils; + +type + /// + ///

See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels + /// defined by the QR code standard.

+ ///
+ TErrorCorrectionLevel = class sealed + private + Fbits: Integer; + Fname: string; + Fordinal_Renamed_Field: Integer; + class var FOR_BITS: TArray; + + class procedure InitalizeClass; static; + class procedure FinalizeClass; static; + public + constructor Create(const ordinal, bits: Integer; const name: String); + + /// + /// Fors the bits. + /// + /// int containing the two bits encoding a QR Code's error correction level + /// + /// representing the encoded error correction level + /// + class function forBits(const bits: Integer): TErrorCorrectionLevel; static; + + /// L = ~7% correction + class var L: TErrorCorrectionLevel; + + /// M = ~15% correction + class var M: TErrorCorrectionLevel; + + /// Q = ~25% correction + class var Q: TErrorCorrectionLevel; + + /// H = ~30% correction + class var H: TErrorCorrectionLevel; + + /// + /// Ordinals this instance. + /// + /// + function ordinal: Integer; + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + function ToString: String; override; + + /// + /// Gets the bits. + /// + property Bits: Integer read Fbits; + + /// + /// Gets the name. + /// + property Name: String read Fname; + end; + +implementation + +{ TErrorCorrectionLevel } + +constructor TErrorCorrectionLevel.Create(const ordinal, bits: Integer; + const name: String); +begin + Fordinal_Renamed_Field := ordinal; + Fbits := bits; + Fname := name +end; + +class procedure TErrorCorrectionLevel.InitalizeClass; +begin + H := TErrorCorrectionLevel.Create(3, 2, 'H'); + L := TErrorCorrectionLevel.Create(0, 1, 'L'); + M := TErrorCorrectionLevel.Create(1, 0, 'M'); + Q := TErrorCorrectionLevel.Create(2, 3, 'Q'); + + FOR_BITS := TArray.Create(M, L, H, Q); +end; + +class procedure TErrorCorrectionLevel.FinalizeClass; +begin + H.FOR_BITS := nil; + L.FOR_BITS := nil; + M.FOR_BITS := nil; + Q.FOR_BITS := nil; + + FreeAndNil(H); + FreeAndNil(L); + FreeAndNil(M); + FreeAndNil(Q); + FOR_BITS := nil; +end; + +class function TErrorCorrectionLevel.forBits(const bits: Integer): TErrorCorrectionLevel; +begin + if ((bits < 0) or + (bits >= Length(TErrorCorrectionLevel.FOR_BITS))) + then + raise EArgumentException.Create('Invalid argument'); + + Result := TErrorCorrectionLevel.FOR_BITS[bits]; +end; + +function TErrorCorrectionLevel.ordinal: Integer; +begin + Result := Fordinal_Renamed_Field; +end; + +function TErrorCorrectionLevel.ToString: string; +begin + Result := Fname +end; + +initialization + TErrorCorrectionLevel.InitalizeClass; +finalization + TErrorCorrectionLevel.FinalizeClass; +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.FormatInformation.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.FormatInformation.pas new file mode 100644 index 0000000..531e132 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.FormatInformation.pas @@ -0,0 +1,256 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.FormatInformation; + +interface + +uses + Generics.Collections, + ZXing.QrCode.Internal.ErrorCorrectionLevel, + Classes, + ZXing.Common.Detector.MathUtils; + +type + ///

Encapsulates a QR Code's format information, including the data mask used and + /// error correction level.

+ /// + ///
+ /// + /// + /// + /// + TFormatInformation = class sealed + private + FErrorCorrectionLevel: TErrorCorrectionLevel; + FDataMask: Byte; + + const + FORMAT_INFO_MASK_QR: Integer = $5412; + + /// See ISO 18004:2006, Annex C, Table C.1 + class var FORMAT_INFO_DECODE_LOOKUP: TArray>; + + /// Offset i holds the number of 1 bits in the binary representation of i + class var BITS_SET_IN_HALF_BYTE: TArray; + + class procedure InitializeClass; static; + class procedure FinalizeClass; static; + + class function doDecodeFormatInformation(const maskedFormatInfo1, + maskedFormatInfo2: Integer): TFormatInformation; static; + public + constructor Create(const formatInfo: Integer); + + function Equals(o: TObject): Boolean; override; + function GetHashCode: Integer; override; + class function numBitsDiffering(a, b: Integer): Integer; static; + + /// + /// Decodes the format information. + /// + /// format info indicator, with mask still applied + /// The masked format info2. + /// + /// information about the format it specifies, or null + /// if doesn't seem to match any known pattern + /// + class function decodeFormatInformation(const maskedFormatInfo1, + maskedFormatInfo2: Integer): TFormatInformation; static; + + property ErrorCorrectionLevel: TErrorCorrectionLevel + read FErrorCorrectionLevel; + property DataMask: Byte read FDataMask; + end; + +implementation + +{ TFormatInformation } + +constructor TFormatInformation.Create(const formatInfo: Integer); +begin + // Bits 3,4 + FErrorCorrectionLevel := TErrorCorrectionLevel.forBits + (TMathUtils.Asr(formatInfo, 3) and $03); + // Bottom 3 bits + FDataMask := Byte(formatInfo and 7); +end; + +class function TFormatInformation.decodeFormatInformation + (const maskedFormatInfo1, maskedFormatInfo2: Integer): TFormatInformation; +var + formatInfo: TFormatInformation; +begin + formatInfo := doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2); + + if (formatInfo <> nil) then + Result := formatInfo + else + // Should return null, but, some QR codes apparently + // do not mask this info. Try again by actually masking the pattern + // first + Result := TFormatInformation.doDecodeFormatInformation + ((maskedFormatInfo1 xor FORMAT_INFO_MASK_QR), + (maskedFormatInfo2 xor FORMAT_INFO_MASK_QR)); +end; + +class function TFormatInformation.doDecodeFormatInformation + (const maskedFormatInfo1, maskedFormatInfo2: Integer): TFormatInformation; +var + bestDifference, bestFormatInfo, bitsDifference, targetInfo: Integer; + decodeInfo: TArray; +begin + Result := nil; + + // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing + bestDifference := High(Integer); + bestFormatInfo := 0; + + for decodeInfo in FORMAT_INFO_DECODE_LOOKUP do + begin + targetInfo := decodeInfo[0]; + if ((targetInfo = maskedFormatInfo1) or (targetInfo = maskedFormatInfo2)) + then + begin + // Found an exact match + Result := TFormatInformation.Create(decodeInfo[1]); + exit; + end; + + bitsDifference := numBitsDiffering(maskedFormatInfo1, targetInfo); + if (bitsDifference < bestDifference) then + begin + bestFormatInfo := decodeInfo[1]; + bestDifference := bitsDifference; + end; + + if (maskedFormatInfo1 <> maskedFormatInfo2) then + begin + // also try the other option + bitsDifference := numBitsDiffering(maskedFormatInfo2, targetInfo); + if (bitsDifference < bestDifference) then + begin + bestFormatInfo := decodeInfo[1]; + bestDifference := bitsDifference; + end; + end; + end; + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits + // differing means we found a match + if (bestDifference <= 3) then + begin + Result := TFormatInformation.Create(bestFormatInfo); + exit; + end; +end; + +function TFormatInformation.Equals(o: TObject): Boolean; +var + other: TFormatInformation; +begin + Result := false; + if (not(o is TFormatInformation)) then + exit; + + other := TFormatInformation(o); + Result := ((FErrorCorrectionLevel = other.ErrorCorrectionLevel) and + (FDataMask = other.DataMask)); +end; + +function TFormatInformation.GetHashCode: Integer; +begin + Result := ((FErrorCorrectionLevel.ordinal shl 3) or FDataMask) +end; + +class procedure TFormatInformation.InitializeClass; +begin + SetLength(FORMAT_INFO_DECODE_LOOKUP, $20); + + FORMAT_INFO_DECODE_LOOKUP[0] := TArray.Create($5412, 0); + FORMAT_INFO_DECODE_LOOKUP[1] := TArray.Create($5125, 1); + FORMAT_INFO_DECODE_LOOKUP[2] := TArray.Create($5E7C, 2); + FORMAT_INFO_DECODE_LOOKUP[3] := TArray.Create($5B4B, 3); + FORMAT_INFO_DECODE_LOOKUP[4] := TArray.Create($45F9, 4); + FORMAT_INFO_DECODE_LOOKUP[5] := TArray.Create($40CE, 5); + FORMAT_INFO_DECODE_LOOKUP[6] := TArray.Create($4F97, 6); + FORMAT_INFO_DECODE_LOOKUP[7] := TArray.Create($4AA0, 7); + FORMAT_INFO_DECODE_LOOKUP[8] := TArray.Create($77C4, 8); + FORMAT_INFO_DECODE_LOOKUP[9] := TArray.Create($72F3, 9); + FORMAT_INFO_DECODE_LOOKUP[10] := TArray.Create($7DAA, 10); + FORMAT_INFO_DECODE_LOOKUP[11] := TArray.Create($789D, 11); + FORMAT_INFO_DECODE_LOOKUP[12] := TArray.Create($662F, 12); + FORMAT_INFO_DECODE_LOOKUP[13] := TArray.Create($6318, 13); + FORMAT_INFO_DECODE_LOOKUP[14] := TArray.Create($6C41, 14); + FORMAT_INFO_DECODE_LOOKUP[15] := TArray.Create($6976, 15); + FORMAT_INFO_DECODE_LOOKUP[$10] := TArray.Create($1689, $10); + FORMAT_INFO_DECODE_LOOKUP[$11] := TArray.Create($13BE, $11); + FORMAT_INFO_DECODE_LOOKUP[$12] := TArray.Create($1CE7, $12); + FORMAT_INFO_DECODE_LOOKUP[$13] := TArray.Create($19D0, $13); + FORMAT_INFO_DECODE_LOOKUP[20] := TArray.Create($762, 20); + FORMAT_INFO_DECODE_LOOKUP[$15] := TArray.Create($255, $15); + FORMAT_INFO_DECODE_LOOKUP[$16] := TArray.Create($D0C, $16); + FORMAT_INFO_DECODE_LOOKUP[$17] := TArray.Create($83B, $17); + FORMAT_INFO_DECODE_LOOKUP[$18] := TArray.Create($355F, $18); + FORMAT_INFO_DECODE_LOOKUP[$19] := TArray.Create($3068, $19); + FORMAT_INFO_DECODE_LOOKUP[$1A] := TArray.Create($3F31, $1A); + FORMAT_INFO_DECODE_LOOKUP[$1B] := TArray.Create($3A06, $1B); + FORMAT_INFO_DECODE_LOOKUP[$1C] := TArray.Create($24B4, $1C); + FORMAT_INFO_DECODE_LOOKUP[$1D] := TArray.Create($2183, $1D); + FORMAT_INFO_DECODE_LOOKUP[30] := TArray.Create($2EDA, 30); + FORMAT_INFO_DECODE_LOOKUP[$1F] := TArray.Create($2BED, $1F); + + BITS_SET_IN_HALF_BYTE := TArray.Create(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, + 2, 3, 2, 3, 3, 4); +end; + +class procedure TFormatInformation.FinalizeClass; +var + i: Integer; +begin + for i := 0 to Pred(Length(FORMAT_INFO_DECODE_LOOKUP)) do + FORMAT_INFO_DECODE_LOOKUP[i] := nil; + + FORMAT_INFO_DECODE_LOOKUP := nil; + BITS_SET_IN_HALF_BYTE := nil; +end; + +class function TFormatInformation.numBitsDiffering(a, b: Integer): Integer; +begin + a := (a xor b); // a now has a 1 bit exactly where its bit differs with b's + // Count bits set quickly with a series of lookups: + Result := BITS_SET_IN_HALF_BYTE[(a and $0F)] + BITS_SET_IN_HALF_BYTE + [TMathUtils.Asr(UInt32(a), 4) and $0F] + BITS_SET_IN_HALF_BYTE + [TMathUtils.Asr(UInt32(a), 8) and $0F] + BITS_SET_IN_HALF_BYTE + [TMathUtils.Asr(UInt32(a), 12) and $0F] + BITS_SET_IN_HALF_BYTE + [TMathUtils.Asr(UInt32(a), 16) and $0F] + BITS_SET_IN_HALF_BYTE + [TMathUtils.Asr(UInt32(a), 20) and $0F] + BITS_SET_IN_HALF_BYTE + [TMathUtils.Asr(UInt32(a), 24) and $0F] + BITS_SET_IN_HALF_BYTE + [TMathUtils.Asr(UInt32(a), 28) and $0F]; +end; + +initialization + +TFormatInformation.InitializeClass; + +finalization + +TFormatInformation.FinalizeClass; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Mode.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Mode.pas new file mode 100644 index 0000000..2913927 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Mode.pas @@ -0,0 +1,248 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E.Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.Mode; + +interface + +uses + System.SysUtils, + ZXing.QrCode.Internal.Version; + +type + /// + ///

See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which + /// data can be encoded to bits in the QR code standard.

+ ///
+ TMode = class sealed + private + Fbits : Integer; + Fname : String; + characterCountBitsForVersions: TArray; + + class procedure InitializeClass; static; + class procedure FinalizeClass; static; + public + constructor Create(const characterCountBitsForVersions: TArray; + const bits: Integer; const name: String); overload; + + // No, we can't use an enum here. J2ME doesn't support it. + + /// + /// + /// + class var TERMINATOR: TMode; + + /// + /// + /// + class var NUMERIC: TMode; + + /// + /// + /// + class var ALPHANUMERIC: TMode; + + /// + /// + /// + class var STRUCTURED_APPEND: TMode; + + /// + /// + /// + class var BYTE: TMode; + + /// + /// + /// + class var ECI: TMode; // character counts don't apply + + /// + /// + /// + class var KANJI: TMode; + + /// + /// + /// + class var FNC1_FIRST_POSITION: TMode; + + /// + /// + /// + class var FNC1_SECOND_POSITION: TMode; + + /// See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. + class var HANZI: TMode; + + /// + /// Fors the bits. + /// + /// four bits encoding a QR Code data mode + /// + /// encoded by these bits + /// + /// if bits do not correspond to a known mode + class function forBits(const bits: Integer): TMode; static; + + /// version in question + /// + /// number of bits used, in this QR Code symbol {@link Version}, to encode the + /// count of characters that will follow encoded in this {@link Mode} + /// + function getCharacterCountBits(const version: TVersion): Integer; + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + function ToString: String; override; + + /// + /// Gets the name. + /// + property Name: String read Fname; + + /// + /// Gets the bits. + /// + property Bits: Integer read Fbits; + end; + +implementation + +{ TMode } + +constructor TMode.Create(const characterCountBitsForVersions: TArray; + const bits: Integer; const name: String); +begin + Self.characterCountBitsForVersions := characterCountBitsForVersions; + Self.Fbits := bits; + Self.Fname := name +end; + +class procedure TMode.InitializeClass; +begin + + TMode.TERMINATOR := TMode.Create(TArray.Create(0, 0, 0), 0, 'TERMINATOR'); + TMode.NUMERIC := TMode.Create(TArray.Create(10, 12, 14), 1, + 'NUMERIC'); + TMode.ALPHANUMERIC := TMode.Create(TArray.Create(9, 11, 13), 2, + 'ALPHANUMERIC'); + TMode.STRUCTURED_APPEND := TMode.Create(TArray.Create(0, 0, 0), 3, + 'STRUCTURED_APPEND'); + TMode.BYTE := TMode.Create(TArray.Create(8, $10, $10), 4, 'BYTE'); + TMode.ECI := TMode.Create(nil, 7, 'ECI'); + TMode.KANJI := TMode.Create(TArray.Create(8, 10, 12), 8, 'KANJI'); + TMode.FNC1_FIRST_POSITION := TMode.Create(nil, 5, 'FNC1_FIRST_POSITION'); + TMode.FNC1_SECOND_POSITION := TMode.Create(nil, 9, 'FNC1_SECOND_POSITION'); + TMode.HANZI := TMode.Create(TArray.Create(8, 10, 12), 13, 'HANZI') +end; + +class procedure TMode.FinalizeClass; +begin + TMode.TERMINATOR.characterCountBitsForVersions := nil; + TMode.NUMERIC.characterCountBitsForVersions := nil; + TMode.ALPHANUMERIC.characterCountBitsForVersions := nil; + TMode.STRUCTURED_APPEND.characterCountBitsForVersions := nil; + TMode.BYTE.characterCountBitsForVersions := nil; + TMode.ECI.characterCountBitsForVersions := nil; + TMode.KANJI.characterCountBitsForVersions := nil; + TMode.FNC1_FIRST_POSITION.characterCountBitsForVersions := nil; + TMode.FNC1_SECOND_POSITION.characterCountBitsForVersions := nil; + TMode.HANZI.characterCountBitsForVersions := nil; + + // SetLength(TMode.TERMINATOR.name, 0); + // SetLength(TMode.NUMERIC.name, 0); + // SetLength(TMode.ALPHANUMERIC.name, 0); + // SetLength(TMode.STRUCTURED_APPEND.name, 0); + // SetLength(TMode.BYTE.name, 0); + // SetLength(TMode.ECI.name, 0); + // SetLength(TMode.KANJI.name, 0); + // SetLength(TMode.FNC1_FIRST_POSITION.name, 0); + // SetLength(TMode.FNC1_SECOND_POSITION.name, 0); + // SetLength(TMode.HANZI.name, 0); + + FreeAndNil(TMode.TERMINATOR); + FreeAndNil(TMode.NUMERIC); + FreeAndNil(TMode.ALPHANUMERIC); + FreeAndNil(TMode.STRUCTURED_APPEND); + FreeAndNil(TMode.BYTE); + FreeAndNil(TMode.ECI); + FreeAndNil(TMode.KANJI); + FreeAndNil(TMode.FNC1_FIRST_POSITION); + FreeAndNil(TMode.FNC1_SECOND_POSITION); + FreeAndNil(TMode.HANZI); + +end; + +class function TMode.forBits(const bits: Integer): TMode; +begin + case bits of + $0: Result := TMode.TERMINATOR; + $1: Result := TMode.NUMERIC; + $2: Result := TMode.ALPHANUMERIC; + $3: Result := TMode.STRUCTURED_APPEND; + $4: Result := TMode.BYTE; + $5: Result := TMode.FNC1_FIRST_POSITION; + $7: Result := TMode.ECI; + $8: Result := TMode.KANJI; + $9: Result := TMode.FNC1_SECOND_POSITION; + $D: Result := TMode.HANZI; // 0xD is defined in GBT 18284-2000, may not be supported in foreign country + else + raise EArgumentException.Create('Invalid arguments'); + end; +end; + +function TMode.getCharacterCountBits(const version: TVersion): Integer; +var + offset, + number : Integer; +begin + if (Self.characterCountBitsForVersions = nil) + then + raise EArgumentException.Create('Character count doesn''t apply to this mode'); + + number := version.VersionNumber; + if (number <= 9) + then + offset := 0 + else + if (number <= 26) + then + offset := 1 + else + offset := 2; + + Result := Self.characterCountBitsForVersions[offset]; +end; + +function TMode.ToString: string; +begin + Result := Self.name; +end; + +initialization + TMode.InitializeClass; +finalization + TMode.FinalizeClass; +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.QRCodeDecoderMetaData.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.QRCodeDecoderMetaData.pas new file mode 100644 index 0000000..bdb6de5 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.QRCodeDecoderMetaData.pas @@ -0,0 +1,77 @@ +{ + * Copyright 2013 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 E. Spelt and K. Gossens +} + + +unit ZXing.QrCode.Internal.QRCodeDecoderMetaData; + +interface + +uses + ZXing.ResultPoint; + +type + /// + /// Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the + /// decoding caller. Callers are expected to process this. + /// + TQRCodeDecoderMetaData = class sealed + private + Fmirrored: Boolean; + public + /// + /// Initializes a new instance of the class. + /// + /// if set to true [mirrored]. + constructor Create(const mirrored: Boolean); + + /// + /// Apply the result points' order correction due to mirroring. + /// + /// Array of points to apply mirror correction to. + procedure applyMirroredCorrection(const points: TArray); + + /// + /// true if the QR Code was mirrored. + /// + property IsMirrored: boolean read Fmirrored; + end; + +implementation + +{ TQRCodeDecoderMetaData } + +constructor TQRCodeDecoderMetaData.Create(const mirrored: Boolean); +begin + Fmirrored := mirrored; +end; + +procedure TQRCodeDecoderMetaData.applyMirroredCorrection( + const points: TArray); +var + bottomLeft: IResultPoint; +begin + if ((FMirrored and (points <> nil)) and (Length(points) >= 3)) then + begin + bottomLeft := points[0]; + points[0] := points[2]; + points[2] := bottomLeft; + // No need to 'fix' top-left and alignment pattern. + end +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Version.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Version.pas new file mode 100644 index 0000000..5d6208a --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Decoder/ZXing.QrCode.Internal.Version.pas @@ -0,0 +1,681 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.Version; + +interface + +uses + System.SysUtils, + ZXing.Common.Bitmatrix, + ZXing.QrCode.Internal.ErrorCorrectionLevel, + ZXing.QrCode.Internal.FormatInformation, + ZXing.Common.Detector.MathUtils; + +type + /// + /// See ISO 18004:2006 Annex D + /// + TVersion = class + type + TECB = class + public + count: Integer; + dataCodewords: Integer; + constructor Create(count: Integer; dataCodewords: Integer); + end; + + TECBlocks = class sealed + private + ecBlocks: TArray; + + function getTotalECCodeWords: Integer; + function get_NumBlocks: Integer; + public + ecCodewordsPerBlock: Integer; + constructor Create(ecCodewordsPerBlock: Integer; ecBlocks: TArray); + destructor Destroy; override; + function getECBlocks: TArray; + { property ecCodewordsPerBlock: Integer read get_ECCodewordsPerBlock; + property NumBlocks: Integer read get_NumBlocks; + property TotalECCodewords: Integer read get_TotalECCodewords; + } + property NumBlocks: Integer read get_NumBlocks; + property TotalECCodewords: Integer read getTotalECCodeWords; + end; + + private + FalignmentPatternCenters: TArray; + FecBlocks: TArray; + FTotalCodewords: Integer; + FversionNumber: Integer; + + class var BuildVersions : TArray; + /// See ISO 18004:2006 Annex D. + /// Element i represents the raw version bits that specify version i + 7 + /// + class var VERSION_DECODE_INFO: TArray; + + function CalcDimensionForVersion: Integer; + class function GetBuildVersions: TArray; static; + class procedure ClassInit; static; + class procedure ClassFinal; static; + + public + constructor Create(const versionNumber: Integer; + const alignmentPatternCenters: TArray; + const ecBlocks: TArray); + destructor Destroy; override; + + class function decodeVersionInformation(versionBits: Integer) + : TVersion; static; + function buildFunctionPattern: TBitMatrix; + function getECBlocksForLevel(ecLevel: TErrorCorrectionLevel): TECBlocks; + class function getProvisionalVersionForDimension( + const dimension: Integer): TVersion; static; + class function getVersionForNumber( + const versionNumber: Integer): TVersion; static; + function ToString: String; override; + + property DimensionForVersion: Integer read CalcDimensionForVersion; + property alignmentPatternCenters: TArray + read FalignmentPatternCenters; + + property TotalCodewords: Integer read FTotalCodewords; + property versionNumber: Integer read FversionNumber; + end; + +implementation + +{ TVersion.TECB } + +constructor TVersion.TECB.Create(count, dataCodewords: Integer); +begin + self.count := count; + self.dataCodewords := dataCodewords; +end; + +{ TVersion.TECBlocks } + +constructor TVersion.TECBlocks.Create(ecCodewordsPerBlock: Integer; + ecBlocks: TArray); +begin + self.ecBlocks := ecBlocks; + self.ecCodewordsPerBlock := ecCodewordsPerBlock; +end; + +destructor TVersion.TECBlocks.Destroy; +begin + ecBlocks :=nil; + inherited; +end; + +function TVersion.TECBlocks.getECBlocks: TArray; +begin + result := self.ecBlocks; +end; + +function TVersion.TECBlocks.getTotalECCodeWords: Integer; +begin + result := ecCodewordsPerBlock * NumBlocks; +end; + +function TVersion.TECBlocks.get_NumBlocks: Integer; +var + total: Integer; + ecBlock: TECB; +begin + total := 0; + for ecBlock in ecBlocks do + begin + inc(total, ecBlock.count); + end; + + result := total; + +end; + +{ TVersion } + +constructor TVersion.Create(const versionNumber: Integer; + const alignmentPatternCenters: TArray; + const ecBlocks: TArray); +var + ecBlock: TECB; + total, ecCodewords: Integer; + ecbArray: TArray; +begin + FversionNumber := versionNumber; + FalignmentPatternCenters := alignmentPatternCenters; + FecBlocks := ecBlocks; + total := 0; + ecCodewords := ecBlocks[0].ecCodewordsPerBlock; + ecbArray := ecBlocks[0].getECBlocks; + + for ecBlock in ecbArray do + Inc(total, (ecBlock.count * (ecBlock.dataCodewords + ecCodewords))); + + FTotalCodewords := total; + ecbArray := nil; +end; + +destructor TVersion.Destroy; +var + ecBlocks : TECBlocks; + ECB : TECB; +begin + FalignmentPatternCenters := nil; + for ecBlocks in FecBlocks do + begin + for ecb in ecBlocks.ecBlocks do + begin + ECB.Free; + //ECB := nil; + end; + ecBlocks.free; + end; + + FecBlocks := nil; + + inherited; +end; + +function TVersion.buildFunctionPattern: TBitMatrix; +var + dimension, max, x, i, y: Integer; +begin + dimension := DimensionForVersion; + result := TBitMatrix.Create(dimension); + result.setRegion(0, 0, 9, 9); + result.setRegion((dimension - 8), 0, 8, 9); + result.setRegion(0, (dimension - 8), 9, 8); + max := Length(FalignmentPatternCenters); + x := 0; + + while ((x < max)) do + begin + i := (FalignmentPatternCenters[x] - 2); + y := 0; + while ((y < max)) do + begin + if (((x <> 0) or ((y <> 0) and (y <> (max - 1)))) and + ((x <> (max - 1)) or (y <> 0))) then + result.setRegion((self.alignmentPatternCenters[y] - 2), i, 5, 5); + inc(y) + end; + inc(x) + end; + + result.setRegion(6, 9, 1, (dimension - $11)); + result.setRegion(9, 6, (dimension - $11), 1); + if (self.versionNumber > 6) then + begin + result.setRegion((dimension - 11), 0, 3, 6); + result.setRegion(0, (dimension - 11), 6, 3) + end; + +end; + +class function TVersion.GetBuildVersions: TArray; +begin + Result := TArray.Create( + + TVersion.Create(1, TArray.Create(), + TArray.Create(TECBlocks.Create(7, + TArray.Create(TECB.Create(1, 19))), TECBlocks.Create(10, + TArray.Create(TECB.Create(1, 16))), TECBlocks.Create(13, + TArray.Create(TECB.Create(1, 13))), TECBlocks.Create(17, + TArray.Create(TECB.Create(1, 9))))), + + TVersion.Create(2, TArray.Create(6, 18), + TArray.Create(TECBlocks.Create(10, + TArray.Create(TECB.Create(1, 34))), TECBlocks.Create(16, + TArray.Create(TECB.Create(1, 28))), TECBlocks.Create(22, + TArray.Create(TECB.Create(1, 22))), TECBlocks.Create(28, + TArray.Create(TECB.Create(1, 16))))), + + TVersion.Create(3, TArray.Create(6, 22), + TArray.Create(TECBlocks.Create(15, + TArray.Create(TECB.Create(1, 55))), TECBlocks.Create(26, + TArray.Create(TECB.Create(1, 44))), TECBlocks.Create(18, + TArray.Create(TECB.Create(2, 17))), TECBlocks.Create(22, + TArray.Create(TECB.Create(2, 13))))), + + TVersion.Create(4, TArray.Create(6, 26), + TArray.Create(TECBlocks.Create(20, + TArray.Create(TECB.Create(1, 80))), TECBlocks.Create(18, + TArray.Create(TECB.Create(2, 32))), TECBlocks.Create(26, + TArray.Create(TECB.Create(2, 24))), TECBlocks.Create(16, + TArray.Create(TECB.Create(4, 9))))), + + TVersion.Create(5, TArray.Create(6, 30), + TArray.Create(TECBlocks.Create(26, + TArray.Create(TECB.Create(1, 108))), TECBlocks.Create(24, + TArray.Create(TECB.Create(2, 43))), TECBlocks.Create(18, + TArray.Create(TECB.Create(2, 15), TECB.Create(2, 16))), + TECBlocks.Create(22, TArray.Create(TECB.Create(2, 11), + TECB.Create(2, 12))))), + + TVersion.Create(6, TArray.Create(6, 34), + TArray.Create(TECBlocks.Create(18, + TArray.Create(TECB.Create(2, 68))), TECBlocks.Create(16, + TArray.Create(TECB.Create(4, 27))), TECBlocks.Create(24, + TArray.Create(TECB.Create(4, 19))), TECBlocks.Create(28, + TArray.Create(TECB.Create(4, 15))))), + + TVersion.Create(7, TArray.Create(6, 22, 38), + TArray.Create(TECBlocks.Create(20, + TArray.Create(TECB.Create(2, 78))), TECBlocks.Create(18, + TArray.Create(TECB.Create(4, 31))), TECBlocks.Create(18, + TArray.Create(TECB.Create(2, 14), TECB.Create(4, 15))), + TECBlocks.Create(26, TArray.Create(TECB.Create(4, 13), + TECB.Create(1, 14))))), + + TVersion.Create(8, TArray.Create(6, 24, 42), + TArray.Create(TECBlocks.Create(24, + TArray.Create(TECB.Create(2, 97))), TECBlocks.Create(22, + TArray.Create(TECB.Create(2, 38), TECB.Create(2, 39))), + TECBlocks.Create(22, TArray.Create(TECB.Create(4, 18), TECB.Create(2, + 19))), TECBlocks.Create(26, TArray.Create(TECB.Create(4, 14), + TECB.Create(2, 15))))), + + TVersion.Create(9, TArray.Create(6, 26, 46), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(2, 116))), TECBlocks.Create(22, + TArray.Create(TECB.Create(3, 36), TECB.Create(2, 37))), + TECBlocks.Create(20, TArray.Create(TECB.Create(4, 16), TECB.Create(4, + 17))), TECBlocks.Create(24, TArray.Create(TECB.Create(4, 12), + TECB.Create(4, 13))))), + + TVersion.Create(10, TArray.Create(6, 28, 50), + TArray.Create(TECBlocks.Create(18, + TArray.Create(TECB.Create(2, 68), TECB.Create(2, 69))), + TECBlocks.Create(26, TArray.Create(TECB.Create(4, 43), TECB.Create(1, + 44))), TECBlocks.Create(24, TArray.Create(TECB.Create(6, 19), + TECB.Create(2, 20))), TECBlocks.Create(28, + TArray.Create(TECB.Create(6, 15), TECB.Create(2, 16))))), + + TVersion.Create(11, TArray.Create(6, 30, 54), + TArray.Create(TECBlocks.Create(20, + TArray.Create(TECB.Create(4, 81))), TECBlocks.Create(30, + TArray.Create(TECB.Create(1, 50), TECB.Create(4, 51))), + TECBlocks.Create(28, TArray.Create(TECB.Create(4, 22), TECB.Create(4, + 23))), TECBlocks.Create(24, TArray.Create(TECB.Create(3, 12), + TECB.Create(8, 13))))), + + TVersion.Create(12, TArray.Create(6, 32, 58), + TArray.Create(TECBlocks.Create(24, + TArray.Create(TECB.Create(2, 92), TECB.Create(2, 93))), + TECBlocks.Create(22, TArray.Create(TECB.Create(6, 36), TECB.Create(2, + 37))), TECBlocks.Create(26, TArray.Create(TECB.Create(4, 20), + TECB.Create(6, 21))), TECBlocks.Create(28, + TArray.Create(TECB.Create(7, 14), TECB.Create(4, 15))))), + + TVersion.Create(13, TArray.Create(6, 34, 62), + TArray.Create(TECBlocks.Create(26, + TArray.Create(TECB.Create(4, 107))), TECBlocks.Create(22, + TArray.Create(TECB.Create(8, 37), TECB.Create(1, 38))), + TECBlocks.Create(24, TArray.Create(TECB.Create(8, 20), TECB.Create(4, + 21))), TECBlocks.Create(22, TArray.Create(TECB.Create(12, 11), + TECB.Create(4, 12))))), + + TVersion.Create(14, TArray.Create(6, 26, 46, 66), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(3, 115), TECB.Create(1, 116))), + TECBlocks.Create(24, TArray.Create(TECB.Create(4, 40), TECB.Create(5, + 41))), TECBlocks.Create(20, TArray.Create(TECB.Create(11, 16), + TECB.Create(5, 17))), TECBlocks.Create(24, + TArray.Create(TECB.Create(11, 12), TECB.Create(5, 13))))), + + TVersion.Create(15, TArray.Create(6, 26, 48, 70), + TArray.Create(TECBlocks.Create(22, + TArray.Create(TECB.Create(5, 87), TECB.Create(1, 88))), + TECBlocks.Create(24, TArray.Create(TECB.Create(5, 41), TECB.Create(5, + 42))), TECBlocks.Create(30, TArray.Create(TECB.Create(5, 24), + TECB.Create(7, 25))), TECBlocks.Create(24, + TArray.Create(TECB.Create(11, 12), TECB.Create(7, 13))))), + + TVersion.Create(16, TArray.Create(6, 26, 50, 74), + TArray.Create(TECBlocks.Create(24, + TArray.Create(TECB.Create(5, 98), TECB.Create(1, 99))), + TECBlocks.Create(28, TArray.Create(TECB.Create(7, 45), TECB.Create(3, + 46))), TECBlocks.Create(24, TArray.Create(TECB.Create(15, 19), + TECB.Create(2, 20))), TECBlocks.Create(30, + TArray.Create(TECB.Create(3, 15), TECB.Create(13, 16))))), + + TVersion.Create(17, TArray.Create(6, 30, 54, 78), + TArray.Create(TECBlocks.Create(28, + TArray.Create(TECB.Create(1, 107), TECB.Create(5, 108))), + TECBlocks.Create(28, TArray.Create(TECB.Create(10, 46), TECB.Create(1, + 47))), TECBlocks.Create(28, TArray.Create(TECB.Create(1, 22), + TECB.Create(15, 23))), TECBlocks.Create(28, + TArray.Create(TECB.Create(2, 14), TECB.Create(17, 15))))), + + TVersion.Create(18, TArray.Create(6, 30, 56, 82), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(5, 120), TECB.Create(1, 121))), + TECBlocks.Create(26, TArray.Create(TECB.Create(9, 43), TECB.Create(4, + 44))), TECBlocks.Create(28, TArray.Create(TECB.Create(17, 22), + TECB.Create(1, 23))), TECBlocks.Create(28, + TArray.Create(TECB.Create(2, 14), TECB.Create(19, 15))))), + + TVersion.Create(19, TArray.Create(6, 30, 58, 86), + TArray.Create(TECBlocks.Create(28, + TArray.Create(TECB.Create(3, 113), TECB.Create(4, 114))), + TECBlocks.Create(26, TArray.Create(TECB.Create(3, 44), TECB.Create(11, + 45))), TECBlocks.Create(26, TArray.Create(TECB.Create(17, 21), + TECB.Create(4, 22))), TECBlocks.Create(26, + TArray.Create(TECB.Create(9, 13), TECB.Create(16, 14))))), + + TVersion.Create(20, TArray.Create(6, 34, 62, 90), + TArray.Create(TECBlocks.Create(28, + TArray.Create(TECB.Create(3, 107), TECB.Create(5, 108))), + TECBlocks.Create(26, TArray.Create(TECB.Create(3, 41), TECB.Create(13, + 42))), TECBlocks.Create(30, TArray.Create(TECB.Create(15, 24), + TECB.Create(5, 25))), TECBlocks.Create(28, + TArray.Create(TECB.Create(15, 15), TECB.Create(10, 16))))), + + TVersion.Create(21, TArray.Create(6, 28, 50, 72, 94), + TArray.Create(TECBlocks.Create(28, + TArray.Create(TECB.Create(4, 116), TECB.Create(4, 117))), + TECBlocks.Create(26, TArray.Create(TECB.Create(17, 42))), + TECBlocks.Create(28, TArray.Create(TECB.Create(17, 22), TECB.Create(6, + 23))), TECBlocks.Create(30, TArray.Create(TECB.Create(19, 16), + TECB.Create(6, 17))))), + + TVersion.Create(22, TArray.Create(6, 26, 50, 74, 98), + TArray.Create(TECBlocks.Create(28, + TArray.Create(TECB.Create(2, 111), TECB.Create(7, 112))), + TECBlocks.Create(28, TArray.Create(TECB.Create(17, 46))), + TECBlocks.Create(30, TArray.Create(TECB.Create(7, 24), TECB.Create(16, + 25))), TECBlocks.Create(24, TArray.Create(TECB.Create(34, 13))))), + + TVersion.Create(23, TArray.Create(6, 30, 54, 78, 102), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(4, 121), TECB.Create(5, 122))), + TECBlocks.Create(28, TArray.Create(TECB.Create(4, 47), TECB.Create(14, + 48))), TECBlocks.Create(30, TArray.Create(TECB.Create(11, 24), + TECB.Create(14, 25))), TECBlocks.Create(30, + TArray.Create(TECB.Create(16, 15), TECB.Create(14, 16))))), + + TVersion.Create(24, TArray.Create(6, 28, 54, 80, 106), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(6, 117), TECB.Create(4, 118))), + TECBlocks.Create(28, TArray.Create(TECB.Create(6, 45), TECB.Create(14, + 46))), TECBlocks.Create(30, TArray.Create(TECB.Create(11, 24), + TECB.Create(16, 25))), TECBlocks.Create(30, + TArray.Create(TECB.Create(30, 16), TECB.Create(2, 17))))), + + TVersion.Create(25, TArray.Create(6, 32, 58, 84, 110), + TArray.Create(TECBlocks.Create(26, + TArray.Create(TECB.Create(8, 106), TECB.Create(4, 107))), + TECBlocks.Create(28, TArray.Create(TECB.Create(8, 47), TECB.Create(13, + 48))), TECBlocks.Create(30, TArray.Create(TECB.Create(7, 24), + TECB.Create(22, 25))), TECBlocks.Create(30, + TArray.Create(TECB.Create(22, 15), TECB.Create(13, 16))))), + + TVersion.Create(26, TArray.Create(6, 30, 58, 86, 114), + TArray.Create(TECBlocks.Create(28, + TArray.Create(TECB.Create(10, 114), TECB.Create(2, 115))), + TECBlocks.Create(28, TArray.Create(TECB.Create(19, 46), TECB.Create(4, + 47))), TECBlocks.Create(28, TArray.Create(TECB.Create(28, 22), + TECB.Create(6, 23))), TECBlocks.Create(30, + TArray.Create(TECB.Create(33, 16), TECB.Create(4, 17))))), + + TVersion.Create(27, TArray.Create(6, 34, 62, 90, 118), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(8, 122), TECB.Create(4, 123))), + TECBlocks.Create(28, TArray.Create(TECB.Create(22, 45), TECB.Create(3, + 46))), TECBlocks.Create(30, TArray.Create(TECB.Create(8, 23), + TECB.Create(26, 24))), TECBlocks.Create(30, + TArray.Create(TECB.Create(12, 15), TECB.Create(28, 16))))), + + TVersion.Create(28, TArray.Create(6, 26, 50, 74, 98, 122), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(3, 117), TECB.Create(10, 118))), + TECBlocks.Create(28, TArray.Create(TECB.Create(3, 45), TECB.Create(23, + 46))), TECBlocks.Create(30, TArray.Create(TECB.Create(4, 24), + TECB.Create(31, 25))), TECBlocks.Create(30, + TArray.Create(TECB.Create(11, 15), TECB.Create(31, 16))))), + + TVersion.Create(29, TArray.Create(6, 30, 54, 78, 102, 126), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(7, 116), TECB.Create(7, 117))), + TECBlocks.Create(28, TArray.Create(TECB.Create(21, 45), TECB.Create(7, + 46))), TECBlocks.Create(30, TArray.Create(TECB.Create(1, 23), + TECB.Create(37, 24))), TECBlocks.Create(30, + TArray.Create(TECB.Create(19, 15), TECB.Create(26, 16))))), + + TVersion.Create(30, TArray.Create(6, 26, 52, 78, 104, 130), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(5, 115), TECB.Create(10, 116))), + TECBlocks.Create(28, TArray.Create(TECB.Create(19, 47), + TECB.Create(10, 48))), TECBlocks.Create(30, + TArray.Create(TECB.Create(15, 24), TECB.Create(25, 25))), + TECBlocks.Create(30, TArray.Create(TECB.Create(23, 15), + TECB.Create(25, 16))))), + + TVersion.Create(31, TArray.Create(6, 30, 56, 82, 108, 134), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(13, 115), TECB.Create(3, 116))), + TECBlocks.Create(28, TArray.Create(TECB.Create(2, 46), TECB.Create(29, + 47))), TECBlocks.Create(30, TArray.Create(TECB.Create(42, 24), + TECB.Create(1, 25))), TECBlocks.Create(30, + TArray.Create(TECB.Create(23, 15), TECB.Create(28, 16))))), + + TVersion.Create(32, TArray.Create(6, 34, 60, 86, 112, 138), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(17, 115))), TECBlocks.Create(28, + TArray.Create(TECB.Create(10, 46), TECB.Create(23, 47))), + TECBlocks.Create(30, TArray.Create(TECB.Create(10, 24), + TECB.Create(35, 25))), TECBlocks.Create(30, + TArray.Create(TECB.Create(19, 15), TECB.Create(35, 16))))), + + TVersion.Create(33, TArray.Create(6, 30, 58, 86, 114, 142), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(17, 115), TECB.Create(1, 116))), + TECBlocks.Create(28, TArray.Create(TECB.Create(14, 46), + TECB.Create(21, 47))), TECBlocks.Create(30, + TArray.Create(TECB.Create(29, 24), TECB.Create(19, 25))), + TECBlocks.Create(30, TArray.Create(TECB.Create(11, 15), + TECB.Create(46, 16))))), + + TVersion.Create(34, TArray.Create(6, 34, 62, 90, 118, 146), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(13, 115), TECB.Create(6, 116))), + TECBlocks.Create(28, TArray.Create(TECB.Create(14, 46), + TECB.Create(23, 47))), TECBlocks.Create(30, + TArray.Create(TECB.Create(44, 24), TECB.Create(7, 25))), + TECBlocks.Create(30, TArray.Create(TECB.Create(59, 16), + TECB.Create(1, 17))))), + + TVersion.Create(35, TArray.Create(6, 30, 54, 78, 102, 126, 150), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(12, 121), TECB.Create(7, 122))), + TECBlocks.Create(28, TArray.Create(TECB.Create(12, 47), + TECB.Create(26, 48))), TECBlocks.Create(30, + TArray.Create(TECB.Create(39, 24), TECB.Create(14, 25))), + TECBlocks.Create(30, TArray.Create(TECB.Create(22, 15), + TECB.Create(41, 16))))), + + TVersion.Create(36, TArray.Create(6, 24, 50, 76, 102, 128, 154), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(6, 121), TECB.Create(14, 122))), + TECBlocks.Create(28, TArray.Create(TECB.Create(6, 47), TECB.Create(34, + 48))), TECBlocks.Create(30, TArray.Create(TECB.Create(46, 24), + TECB.Create(10, 25))), TECBlocks.Create(30, + TArray.Create(TECB.Create(2, 15), TECB.Create(64, 16))))), + + TVersion.Create(37, TArray.Create(6, 28, 54, 80, 106, 132, 158), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(17, 122), TECB.Create(4, 123))), + TECBlocks.Create(28, TArray.Create(TECB.Create(29, 46), + TECB.Create(14, 47))), TECBlocks.Create(30, + TArray.Create(TECB.Create(49, 24), TECB.Create(10, 25))), + TECBlocks.Create(30, TArray.Create(TECB.Create(24, 15), + TECB.Create(46, 16))))), + + TVersion.Create(38, TArray.Create(6, 32, 58, 84, 110, 136, 162), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(4, 122), TECB.Create(18, 123))), + TECBlocks.Create(28, TArray.Create(TECB.Create(13, 46), + TECB.Create(32, 47))), TECBlocks.Create(30, + TArray.Create(TECB.Create(48, 24), TECB.Create(14, 25))), + TECBlocks.Create(30, TArray.Create(TECB.Create(42, 15), + TECB.Create(32, 16))))), + + TVersion.Create(39, TArray.Create(6, 26, 54, 82, 110, 138, 166), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(20, 117), TECB.Create(4, 118))), + TECBlocks.Create(28, TArray.Create(TECB.Create(40, 47), TECB.Create(7, + 48))), TECBlocks.Create(30, TArray.Create(TECB.Create(43, 24), + TECB.Create(22, 25))), TECBlocks.Create(30, + TArray.Create(TECB.Create(10, 15), TECB.Create(67, 16))))), + + TVersion.Create(40, TArray.Create(6, 30, 58, 86, 114, 142, 170), + TArray.Create(TECBlocks.Create(30, + TArray.Create(TECB.Create(19, 118), TECB.Create(6, 119))), + TECBlocks.Create(28, TArray.Create(TECB.Create(18, 47), + TECB.Create(31, 48))), TECBlocks.Create(30, + TArray.Create(TECB.Create(34, 24), TECB.Create(34, 25))), + TECBlocks.Create(30, TArray.Create(TECB.Create(20, 15), + TECB.Create(61, 16))))) + + ); + +end; + +function TVersion.CalcDimensionForVersion: Integer; +begin + result := 17 + 4 * versionNumber; +end; + +class function TVersion.decodeVersionInformation(versionBits: Integer) + : TVersion; +var + bestDifference, bestversion, i, targetVersion, bitsDifference: Integer; +begin + bestDifference := $7FFFFFFF; + bestversion := 0; + i := 0; + + while ((i < Length(TVersion.VERSION_DECODE_INFO))) do + begin + targetVersion := TVersion.VERSION_DECODE_INFO[i]; + + if (targetVersion = versionBits) then + begin + result := TVersion.getVersionForNumber((i + 7)); + exit + end; + + bitsDifference := TFormatInformation.numBitsDiffering(versionBits, + targetVersion); + + if (bitsDifference < bestDifference) then + begin + bestversion := (i + 7); + bestDifference := bitsDifference + end; + inc(i) + + end; + + if (bestDifference <= 3) then + begin + result := TVersion.getVersionForNumber(bestversion); + exit + end; + + result := nil; +end; + +function TVersion.getECBlocksForLevel(ecLevel: TErrorCorrectionLevel) + : TECBlocks; +begin + result := FecBlocks[ecLevel.ordinal] +end; + +class function TVersion.getProvisionalVersionForDimension( + const dimension: Integer): TVersion; +begin + Result := nil; + + if ((dimension mod 4) <> 1) + then + exit; + + try + Result := TVersion.getVersionForNumber(TMathUtils.Asr(dimension - $11, 2)); + except + on E: EArgumentException do + Result := nil; + end +end; + +class function TVersion.getVersionForNumber( + const versionNumber: Integer): TVersion; +begin + if ((versionNumber < 1) or (versionNumber > 40)) then + raise EArgumentException.Create + ('version number needs to be between 1 and 40'); + + Result := TVersion.BuildVersions[(versionNumber - 1)]; +end; + +function TVersion.ToString: string; +begin + result := self.versionNumber.ToString(); +end; + +class procedure TVersion.ClassInit(); +begin + TVersion.VERSION_DECODE_INFO := TArray.Create($7C94, $85BC, $9A99, + $A4D3, $BBF6, $C762, $D847, $E60D, $F928, $10B78, $1145D, $12A17, $13532, + $149A6, $15683, $168C9, $177EC, $18EC4, $191E1, $1AFAB, $1B08E, $1CC1A, + $1D33F, $1ED75, $1F250, $209D5, $216F0, $228BA, $2379F, $24B0B, $2542E, + $26A64, $27541, $28C69); + + TVersion.BuildVersions := TVersion.GetBuildVersions; +end; + +class procedure TVersion.ClassFinal(); +var version :Tversion; +begin + TVersion.VERSION_DECODE_INFO := nil; + + for version in TVersion.BuildVersions do + begin + version.Free; + end; + + TVersion.BuildVersions :=nil; +end; + + +Initialization + +TVersion.ClassInit(); + +Finalization + +TVersion.ClassFinal(); + + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.Datamatrix.Internal.Detector.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.Datamatrix.Internal.Detector.pas new file mode 100644 index 0000000..7d6f6d2 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.Datamatrix.Internal.Detector.pas @@ -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 + /// + ///

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.

+ ///
+ TDataMatrixDetector = class(TObject) + private + var + Fimage: TBitMatrix; + FrectangleDetector: TWhiteRectangleDetector; + + type + /// + /// Simply encapsulates two points and a number of transitions between them. + /// + 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; + + /// + /// Orders ResultPointsAndTransitions by number of transitions, ascending. + /// + TResultPointsAndTransitionsComparator = class sealed + (TComparer) + 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; + 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 } + +/// +/// Initializes a new instance of the class. +/// +/// The image. +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; + +/// +///

Detects a Data Matrix Code in an image.

+///
+/// encapsulating results of detecting a Data Matrix Code or null +function TDataMatrixDetector.detect(): TDetectorResult; +var + topRight, correctedTopRight, pointA, pointB, pointC, pointD, maybeTopLeft, + bottomLeft, bottomRight, topLeft, maybeBottomRight, point: IResultPoint; + + cornerPoints: TArray; + bits: TBitMatrix; + entry: TPair; // TKeyValuePair + Transitions: TObjectList; + lSideOne, lSideTwo, transBetween, transA, transB: TResultPointsAndTransitions; + pointCount: TDictionary; + + corners: TArray; + + 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.Create; + pointCount := TDictionary.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.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.Create(topLeft, + bottomLeft, bottomRight, correctedTopRight)); + + finally + pointCount.Free; + Transitions.Free; + cornerPoints := nil; + end; +end; + +/// +/// Calculates the position of the white top right module using the output of the rectangle detector +/// for a rectangular matrix +/// +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; + +/// +/// Calculates the position of the white top right module using the output of the rectangle detector +/// for a square matrix +/// +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; + +/// +/// Increments the Integer associated with a key by one. +/// +procedure TDataMatrixDetector.increment + (table: TDictionary; 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; + +/// +/// Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. +/// +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. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPattern.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPattern.pas new file mode 100644 index 0000000..73649b0 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPattern.pas @@ -0,0 +1,69 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E.Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.AlignmentPattern; +interface +uses ZXing.ResultPoint; + +type + /// + /// As we did for ResultPoint, we use an interfaced object to implement automatic deallocation + /// of TAligmnentPattern instances + /// the actual implementation of this interface is in unit ZXing.QrCode.Internal.AlignmentPatternImplementation + /// + IAlignmentPattern = interface(IResultPoint) + ['{8C0A5D01-9620-42B6-BE3E-9C40717B5B38}'] + ///

Determines if this alignment pattern "about equals" an alignment pattern at the stated + /// position and size -- meaning, it is at nearly the same center with nearly the same size.

+ ///
+ function aboutEquals(const moduleSize, i, j: Single): Boolean; + + /// + /// Combines this object's current estimate of a finder pattern position and module size + /// with a new estimate. It returns a new {@code FinderPattern} containing an average of the two. + /// + /// The i. + /// The j. + /// New size of the module. + /// + function combineEstimate(const i, j, newModuleSize: Single): IAlignmentPattern; + end; + + + /// + /// contains all static methods for using IAlignmentPatterns instances + /// + TAlignmentPatternHelpers = class + /// + /// IAlignmentPattern instances must be obtained by calling this function + /// + class function CreateAlignmentPattern(const posX, posY, estimatedModuleSize: Single):IAlignmentPattern; + end; + +implementation +uses ZXing.QrCode.Internal.AlignmentPatternImplementation; + +{ TAlignmentPatternHelpers } +class function TAlignmentPatternHelpers.CreateAlignmentPattern(const posX, posY, estimatedModuleSize: Single):IAlignmentPattern; +begin + result := ZXing.QrCode.Internal.AlignmentPatternImplementation.NewAlignmentPattern(posX,posY,estimatedModuleSize); +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPatternFinder.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPatternFinder.pas new file mode 100644 index 0000000..b09c265 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPatternFinder.pas @@ -0,0 +1,407 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E.Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.AlignmentPatternFinder; + +interface + +uses + System.SysUtils, + System.Math, + System.Generics.Collections, + ZXing.Common.BitMatrix, + ZXing.QrCode.Internal.AlignmentPattern, // nullableType, + ZXing.ResultPoint, + ZXing.Common.Detector.MathUtils; + +type + ///

This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder + /// patterns but are smaller and appear at regular intervals throughout the image.

+ /// + ///

At the moment this only looks for the bottom-right alignment pattern.

+ /// + ///

This is mostly a simplified copy of {@link FinderPatternFinder}. It is copied, + /// pasted and stripped down here for maximum performance but does unfortunately duplicate + /// some code.

+ /// + ///

This class is thread-safe but not reentrant. Each thread must allocate its own object.

+ /// + ///
+ TAlignmentPatternFinder = class sealed + private + image: TBitMatrix; + possibleCenters: TList; + startX, startY: Integer; + width, height: Integer; + moduleSize: Single; + crossCheckStateCount: TArray; + resultPointCallback: TResultPointCallback; + + /// Given a count of black/white/black pixels just seen and an end position, + /// figures the location of the center of this black/white/black run. + /// + class function centerFromEnd(const stateCount: TArray; + const pEnd: Integer): Single; static; + + /// count of black/white/black pixels just read + /// + /// true iff the proportions of the counts is close enough to the 1/1/1 ratios + /// used by alignment patterns to be considered a match + /// + function foundPatternCross(const stateCount: TArray): Boolean; + + /// + ///

After a horizontal scan finds a potential alignment pattern, this method + /// "cross-checks" by scanning down vertically through the center of the possible + /// alignment pattern to see if the same proportion is detected.

+ ///
+ /// row where an alignment pattern was detected + /// center of the section that appears to cross an alignment pattern + /// maximum reasonable number of modules that should be + /// observed in any reading state, based on the results of the horizontal scan + /// The original state count total. + /// + /// vertical center of alignment pattern, or null if not found + /// + function crossCheckVertical(const startI, centerJ, maxCount, + originalStateCountTotal: Integer): Single; + + ///

This is called when a horizontal scan finds a possible alignment pattern. It will + /// cross check with a vertical scan, and if successful, will see if this pattern had been + /// found on a previous horizontal scan. If so, we consider it confirmed and conclude we have + /// found the alignment pattern.

+ /// + ///
+ /// reading state module counts from horizontal scan + /// + /// row where alignment pattern may be found + /// + /// end of possible alignment pattern in row + /// + /// {@link TAlignmentPattern} if we have found the same pattern twice, or null if not + /// + function handlePossibleCenter(const stateCount: TArray; + const i, j: Integer): IAlignmentPattern; + public + ///

Creates a finder that will look in a portion of the whole image.

+ /// + ///
+ /// image to search + /// + /// left column from which to start searching + /// + /// top row from which to start searching + /// + /// width of region to search + /// + /// height of region to search + /// + /// estimated module size so far + /// + constructor Create(const image: TBitMatrix; const startX, startY, + width, height: Integer; const moduleSize: Single; + resultPointCallback: TResultPointCallback); + destructor Destroy; override; + + ///

This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since + /// it's pretty performance-critical and so is written to be fast foremost.

+ /// + ///
+ /// {@link TAlignmentPattern} if found + /// + function find: IAlignmentPattern; + end; + +implementation + +{ TAlignmentPatternFinder } + +constructor TAlignmentPatternFinder.Create(const image: TBitMatrix; + const startX, startY, width, height: Integer; const moduleSize: Single; + resultPointCallback: TResultPointCallback); +begin + Self.image := image; + Self.possibleCenters := TList.Create; + Self.possibleCenters.Capacity := 5; + Self.startX := startX; + Self.startY := startY; + Self.width := width; + Self.height := height; + Self.moduleSize := moduleSize; + Self.crossCheckStateCount := TArray.Create(0, 0, 0); + Self.resultPointCallback := resultPointCallback; +end; + +destructor TAlignmentPatternFinder.Destroy; +begin + if possibleCenters<>nil then + possibleCenters.Clear; + FreeAndNil(self.possibleCenters); + self.crossCheckStateCount := nil; + self.resultPointCallback :=nil; + inherited; +end; + +function TAlignmentPatternFinder.find: IAlignmentPattern; +var + confirmed: IAlignmentPattern; + maxJ, middleI, iGen, i, j, currentState: Integer; + stateCount: TArray; +begin + startX := Self.startX; + height := Self.height; + maxJ := startX + self.width; + middleI := Self.startY + (TMathUtils.Asr(height, 1)); + // We are looking for black/white/black modules in 1:1:1 ratio; + // this tracks the number of black/white/black modules seen so far + stateCount := TArray.Create(0, 0, 0); + for iGen := 0 to Pred(height) do + begin + // Search from middle outwards + if ((iGen and 1) = 0) + then + i := middleI + (TMathUtils.Asr(iGen + 1, 1)) + else + i := middleI + (-1 * TMathUtils.Asr(iGen + 1, 1)); + + stateCount[0] := 0; + stateCount[1] := 0; + stateCount[2] := 0; + j := startX; + // Burn off leading white pixels before anything else; if we start in the middle of + // a white run, it doesn't make sense to count its length, since we don't know if the + // white run continued to the left of the start point + while ((j < maxJ) and (not Self.image[j, i])) do + Inc(j); + + currentState := 0; + while ((j < maxJ)) do + begin + if (Self.image[j, i]) then + begin + // Black pixel + if (currentState = 1) then + begin + // Counting black pixels + Inc(stateCount[currentState]); + end else + begin + // Counting white pixels + if (currentState = 2) then + begin + // A winner? + if (Self.foundPatternCross(stateCount)) then + begin + // Yes + confirmed := self.handlePossibleCenter(stateCount, i, j); + if (confirmed <> nil) then + begin + result := confirmed; + exit + end; + end; + stateCount[0] := stateCount[2]; + stateCount[1] := 1; + stateCount[2] := 0; + currentState := 1; + end else + begin + Inc(currentState); + Inc(stateCount[currentState]); + end; + end; + end else + begin + // White pixel + if (currentState = 1) + then + // Counting black pixels + Inc(currentState); + Inc(stateCount[currentState]) + end; + Inc(j) + end; + + if (Self.foundPatternCross(stateCount)) then + begin + confirmed := self.handlePossibleCenter(stateCount, i, maxJ); + if (confirmed <> nil) then + begin + result := confirmed; + exit; + end; + end; + end; + + // Hmm, nothing we saw was observed and confirmed twice. If we had + // any guess at all, return it. + if (Self.possibleCenters.Count <> 0) + then + Result := Self.possibleCenters[0] + else + Result := nil; +end; + +class function TAlignmentPatternFinder.centerFromEnd( + const stateCount: TArray; const pEnd: Integer): Single; +begin + Result := (pEnd - stateCount[2]) - (stateCount[1] / 2.0); + if (Single.IsNaN(Result)) + then + Result := -1; +end; + +function TAlignmentPatternFinder.foundPatternCross( + const stateCount: TArray): Boolean; +var + maxVariance: Single; + i: Integer; +begin + maxVariance := moduleSize / 2; + for i := 0 to Pred(3) do + begin + if (Abs(self.moduleSize - stateCount[i]) >= maxVariance) then + begin + Result := false; + exit; + end; + end; + Result := true; +end; + +function TAlignmentPatternFinder.crossCheckVertical(const startI, centerJ, + maxCount, originalStateCountTotal: Integer): Single; +var + maxI, + i, stateCountTotal: Integer; + stateCount: TArray; +begin + maxI := Self.image.height; + stateCount := Self.crossCheckStateCount; + stateCount[0] := 0; + stateCount[1] := 0; + stateCount[2] := 0; + + // Start counting up from center + i := startI; + while (((i >= 0) and self.image[centerJ, i]) and + (stateCount[1] <= maxCount)) do + begin + Inc(stateCount[1]); + Dec(i); + end; + // If already too many modules in this state or ran off the edge: + if ((i < 0) or (stateCount[1] > maxCount)) then + begin + Result := -1; + exit; + end; + while (((i >= 0) and (not Self.image[centerJ, i])) and + (stateCount[0] <= maxCount)) do + begin + Inc(stateCount[0]); + Dec(i); + end; + if (stateCount[0] > maxCount) then + begin + Result := -1; + exit; + end; + + // Now also count down from center + i := (startI + 1); + while (((i < maxI) and Self.image[centerJ, i]) and + (stateCount[1] <= maxCount)) do + begin + Inc(stateCount[1]); + Inc(i); + end; + if ((i = maxI) or (stateCount[1] > maxCount)) then + begin + Result := -1; + exit; + end; + while (((i < maxI) and not self.image[centerJ, i]) and + (stateCount[2] <= maxCount)) do + begin + Inc(stateCount[2]); + Inc(i); + end; + if (stateCount[2] > maxCount) then + begin + Result := -1; + exit; + end; + + stateCountTotal := (stateCount[0] + stateCount[1] + stateCount[2]); + if ((5 * Abs(stateCountTotal - originalStateCountTotal)) >= + (2 * originalStateCountTotal)) then + begin + Result := -1; + exit; + end; + + if Self.foundPatternCross(stateCount) + then + Result := TAlignmentPatternFinder.centerFromEnd(stateCount, i) + else + Result := -1; +end; + +function TAlignmentPatternFinder.handlePossibleCenter( + const stateCount: TArray; const i, j: Integer): IAlignmentPattern; +var + center, point: IAlignmentPattern; + stateCountTotal: Integer; + estimatedModuleSize: Single; + centerJ, centerI: Single; +begin + stateCountTotal := (stateCount[0] + stateCount[1] + stateCount[2]); + centerJ := TAlignmentPatternFinder.centerFromEnd(stateCount, j); + if (centerJ = -1) then + begin + Result := nil; + exit; + end; + centerI := crossCheckVertical(i, Floor(centerJ), (2 * stateCount[1]), + stateCountTotal); + if (centerI <> -1) then + begin + estimatedModuleSize := (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0; + for center in Self.possibleCenters do + begin + // Look for about the same center and module size: + if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) then + begin + Result := center.combineEstimate(centerI, centerJ, estimatedModuleSize); + exit; + end; + end; + // Hadn't found this before; save it + point := TAlignmentPatternHelpers.CreateAlignmentPattern(centerJ, centerI, estimatedModuleSize); + Self.possibleCenters.Add(point); + if Assigned(resultPointCallback) + then + Self.resultPointCallback(point); + end; + Result := nil; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPatternImplementation.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPatternImplementation.pas new file mode 100644 index 0000000..5d30606 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.AlignmentPatternImplementation.pas @@ -0,0 +1,112 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E.Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.AlignmentPatternImplementation; + + +interface + +uses + ZXing.QrCode.Internal.AlignmentPattern, + ZXing.ResultPoint, + ZXing.ResultPointImplementation; + +// this is the function that actually creates IAlignmentPattern instances. +// the actual implementation of the interface is totally hidden to all other units, +// since even its declaration is in the implementation section of this unit +function NewAlignmentPattern(const posX, posY, estimatedModuleSize: Single):IAlignmentPattern; + + +implementation + +{ TAlignmentPattern } + + +type + ///

Encapsulates an alignment pattern, which are the smaller square patterns found in + /// all but the simplest QR Codes.

+ /// + ///
+ TAlignmentPattern = class sealed(TResultPoint,IResultPoint,IAlignmentPattern) + private + estimatedModuleSize: Single; + constructor Create(const posX, posY, estimatedModuleSize: Single); + + ///

Determines if this alignment pattern "about equals" an alignment pattern at the stated + /// position and size -- meaning, it is at nearly the same center with nearly the same size.

+ ///
+ function aboutEquals(const moduleSize, i, j: Single): Boolean; + + /// + /// Combines this object's current estimate of a finder pattern position and module size + /// with a new estimate. It returns a new {@code FinderPattern} containing an average of the two. + /// + /// The i. + /// The j. + /// New size of the module. + /// + function combineEstimate(const i, j, + newModuleSize: Single): IAlignmentPattern; + end; + + +constructor TAlignmentPattern.Create(const posX, posY, + estimatedModuleSize: Single); +begin + inherited Create(posX, posY); + + Self.estimatedModuleSize := estimatedModuleSize; +end; + +function TAlignmentPattern.aboutEquals(const moduleSize, i, j: Single): Boolean; +var + moduleSizeDiff: Single; +begin + if ((Abs(i - Self.y) <= moduleSize) and + (Abs(j - Self.x) <= moduleSize)) then + begin + moduleSizeDiff := Abs(moduleSize - self.estimatedModuleSize); + Result := ((moduleSizeDiff <= 1) or + (moduleSizeDiff <= self.estimatedModuleSize)); + end else Result := false; +end; + +function TAlignmentPattern.combineEstimate(const i, j, + newModuleSize: Single): IAlignmentPattern; +var + combinedX, + combinedY, + combinedModuleSize : Single; +begin + combinedX := (self.x + j) / 2.0; + combinedY := (self.y + i) / 2.0; + combinedModuleSize := (estimatedModuleSize + newModuleSize) / 2.0; + Result := TAlignmentPattern.Create(combinedX, combinedY, combinedModuleSize); +end; + + + + +function NewAlignmentPattern(const posX, posY, estimatedModuleSize: Single):IAlignmentPattern; +begin + result := TAlignmentPattern.Create(posX,posY,estimatedModuleSize); +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.Detector.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.Detector.pas new file mode 100644 index 0000000..c4f99e6 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.Detector.pas @@ -0,0 +1,492 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.Detector; + +interface + +uses + System.SysUtils, + System.Math, + Generics.Collections, + ZXing.Common.BitMatrix, + ZXing.ResultPoint, + ZXing.Common.DetectorResult, + ZXing.DecodeHintType, + ZXing.Common.PerspectiveTransform, + ZXing.QrCode.Internal.FinderPatternInfo, + ZXing.QrCode.Internal.FinderPatternFinder, + ZXing.QrCode.Internal.FinderPattern, + ZXing.QrCode.Internal.AlignmentPattern, + ZXing.QrCode.Internal.AlignmentPatternFinder, + ZXing.QrCode.Internal.Version, + ZXing.DefaultGridSampler, + ZXing.Common.Detector.MathUtils; + +type + /// + ///

Encapsulates logic that can detect a QR Code in an image, even if the QR Code + /// is rotated or skewed, or partially obscured.

+ ///
+ TDetector = class + private + FImage: TBitMatrix; + FResultPointCallback: TResultPointCallback; + + function calculateModuleSizeOneWay(pattern: IResultpoint; + otherPattern: IResultpoint): Single; + + class function computeDimension(topLeft: IResultpoint; + topRight: IResultpoint; bottomLeft: IResultpoint; moduleSize: Single; + var dimension: Integer): boolean; static; + + class function createTransform(const topLeft, topRight, bottomLeft, + AlignmentPattern: IResultpoint; const dimension: Integer) + : TPerspectiveTransform; static; + + class function sampleGrid(image: TBitMatrix; + transform: TPerspectiveTransform; dimension: Integer): TBitMatrix; static; + function sizeOfBlackWhiteBlackRun(fromX: Integer; fromY: Integer; + toX: Integer; toY: Integer): Single; + function sizeOfBlackWhiteBlackRunBothWays(fromX: Integer; fromY: Integer; + toX: Integer; toY: Integer): Single; + protected + function calculateModuleSize(const topLeft, topRight, + bottomLeft: IResultPoint): Single; virtual; + + function findAlignmentInRegion(const overallEstModuleSize: Single; + const estAlignmentX, estAlignmentY: Integer; + const allowanceFactor: Single): IAlignmentPattern; + + /// + /// Processes the finder pattern info. + /// + /// The info. + /// + function processFinderPatternInfo(const info: TFinderPatternInfo) + : TDetectorResult; virtual; + public + /// + /// Initializes a new instance of the class. + /// + /// The image. + constructor Create(const image: TBitMatrix); + destructor Destroy; override; + + /// + ///

Detects a QR Code in an image.

+ ///
+ /// + /// encapsulating results of detecting a QR Code + /// + function detect(): TDetectorResult; overload; + + /// + ///

Detects a QR Code in an image.

+ ///
+ /// optional hints to detector + /// + /// encapsulating results of detecting a QR Code + /// + function detect(const hints: TDictionary) + : TDetectorResult; overload; + + property image: TBitMatrix read FImage; + property ResultPointCallback: TResultPointCallback + read FResultPointCallback; + end; + +implementation + +{ TDetector } + +constructor TDetector.Create(const image: TBitMatrix); +begin + FImage := image; +end; + +destructor TDetector.Destroy; +begin + FResultPointCallback := nil; + inherited; +end; + +function TDetector.calculateModuleSize(const topLeft, topRight, + bottomLeft: IResultPoint): Single; +begin + Result := ((self.calculateModuleSizeOneWay(topLeft, topRight) + + self.calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2) +end; + +function TDetector.calculateModuleSizeOneWay(pattern: IResultPoint; + otherPattern: IResultPoint): Single; +var + moduleSizeEst1, moduleSizeEst2: Single; + +begin + moduleSizeEst1 := self.sizeOfBlackWhiteBlackRunBothWays(Floor(pattern.X), + Floor(pattern.Y), Floor(otherPattern.X), Floor(otherPattern.Y)); + moduleSizeEst2 := self.sizeOfBlackWhiteBlackRunBothWays(Floor(otherPattern.X), + Floor(otherPattern.Y), Floor(pattern.X), Floor(pattern.Y)); + + if (moduleSizeEst1 = -1) then + begin + Result := (moduleSizeEst2 / 7); + exit + end; + + if (moduleSizeEst2 = -1) then + begin + Result := (moduleSizeEst1 / 7); + exit + end; + + Result := ((moduleSizeEst1 + moduleSizeEst2) / 14); +end; + +class function TDetector.computeDimension(topLeft: IResultPoint; + topRight: IResultPoint; bottomLeft: IResultPoint; moduleSize: Single; + var dimension: Integer): boolean; + +var + tltrCentersDimension, tlblCentersDimension: Integer; +begin + tltrCentersDimension := + round((TResultPointHelpers.distance(topLeft, topRight) / moduleSize)); + tlblCentersDimension := + round((TResultPointHelpers.distance(topLeft, bottomLeft) / moduleSize)); + dimension := TMathUtils.Asr + ((tltrCentersDimension + tlblCentersDimension), 1) + 7; + + case (dimension and 3) of + 0: inc(dimension); // below a valid dimension + 1: ; // exactly on a valid dimension e.g. 21, 25, 29, ..., 177 + 2: dec(dimension); // above a valid dimension + 3: Exit(False); // exactly between two valid dimensions + end; + + Result := True; +end; + +class function TDetector.createTransform(const topLeft, topRight, bottomLeft, + AlignmentPattern: IResultPoint; const dimension: Integer) + : TPerspectiveTransform; +var + bottomRightX, bottomRightY, sourceBottomRightX, sourceBottomRightY, + dimMinusThree: Single; +begin + dimMinusThree := (dimension - 3.5); + if (AlignmentPattern <> nil) then + begin + bottomRightX := AlignmentPattern.X; + bottomRightY := AlignmentPattern.Y; + sourceBottomRightX := (dimMinusThree - 3); + sourceBottomRightY := sourceBottomRightX; + end + else + begin + bottomRightX := ((topRight.X - topLeft.X) + bottomLeft.X); + bottomRightY := ((topRight.Y - topLeft.Y) + bottomLeft.Y); + sourceBottomRightX := dimMinusThree; + sourceBottomRightY := sourceBottomRightX; + end; + + Result := TPerspectiveTransform.quadrilateralToQuadrilateral(3.5, 3.5, + dimMinusThree, 3.5, sourceBottomRightX, sourceBottomRightY, 3.5, + dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, + bottomRightY, bottomLeft.X, bottomLeft.Y); +end; + +function TDetector.detect: TDetectorResult; +begin + Result := self.detect(nil) +end; + +function TDetector.detect(const hints: TDictionary) + : TDetectorResult; +var + obj: TObject; + info: TFinderPatternInfo; + finder: TFinderPatternFinder; +begin + Result := nil; + + if ((hints = nil) or + (not hints.ContainsKey(TDecodeHintType.NEED_RESULT_POINT_CALLBACK))) then + FResultPointCallback := nil + else + begin + obj := hints[TDecodeHintType.NEED_RESULT_POINT_CALLBACK]; + if (obj is TResultPointEventObject) then + FResultPointCallback := TResultPointEventObject(obj).Event; + end; + + finder := TFinderPatternFinder.Create(FImage, ResultPointCallback); + try + info := finder.find(hints); + if Assigned(info) then + begin + Result := processFinderPatternInfo(info); + info.Free; + end; + finally + finder.Free; + end; +end; + +function TDetector.processFinderPatternInfo(const info: TFinderPatternInfo) + : TDetectorResult; +var + topLeft, topRight, bottomLeft: IFinderPattern; + moduleSize, bottomRightX, bottomRightY, correctionToTopLeft: Single; + dimension, i, modulesBetweenFPCenters, estAlignmentX, estAlignmentY: Integer; + points: TArray; + provisionalVersion: TVersion; + transform: TPerspectiveTransform; + bits: TBitMatrix; + AlignmentPattern: IAlignmentPattern; +begin + Result := nil; + + topLeft := info.topLeft; + topRight := info.topRight; + bottomLeft := info.bottomLeft; + + moduleSize := calculateModuleSize(topLeft, topRight, bottomLeft); + if (moduleSize < 1.0) then + exit; + + if (not TDetector.computeDimension(topLeft, topRight, bottomLeft, moduleSize, + dimension)) then + exit; + + provisionalVersion := TVersion.getProvisionalVersionForDimension(dimension); + if (provisionalVersion = nil) then + exit; + + modulesBetweenFPCenters := (provisionalVersion.DimensionForVersion - 7); + + AlignmentPattern := nil; + // Anything above version 1 has an alignment pattern + if (Length(provisionalVersion.AlignmentPatternCenters) > 0) then + begin + // Guess where a "bottom right" finder pattern would have been + bottomRightX := (topRight.X - topLeft.X) + bottomLeft.X; + bottomRightY := (topRight.Y - topLeft.Y) + bottomLeft.Y; + + // Estimate that alignment pattern is closer by 3 modules + // from "bottom right" to known top left location + correctionToTopLeft := (1.0 - (3.0 / modulesBetweenFPCenters)); + estAlignmentX := + Floor(topLeft.X + (correctionToTopLeft * (bottomRightX - topLeft.X))); + estAlignmentY := + Floor(topLeft.Y + (correctionToTopLeft * (bottomRightY - topLeft.Y))); + i := 4; + while ((i <= 16)) do + begin + AlignmentPattern := findAlignmentInRegion(moduleSize, estAlignmentX, + estAlignmentY, i); + if (AlignmentPattern <> nil) then + break; + i := (i shl 1); + end; + // If we didn't find alignment pattern... well try anyway without it + end; + + transform := TDetector.createTransform(topLeft, topRight, bottomLeft, + AlignmentPattern, dimension); + try + bits := TDetector.sampleGrid(FImage, transform, dimension); + finally + transform.Free; + end; + + if (bits = nil) then + exit; + + if (AlignmentPattern = nil) then + points := TArray.Create(bottomLeft, topLeft, topRight) + else + points := TArray.Create(bottomLeft, topLeft, topRight, + AlignmentPattern); + + Result := TDetectorResult.Create(bits, points); +end; + +function TDetector.findAlignmentInRegion(const overallEstModuleSize: Single; + const estAlignmentX, estAlignmentY: Integer; const allowanceFactor: Single) + : IAlignmentPattern; +var + allowance, alignmentAreaRightX, alignmentAreaLeftX, alignmentAreaTopY, + alignmentAreaBottomY: Integer; + alignmentFinder: TAlignmentPatternFinder; + candidateResult: IAlignmentPattern; +begin + Result := nil; + + allowance := Floor(allowanceFactor * overallEstModuleSize); + alignmentAreaLeftX := System.Math.Max(0, (estAlignmentX - allowance)); + alignmentAreaRightX := System.Math.Min((FImage.Width - 1), + (estAlignmentX + allowance)); + + if ((alignmentAreaRightX - alignmentAreaLeftX) < (overallEstModuleSize * 3)) + then + exit; + + alignmentAreaTopY := System.Math.Max(0, (estAlignmentY - allowance)); + + alignmentAreaBottomY := System.Math.Min((FImage.Height - 1), + (estAlignmentY + allowance)); + + alignmentFinder := TAlignmentPatternFinder.Create(FImage, alignmentAreaLeftX, + alignmentAreaTopY, (alignmentAreaRightX - alignmentAreaLeftX), + (alignmentAreaBottomY - alignmentAreaTopY), overallEstModuleSize, + self.ResultPointCallback); + + candidateResult := alignmentFinder.find; + + if candidateResult = nil then + Result := nil + else + Result := candidateResult; + + FreeAndNil(alignmentFinder); +end; + +class function TDetector.sampleGrid(image: TBitMatrix; + transform: TPerspectiveTransform; dimension: Integer): TBitMatrix; +begin + Result := TDefaultGridSampler.sampleGrid(image, dimension, dimension, + transform) +end; + +function TDetector.sizeOfBlackWhiteBlackRun(fromX: Integer; fromY: Integer; + toX: Integer; toY: Integer): Single; +var + steep: boolean; + temp, dx, dy, xstep, ystep, X, Y, state, xlimit, realx, realy, error: Integer; +begin + 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 (fromX < toX) then + xstep := 1 + else + xstep := -1; + + if (fromY < toY) then + ystep := 1 + else + ystep := -1; + + state := 0; + xlimit := (toX + xstep); + X := fromX; + Y := fromY; + while ((X <> xlimit)) do + begin + if steep then + realx := Y + else + realx := X; + if steep then + realy := X + else + realy := Y; + + if ((state = 1) = FImage[realx, realy]) then + begin + if (state = 2) then + begin + Result := TMathUtils.distance(X, Y, fromX, fromY); + exit + end; + inc(state) + 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; + + if (state = 2) then + begin + Result := TMathUtils.distance((toX + xstep), toY, fromX, fromY); + exit + end; + + Result := Single.NaN; +end; + +function TDetector.sizeOfBlackWhiteBlackRunBothWays(fromX: Integer; + fromY: Integer; toX: Integer; toY: Integer): Single; +var + scale: Double; + otherToX, otherToY: Integer; +begin + Result := sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); + scale := 1; + otherToX := (fromX - (toX - fromX)); + if (otherToX < 0) then + begin + scale := (fromX / (fromX - otherToX)); + otherToX := 0 + end + else if (otherToX >= FImage.Width) then + begin + scale := (((FImage.Width - 1) - fromX) / (otherToX - fromX)); + otherToX := (FImage.Width - 1) + end; + otherToY := Round(fromY - ((toY - fromY) * scale)); + scale := 1; + if (otherToY < 0) then + begin + scale := fromY / (fromY - otherToY); + otherToY := 0 + end + else if (otherToY >= FImage.Height) then + begin + scale := (((FImage.Height - 1) - fromY) / (otherToY - fromY)); + otherToY := (FImage.Height - 1) + end; + otherToX := Round(fromX + (otherToX - fromX) * scale); + Result := Result + self.sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, + otherToY); + + Result := (Result - 1); +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPattern.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPattern.pas new file mode 100644 index 0000000..6210c13 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPattern.pas @@ -0,0 +1,147 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.FinderPattern; + +interface + +uses + ZXing.ResultPoint; + +type + + /// + /// As we did for ResultPoint, we use an interfaced object to implement automatic deallocation + /// of TAligmnentPattern instances + /// the actual implementation of this interface is in unit ZXing.QrCode.Internal.FinderPatternImplementation + /// + IFinderPattern = interface(IResultPoint) + ['{EF95BB2F-8863-4A83-840E-699779592EC0}'] + function GetCount:integer; + procedure SetCount(value:integer); + ///

Determines if this finder pattern "about equals" a finder pattern at the stated + /// position and size -- meaning, it is at nearly the same center with nearly the same size.

+ ///
+ function aboutEquals(const moduleSize, i, j: Single): Boolean; + + /// + /// Combines this object's current estimate of a finder pattern position and module size + /// with a new estimate. It returns a new {@code FinderPattern} containing a weighted average + /// based on count. + /// + /// The i. + /// The j. + /// New size of the module. + /// + function combineEstimate(const i, j, newModuleSize: Single): IFinderPattern; + + /// + /// Gets the size of the estimated module. + /// + /// + /// The size of the estimated module. + /// + function estimatedModuleSize : Single; + property count : Integer read GetCount write SetCount; + end; + + + /// + /// contains all static methods for using IFinderPattern instances + /// + TFinderPatternHelpers= class(TResultPointHelpers) + class function CreateFinderPattern(const posX, posY, estimatedModuleSize: Single; + const count: Integer):IFinderPattern; overload; + class function CreateFinderPattern(const posX, posY, estimatedModuleSize: Single):IFinderPattern; overload; + + class procedure orderBestPatterns(const patterns: TArray); static; + + end; + +implementation +uses ZXing.QrCode.Internal.FinderPatternImplementation; + +class function TFinderPatternHelpers.CreateFinderPattern(const posX, posY, estimatedModuleSize: Single; const count: Integer):IFinderPattern; +begin + result := ZXing.QrCode.Internal.FinderPatternImplementation.NewFinderPattern(posX, posY, estimatedModuleSize ,count); +end; + +class function TFinderPatternHelpers.CreateFinderPattern(const posX, posY, estimatedModuleSize: Single):IFinderPattern; +begin + result := ZXing.QrCode.Internal.FinderPatternImplementation.NewFinderPattern(posX, posY, estimatedModuleSize); +end; + + + +class procedure TFinderPatternHelpers.orderBestPatterns( const patterns: TArray); +var + zeroOneDistance, + oneTwoDistance, + zeroTwoDistance: Single; + pointA, + pointB, + pointC, + temp: IFinderPattern; +begin + // Find distances between pattern centers + zeroOneDistance := distance(patterns[0], patterns[1]); + oneTwoDistance := distance(patterns[1], patterns[2]); + zeroTwoDistance := distance(patterns[0], patterns[2]); + + // Assume one closest to other two is B; A and C will just be guesses at first + if ((oneTwoDistance >= zeroOneDistance) and + (oneTwoDistance >= zeroTwoDistance)) then + begin + pointB := patterns[0]; + pointA := patterns[1]; + pointC := patterns[2]; + end + else if ((zeroTwoDistance >= oneTwoDistance) and + (zeroTwoDistance >= zeroOneDistance)) then + begin + pointB := patterns[1]; + pointA := patterns[0]; + pointC := patterns[2]; + end + else + begin + pointB := patterns[2]; + pointA := patterns[0]; + pointC := patterns[1]; + end; + + // Use cross product to figure out whether A and C are correct or flipped. + // This asks whether BC x BA has a positive z component, which is the arrangement + // we want for A, B, C. If it's negative, then we've got it flipped around and + // should swap A and C. + if (TResultPointHelpers.crossProductZ(pointA, pointB, pointC) < 0) then + begin + temp := pointA; + pointA := pointC; + pointC := temp; + end; + + patterns[0] := pointA; + patterns[1] := pointB; + patterns[2] := pointC; +end; + + + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternFinder.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternFinder.pas new file mode 100644 index 0000000..4c95f81 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternFinder.pas @@ -0,0 +1,977 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.FinderPatternFinder; + +interface + +uses + System.SysUtils, + System.Math, + System.Generics.Defaults, + System.Generics.Collections, + ZXing.Common.BitMatrix, + ZXing.ResultPoint, + ZXing.DecodeHinttype, + ZXing.QrCode.Internal.FinderPatternInfo, + ZXing.QrCode.Internal.FinderPattern; + +type + /// + ///

This class attempts to find finder patterns in a QR Code. Finder patterns are the square + /// markers at three corners of a QR Code.

+ /// + ///

This class is thread-safe but not reentrant. Each thread must allocate its own object. + ///

+ TFinderPatternFinder = class + private + const + CENTER_QUORUM: Integer = 2; + INTEGER_MATH_SHIFT: Integer = 8; + var + FImage: TBitMatrix; + FPossibleCenters: TList; + FhasSkipped: Boolean; + FCrossCheckStateCount: TArray; + FresultPointCallback: TResultPointCallback; + + class function centerFromEnd(stateCount: TArray; pEnd: Integer): Single; static; + + function crossCheckDiagonal(startI: Integer; centerJ: Integer; maxCount: Integer; originalStateCountTotal: Integer): boolean; + function crossCheckHorizontal(startJ: Integer; centerI: Integer; maxCount: Integer; originalStateCountTotal: Integer): Single; + function crossCheckVertical(startI: Integer; centerJ: Integer; maxCount: Integer; originalStateCountTotal: Integer): Single; + function findRowSkip: Integer; + function haveMultiplyConfirmedCenters: boolean; + function selectBestPatterns: TArray; + + function CrossCheckStateCount: TArray; + protected + const + /// + /// 1 pixel/module times 3 modules/center + /// + MIN_SKIP: Integer = 3; + /// + /// support up to version 10 for mobile clients + /// + MAX_MODULES: Integer = 97; + class function foundPatternCross(const stateCount: TArray): Boolean; static; + function handlePossibleCenter(stateCount: TArray; i: Integer; + j: Integer): boolean; + property image: TBitMatrix read FImage; + public + /// + ///

Creates a finder that will search the image for three finder patterns.

+ ///
+ /// image to search + constructor Create(const image: TBitMatrix); overload; + + /// + /// Initializes a new instance of the class. + /// + /// The image. + /// The result point callback. + constructor Create(const image: TBitMatrix; + resultPointCallback: TResultPointCallback); overload; + + destructor Destroy; override; + + function find(const hints: TDictionary): TFinderPatternInfo; virtual; + end; + + TFurthestFromAverageComparator = class sealed(TInterfacedObject, + IComparer) + private + average: Single; + public + constructor Create(f: Single); + function Compare(const Left, Right: IFinderPattern): Integer; + end; + + TCenterComparator = class sealed(TInterfacedObject, IComparer) + private + average: Single; + public + constructor Create(f: Single); + function Compare(const Left, Right: IFinderPattern): Integer; + end; + +implementation + +{ TFinderPatternFinder } + +constructor TFinderPatternFinder.Create(const image: TBitMatrix); +begin + Self.Create(image, TResultPointCallback(nil)); +end; + +constructor TFinderPatternFinder.Create(const image: TBitMatrix; + resultPointCallback: TResultPointCallback); +begin + FImage := image; + FPossibleCenters := TList.Create; + FCrossCheckStateCount := TArray.Create(0, 0, 0, 0, 0); + FresultPointCallback := resultPointCallback; +end; + +destructor TFinderPatternFinder.Destroy; +begin + FImage := nil; + + {for i := Pred(PossibleCenters.Count) downto 0 do + begin + PossibleCenters[i].Free; + PossibleCenters.Delete(i); + end;} + + FPossibleCenters.Free; + FCrossCheckStateCount := nil; + + inherited; +end; + +class function TFinderPatternFinder.centerFromEnd(stateCount: TArray; + pEnd: Integer): Single; +var + aResult: Single; +begin + aResult := (pEnd - stateCount[4] - stateCount[3]) - (stateCount[2] / 2); + + if (Single.IsNaN(aResult)) then + begin + result := -1; + exit + end; + + result := aResult; +end; + +function TFinderPatternFinder.crossCheckDiagonal(startI, centerJ, maxCount, + originalStateCountTotal: Integer): boolean; +var + stateCount: TArray; + i, maxI, maxJ, stateCountTotal: Integer; +begin + stateCount := CrossCheckStateCount; + try + i := 0; + while ((((startI >= i) and (centerJ >= i)) and self.image[(centerJ - i), + (startI - i)])) do + begin + inc(stateCount[2]); + inc(i) + end; + if ((startI < i) or (centerJ < i)) then + begin + result := false; + exit + end; + while (((((startI >= i) and (centerJ >= i)) and + not self.image[(centerJ - i), (startI - i)]) and + (stateCount[1] <= maxCount))) do + begin + inc(stateCount[1]); + inc(i) + end; + if (((startI < i) or (centerJ < i)) or (stateCount[1] > maxCount)) then + begin + result := false; + exit + end; + while (((((startI >= i) and (centerJ >= i)) and self.image[(centerJ - i), + (startI - i)]) and (stateCount[0] <= maxCount))) do + begin + inc(stateCount[0]); + inc(i) + end; + if (stateCount[0] > maxCount) then + begin + result := false; + exit + end; + maxI := self.image.Height; + maxJ := self.image.Width; + i := 1; + while (((((startI + i) < maxI) and ((centerJ + i) < maxJ)) and + self.image[(centerJ + i), (startI + i)])) do + begin + inc(stateCount[2]); + inc(i) + end; + if (((startI + i) >= maxI) or ((centerJ + i) >= maxJ)) then + begin + result := false; + exit + end; + while ((((((startI + i) < maxI) and ((centerJ + i) < maxJ)) and + not self.image[(centerJ + i), (startI + i)]) and + (stateCount[3] < maxCount))) do + begin + inc(stateCount[3]); + inc(i) + end; + if ((((startI + i) >= maxI) or ((centerJ + i) >= maxJ)) or + (stateCount[3] >= maxCount)) then + begin + result := false; + exit + end; + while ((((((startI + i) < maxI) and ((centerJ + i) < maxJ)) and + self.image[(centerJ + i), (startI + i)]) and + (stateCount[4] < maxCount))) do + begin + inc(stateCount[4]); + inc(i) + end; + if (stateCount[4] >= maxCount) then + begin + result := false; + exit + end; + + stateCountTotal := + ((((stateCount[0] + stateCount[1]) + stateCount[2]) + stateCount[3]) + + stateCount[4]); + + Result := (Abs(stateCountTotal - originalStateCountTotal) < + (2 * originalStateCountTotal)) and TFinderPatternFinder.foundPatternCross + (stateCount); + + finally + stateCount := nil; + end; +end; + +function TFinderPatternFinder.crossCheckHorizontal(startJ: Integer; + centerI: Integer; maxCount: Integer; + originalStateCountTotal: Integer): Single; +var + stateCount: TArray; + maxJ, j, stateCountTotal: Integer; + +begin + maxJ := FImage.Width; + stateCount := CrossCheckStateCount; + + try + + j := startJ; + while (((j >= 0) and FImage[j, centerI])) do + begin + inc(stateCount[2]); + dec(j) + end; + + if (j < 0) then + begin + result := -1; + exit + end; + + while ((((j >= 0) and not FImage[j, centerI]) and + (stateCount[1] <= maxCount))) do + begin + inc(stateCount[1]); + dec(j) + end; + + if ((j < 0) or (stateCount[1] > maxCount)) then + begin + result := -1; + exit + end; + + while ((((j >= 0) and FImage[j, centerI]) and + (stateCount[0] <= maxCount))) do + begin + inc(stateCount[0]); + dec(j) + end; + + if (stateCount[0] > maxCount) then + begin + result := -1; + exit + end; + j := (startJ + 1); + + while (((j < maxJ) and FImage[j, centerI])) do + begin + inc(stateCount[2]); + inc(j) + end; + + if (j = maxJ) then + begin + result := -1; + exit + end; + + while ((((j < maxJ) and not FImage[j, centerI]) and + (stateCount[3] < maxCount))) do + begin + inc(stateCount[3]); + inc(j) + end; + + if ((j = maxJ) or (stateCount[3] >= maxCount)) then + begin + result := -1; + exit + end; + + while (((j < maxJ) and FImage[j, centerI]) and + (stateCount[4] < maxCount)) do + begin + inc(stateCount[4]); + inc(j) + end; + + if (stateCount[4] >= maxCount) then + begin + result := -1; + exit + end; + + stateCountTotal := + ((((stateCount[0] + stateCount[1]) + stateCount[2]) + stateCount[3]) + + stateCount[4]); + + if (5 * Abs(stateCountTotal - originalStateCountTotal) >= + originalStateCountTotal) then + begin + result := -1; + exit + end; + + if TFinderPatternFinder.foundPatternCross(stateCount) then + begin + result := TFinderPatternFinder.centerFromEnd(stateCount, j); + exit; + end; + + finally + stateCount := nil; + end; + + result := -1; + +end; + +function TFinderPatternFinder.CrossCheckStateCount: TArray; +begin + FCrossCheckStateCount[0] := 0; + FCrossCheckStateCount[1] := 0; + FCrossCheckStateCount[2] := 0; + FCrossCheckStateCount[3] := 0; + FCrossCheckStateCount[4] := 0; + result := FCrossCheckStateCount; +end; + +function TFinderPatternFinder.crossCheckVertical(startI: Integer; + centerJ: Integer; maxCount: Integer; + originalStateCountTotal: Integer): Single; +var + stateCount: TArray; + maxI, i, stateCountTotal: Integer; +begin + + maxI := FImage.Height; + stateCount := CrossCheckStateCount; + i := startI; + try + while (((i >= 0) and FImage[centerJ, i])) do + begin + inc(stateCount[2]); + dec(i) + end; + + if (i < 0) then + begin + result := -1; + exit + end; + + while ((((i >= 0) and not FImage[centerJ, i]) and + (stateCount[1] <= maxCount))) do + begin + inc(stateCount[1]); + dec(i) + end; + + if ((i < 0) or (stateCount[1] > maxCount)) then + begin + result := -1; + exit + end; + + while ((((i >= 0) and FImage[centerJ, i]) and + (stateCount[0] <= maxCount))) do + begin + inc(stateCount[0]); + dec(i) + end; + + if (stateCount[0] > maxCount) then + begin + result := -1; + exit + end; + i := (startI + 1); + + while (((i < maxI) and FImage[centerJ, i])) do + begin + inc(stateCount[2]); + inc(i) + end; + + if (i = maxI) then + begin + result := -1; + exit + end; + + while ((((i < maxI) and not FImage[centerJ, i]) and + (stateCount[3] < maxCount))) do + begin + inc(stateCount[3]); + inc(i) + end; + + if ((i = maxI) or (stateCount[3] >= maxCount)) then + begin + result := -1; + exit + end; + + while ((((i < maxI) and FImage[centerJ, i]) and + (stateCount[4] < maxCount))) do + begin + inc(stateCount[4]); + inc(i) + end; + + if (stateCount[4] >= maxCount) then + begin + result := -1; + exit + end; + + stateCountTotal := + ((((stateCount[0] + stateCount[1]) + stateCount[2]) + stateCount[3]) + + stateCount[4]); + + if ((5 * Abs(stateCountTotal - originalStateCountTotal)) >= + (2 * originalStateCountTotal)) then + begin + result := -1; + exit + end; + + if TFinderPatternFinder.foundPatternCross(stateCount) then + begin + result := TFinderPatternFinder.centerFromEnd(stateCount, i); + exit; + end; + + finally + stateCount := nil; + end; + + result := -1; + +end; + +function TFinderPatternFinder.find( + const hints: TDictionary): TFinderPatternInfo; +var + tryHarder, + done, confirmed: Boolean; + maxI, maxJ, iSkip, + i, currentState, j, rowSkip: Integer; + stateCount: TArray; + patternInfo: TArray; + resultInfo: TArray; +begin + Result := nil; + + tryHarder := (hints <> nil) and (hints.ContainsKey(ZXing.DecodeHinttype.TRY_HARDER)); + maxI := Self.image.Height; + maxJ := Self.image.Width; + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the + // image, and then account for the center being 3 modules in size. This gives the smallest + // number of pixels the center could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + iSkip := (3 * maxI) div (4 * MAX_MODULES); + if (iSkip < MIN_SKIP) or (tryHarder) + then + iSkip := MIN_SKIP; + + done := false; + stateCount := TArray.Create(0, 0, 0, 0, 0); + try + i := (iSkip - 1); + while ((i < maxI) and (not done)) do + begin + // Get a row of black/white values + stateCount[0] := 0; + stateCount[1] := 0; + stateCount[2] := 0; + stateCount[3] := 0; + stateCount[4] := 0; + currentState := 0; + + j := 0; + while (j < maxJ) do + begin + if (FImage[j, i]) then + begin + // Black pixel + if ((currentState and 1) = 1) + then + Inc(currentState); + Inc(stateCount[currentState]); + end else + begin + // White pixel + if ((currentState and 1) = 0) then + begin + // Counting black pixels + if (currentState = 4) then + begin + // A winner? + if TFinderPatternFinder.foundPatternCross(stateCount) then + begin + // Yes + confirmed := handlePossibleCenter(stateCount, i, j); + if (confirmed) then + begin + // Start examining every other line. Checking each line turned out to be too + // expensive and didn't improve performance. + iSkip := 2; + if (FhasSkipped) + then + done := haveMultiplyConfirmedCenters() + else + begin + rowSkip := findRowSkip(); + if (rowSkip > stateCount[2]) then + begin + // Skip rows between row of lower confirmed center + // and top of presumed third confirmed center + // but back up a bit to get a full chance of detecting + // it, entire width of center of finder pattern + + // Skip by rowSkip, but back off by stateCount[2] (size of last center + // of pattern we saw) to be conservative, and also back off by iSkip which + // is about to be re-added + Inc(i, ((rowSkip - stateCount[2]) - iSkip)); + j := (maxJ - 1); + end; + end; + end else + begin + stateCount[0] := stateCount[2]; + stateCount[1] := stateCount[3]; + stateCount[2] := stateCount[4]; + stateCount[3] := 1; + stateCount[4] := 0; + currentState := 3; + continue; + end; + // Clear state to start looking again + currentState := 0; + stateCount[0] := 0; + stateCount[1] := 0; + stateCount[2] := 0; + stateCount[3] := 0; + stateCount[4] := 0 + end else + begin + // No, shift counts back by two + stateCount[0] := stateCount[2]; + stateCount[1] := stateCount[3]; + stateCount[2] := stateCount[4]; + stateCount[3] := 1; + stateCount[4] := 0; + currentState := 3; + end; + end else + begin + Inc(currentState); + Inc(stateCount[currentState]); + end; + end else + // Counting white pixels + Inc(stateCount[currentState]); + end; + Inc(j); + end; + + if foundPatternCross(stateCount) then + begin + confirmed := Self.handlePossibleCenter(stateCount, i, maxJ); + if (confirmed) then + begin + iSkip := stateCount[0]; + if (FhasSkipped) + then + // Found a third one + done := self.haveMultiplyConfirmedCenters + end; + end; + Inc(i, iSkip); + end; + + patternInfo := selectBestPatterns(); + if (patternInfo = nil) + then + exit; + + TFinderPatternHelpers.orderBestPatterns(patternInfo); + Result := TFinderPatternInfo.Create(patternInfo); + finally + resultInfo := nil; + stateCount := nil; + patternInfo := nil; + end; +end; + +function TFinderPatternFinder.findRowSkip: Integer; +var + center: IFinderPattern; + firstConfirmedCenter: IResultPoint; +begin + Result := 0; + + if (FPossibleCenters.Count > 1) then + begin + firstConfirmedCenter := nil; + + for center in FPossibleCenters do + begin + if (center.Count >= 2) then + begin + if (firstConfirmedCenter <> nil) then + begin + FhasSkipped := true; + Result := Floor(Abs(firstConfirmedCenter.X - center.X) - + Abs(firstConfirmedCenter.Y - center.Y)) div 2; + exit; + end; + firstConfirmedCenter := center; + end + end + end; +end; + +/// count of black/white/black/white/black pixels just read +/// +/// true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios +/// used by finder patterns to be considered a match +/// +class function TFinderPatternFinder.foundPatternCross( + const stateCount: TArray): Boolean; +var + i, totalModuleSize, + count, moduleSize, + maxVariance: Integer; +begin + Result := false; + + totalModuleSize := 0; + for i := 0 to Pred(5) do + begin + count := stateCount[i]; + if (count = 0) + then + exit; + Inc(totalModuleSize, count); + end; + + if (totalModuleSize < 7) + then + exit; + + moduleSize := ((totalModuleSize shl 8) div 7); + maxVariance := (moduleSize div 2); + // Allow less than 50% variance from 1-1-3-1-1 proportions + Result := (Abs(moduleSize - (stateCount[0] shl INTEGER_MATH_SHIFT)) < maxVariance) and + (Abs(moduleSize - (stateCount[1] shl INTEGER_MATH_SHIFT)) < maxVariance) and + (Abs(3 * moduleSize - (stateCount[2] shl INTEGER_MATH_SHIFT)) < (3 * maxVariance)) and + (Abs(moduleSize - (stateCount[3] shl INTEGER_MATH_SHIFT)) < maxVariance) and + (Abs(moduleSize - (stateCount[4] shl INTEGER_MATH_SHIFT)) < maxVariance); +end; + +function TFinderPatternFinder.handlePossibleCenter(stateCount: TArray; + i, j: Integer): boolean; +var + stateCountTotal, index: Integer; + centerJ, centerI: Single; + center, point: IFinderPattern; + found: boolean; + estimatedModuleSize: Single; +begin + Result := false; + + center := nil; + stateCountTotal := ((((stateCount[0] + stateCount[1]) + stateCount[2]) + + stateCount[3]) + stateCount[4]); + + centerJ := TFinderPatternFinder.centerFromEnd(stateCount, j); + + if (centerJ = -1) + then + exit; + + centerI := self.crossCheckVertical(i, Floor(centerJ), stateCount[2], + stateCountTotal); + + if (centerI = -1) + then + exit; + + centerJ := crossCheckHorizontal(Floor(centerJ), Floor(centerI), stateCount[2], + stateCountTotal); + + if ((centerJ <> -1) and (self.crossCheckDiagonal(Floor(centerI), Floor(centerJ), stateCount[2], + stateCountTotal))) then + begin + estimatedModuleSize := stateCountTotal / 7; + found := false; + index := 0; + while ((index < FPossibleCenters.Count)) do + begin + center := FPossibleCenters[index]; + if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) then + begin + FPossibleCenters[index] := nil; + FPossibleCenters.Delete(index); + FPossibleCenters.Insert(index, center.combineEstimate(centerI, centerJ, + estimatedModuleSize)); + found := true; + break; + end; + + inc(index) + end; + + if (not found) then + begin + point := TFinderPatternHelpers.CreateFinderPattern(centerJ, centerI, estimatedModuleSize); + FPossibleCenters.Add(point); + + if Assigned(FresultPointCallback) + then + FresultPointCallBack(point); + end; + Result := true; + end; +end; + +function TFinderPatternFinder.haveMultiplyConfirmedCenters: boolean; +var + confirmedCount, max, i: Integer; + totalModuleSize, average, totalDeviation: Single; + pattern: IFinderPattern; +begin + confirmedCount := 0; + totalModuleSize := 0; + + max := FPossibleCenters.Count; + + for pattern in FPossibleCenters do + begin + if (pattern.Count >= CENTER_QUORUM) then + begin + inc(confirmedCount); + totalModuleSize := totalModuleSize + pattern.estimatedModuleSize; + end; + end; + + if (confirmedCount < 3) then + begin + result := false; + exit + end; + + average := totalModuleSize / max; + totalDeviation := 0; + i := 0; + + while ((i < max)) do + begin + pattern := FPossibleCenters[i]; + totalDeviation := totalDeviation + + Abs(pattern.estimatedModuleSize - average); + inc(i) + end; + + result := (totalDeviation <= (0.05 * totalModuleSize)); + +end; + +function TFinderPatternFinder.selectBestPatterns: TArray; +var + average, square, totalModuleSize: Double; + size, stdDev, limit, avrsng: Single; + center, possibleCenter, pattern: IFinderPattern; + startSize, i: Integer; + comparator: IComparer; +begin + startSize := FPossibleCenters.Count; + if (startSize < 3) then + begin + result := nil; + exit + end; + if (startSize > 3) then + begin + totalModuleSize := 0; + square := 0; + + for center in FPossibleCenters do + begin + size := center.estimatedModuleSize; + totalModuleSize := totalModuleSize + size; + square := square + (size * size); + end; + + average := totalModuleSize / startSize; + stdDev := Sqrt((square / startSize) - (average * average)); + // this intermediate assignment is a workaround for old-gen compilers + // that are not deallocating TFurthestFromAverageComparator instance + // (bug verified on XE8: just declare a destructor Destroy override + // in TFurthestFromAverageComparator put a breakpoint in it and see + // that the destructor never gets called if you don't use this intermediate + // assignment) + avrsng := average; + comparator := TFurthestFromAverageComparator.Create(avrsng); + FPossibleCenters.Sort(comparator); + limit := System.Math.Max((0.2 * avrsng), stdDev); + i := 0; + while (((i < FPossibleCenters.Count) and + (FPossibleCenters.Count > 3))) do + begin + pattern := FPossibleCenters[i]; + if (Abs(pattern.estimatedModuleSize - average) > limit) then + begin + FPossibleCenters.Delete(i); + dec(i) + end; + inc(i) + end + end; + + if (FPossibleCenters.Count > 3) then + begin + totalModuleSize := 0; + + for possibleCenter in FPossibleCenters do + begin + totalModuleSize := totalModuleSize + possibleCenter.estimatedModuleSize; + end; + + average := totalModuleSize / FPossibleCenters.Count; + // this intermediate assignment is a workaround for old-gen compilers + // that are not deallocating TCenterComparator instance + // (bug verified on XE8: just declare a destructor Destroy override in + // TCenterComparator,put a breakpoint in it and see that the destructor + // never gets called if you don't use this intermediate assignment) + comparator := TCenterComparator.Create(average); + + FPossibleCenters.Sort( comparator ); + + // if (PossibleCenters.Count > 4) then + // begin + // self.PossibleCenters.DeleteRange(4, self.PossibleCenters.Count - 1); + // end; + + end; + + result := TArray.Create(FPossibleCenters[0], + FPossibleCenters[1], FPossibleCenters[2]); + +end; + +{ TFurthestFromAverageComparator } + +function TFurthestFromAverageComparator.Compare(const Left, + Right: IFinderPattern): Integer; +var + dA, dB: Single; +begin + dA := Abs(Right.estimatedModuleSize - self.average); + dB := Abs(Left.estimatedModuleSize - self.average); + + if (dA < dB) then + begin + result := -1; + end + else if (dA = dB) then + begin + result := 0; + end + else + result := 1; + +end; + +constructor TFurthestFromAverageComparator.Create(f: Single); +begin + average := f; +end; + +{ TCenterComparator } + +function TCenterComparator.Compare(const Left, Right: IFinderPattern): Integer; +var + dA, dB: Single; +begin + if (Right.Count = Left.Count) then + begin + dA := Abs(Right.estimatedModuleSize - self.average); + dB := Abs(Left.estimatedModuleSize - self.average); + + if (dA < dB) then + begin + result := 1; + end + else if (dA = dB) then + begin + result := 0; + end + else + result := -1; + + exit; + end; + + result := (Right.Count - Left.Count); + +end; + +constructor TCenterComparator.Create(f: Single); +begin + average := f; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternImplementation.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternImplementation.pas new file mode 100644 index 0000000..78330da --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternImplementation.pas @@ -0,0 +1,152 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.FinderPatternImplementation; + +interface +uses + ZXing.QrCode.Internal.FinderPattern; + + +function NewFinderPattern(const posX, posY, estimatedModuleSize: Single; const count: Integer):IFinderPattern; overload; +function NewFinderPattern(const posX, posY, estimatedModuleSize: Single):IFinderPattern; overload; + + +implementation +uses ZXing.ResultPoint,ZXing.ResultPointImplementation; + +{ TFinderPattern } + + +type + /// + ///

Encapsulates a finder pattern, which are the three square patterns found in + /// the corners of QR Codes. It also encapsulates a count of similar finder patterns, + /// as a convenience to the finder's bookkeeping.

+ ///
+ TFinderPattern = class(TResultPoint,IResultPoint,IFinderPattern) + private + Fcount: Integer; + FestimatedModuleSize: Single; + + function GetCount:integer; + procedure SetCount(value:integer); + + constructor Create(const posX, posY, estimatedModuleSize: Single; + const count: Integer); overload; + constructor Create(const posX, posY, estimatedModuleSize: Single); overload; + + ///

Determines if this finder pattern "about equals" a finder pattern at the stated + /// position and size -- meaning, it is at nearly the same center with nearly the same size.

+ ///
+ function aboutEquals(const moduleSize, i, j: Single): Boolean; + + /// + /// Combines this object's current estimate of a finder pattern position and module size + /// with a new estimate. It returns a new {@code FinderPattern} containing a weighted average + /// based on count. + /// + /// The i. + /// The j. + /// New size of the module. + /// + function combineEstimate(const i, j, newModuleSize: Single): IFinderPattern; + + /// + /// Gets the size of the estimated module. + /// + /// + /// The size of the estimated module. + /// + function estimatedModuleSize : Single; + property count : Integer read GetCount write SetCount; + end; + +constructor TFinderPattern.Create(const posX, posY, + estimatedModuleSize: Single; const count: Integer); +begin + inherited Create(posX, posY); + + FestimatedModuleSize := estimatedModuleSize; + Fcount := count; +end; + +constructor TFinderPattern.Create(const posX, posY, + estimatedModuleSize: Single); +begin + Self.Create(posX, posY, estimatedModuleSize, 1); +end; + +function TFinderPattern.estimatedModuleSize: Single; +begin + result := FestimatedModuleSize; +end; + +function TFinderPattern.GetCount: integer; +begin + result := FCount; +end; + +function TFinderPattern.aboutEquals(const moduleSize, i, j: Single): Boolean; +var + moduleSizeDiff : Single; +begin + Result := false; + + if ((Abs(i - y) <= moduleSize) and (Abs(j - x) <= moduleSize)) then + begin + moduleSizeDiff := Abs(moduleSize - self.estimatedModuleSize); + + Result := ((moduleSizeDiff <= 1) or + (moduleSizeDiff <= self.estimatedModuleSize)); + end; +end; + +procedure TFinderPattern.SetCount(value: integer); +begin + FCount := value; +end; + +function TFinderPattern.combineEstimate(const i, j, + newModuleSize: Single): IFinderPattern; +var + combinedCount: Integer; + combinedX, combinedY: Single; +begin + combinedCount := (Self.count + 1); + combinedX := ((Self.count * x) + j) / combinedCount; + combinedY := ((Self.count * y) + i) / combinedCount; + Result := TFinderPattern.Create(combinedX, combinedY, + (((Self.count * Self.estimatedModuleSize) + newModuleSize) / combinedCount), + combinedCount) +end; + + +function NewFinderPattern(const posX, posY, estimatedModuleSize: Single; const count: Integer):IFinderPattern; +begin + result := TFinderPattern.Create( posX, posY, estimatedModuleSize,count); +end; + +function NewFinderPattern(const posX, posY, estimatedModuleSize: Single):IFinderPattern; +begin + result := TFinderPattern.Create( posX, posY, estimatedModuleSize); +end; + + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternInfo.pas b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternInfo.pas new file mode 100644 index 0000000..7c82ea3 --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/Detector/ZXing.QrCode.Internal.FinderPatternInfo.pas @@ -0,0 +1,69 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.Internal.FinderPatternInfo; + +interface + +uses + ZXing.QrCode.Internal.FinderPattern; + +type + /// + ///

Encapsulates information about finder patterns in an image, including the location of + /// the three finder patterns, and their estimated module size.

+ ///
+ TFinderPatternInfo = class sealed + private + FbottomLeft: IFinderPattern; + FtopLeft: IFinderPattern; + FtopRight: IFinderPattern; + public + /// + /// Initializes a new instance of the class. + /// + /// The pattern centers. + constructor Create(const patternCenters: TArray); + + /// + /// Gets the bottom left. + /// + property bottomLeft : IFinderPattern read FbottomLeft; + + /// + /// Gets the top left. + /// + property topLeft : IFinderPattern read FtopLeft; + + /// + /// Gets the top right. + /// + property topRight : IFinderPattern read FtopRight; + end; + +implementation + +constructor TFinderPatternInfo.Create(const patternCenters: TArray); +begin + FbottomLeft := patternCenters[0]; + FtopLeft := patternCenters[1]; + FtopRight := patternCenters[2] +end; + +end. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/ZXing.Datamatrix.DataMatrixReader.pas b/android-client/ThirdParty/ZXing/2D Barcodes/ZXing.Datamatrix.DataMatrixReader.pas new file mode 100644 index 0000000..e2658ee --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/ZXing.Datamatrix.DataMatrixReader.pas @@ -0,0 +1,258 @@ +{ + * 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. diff --git a/android-client/ThirdParty/ZXing/2D Barcodes/ZXing.QrCode.QRCodeReader.pas b/android-client/ThirdParty/ZXing/2D Barcodes/ZXing.QrCode.QRCodeReader.pas new file mode 100644 index 0000000..9cb6dae --- /dev/null +++ b/android-client/ThirdParty/ZXing/2D Barcodes/ZXing.QrCode.QRCodeReader.pas @@ -0,0 +1,340 @@ +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.QrCode.QRCodeReader; + +interface + +uses + System.SysUtils, + System.Math, + System.Generics.Collections, + ZXing.Common.BitArray, + ZXing.ReadResult, + ZXing.Reader, + ZXing.DecodeHintType, + ZXing.BarcodeFormat, + ZXing.ResultPoint, + ZXing.BinaryBitmap, + ZXing.QrCode.Internal.Decoder, + ZXing.Common.BitMatrix, + ZXing.DecoderResult, + ZXing.ResultMetadataType, + ZXing.Common.DetectorResult, + ZXing.QrCode.Internal.QRCodeDecoderMetaData, + ZXing.QrCode.Internal.Detector, + ZXing.QrCode.Internal.DecodedBitStreamParser; + +type + /// + /// This implementation can detect and decode QR Codes in an image. + /// + TQRCodeReader = class(TInterfacedObject, IReader) + private + FDecoder: TQRDecoder; + 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 msize: Single): Boolean; static; + protected + /// + /// Gets the decoder. + /// + /// + property Decoder: TQRDecoder read FDecoder; + public + constructor Create; + destructor Destroy; override; + + /// + /// Locates and decodes a QR code in an image. + /// + /// a String representing the content encoded by the QR code + /// + function decode(const image: TBinaryBitmap): TReadResult; overload; + /// + /// Locates and decodes a barcode in some format within an image. This method also accepts + /// hints, each possibly associated to some data, which may help the implementation decode. + /// + /// image of barcode to decode + /// passed as a from + /// to arbitrary data. The + /// meaning of the data depends upon the hint type. The implementation may or may not do + /// anything with these hints. + /// + /// String which the barcode encodes + /// + function decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; overload; + + /// + /// Resets any internal state the implementation has after a decode, to prepare it + /// for reuse. + /// + procedure reset; + end; + +implementation +uses ZXing.ByteSegments; + +{ TQRCodeReader } + +constructor TQRCodeReader.Create; +begin + inherited; + FDecoder := TQRDecoder.Create; + NO_POINTS := TArray.Create(); +end; + +destructor TQRCodeReader.Destroy; +begin + NO_POINTS := nil; + FDecoder.Free; + inherited; +end; + +function TQRCodeReader.decode(const image: TBinaryBitmap): TReadResult; +begin + Result := Self.decode(image, nil); +end; + +function TQRCodeReader.decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; +var + DecoderResult: TDecoderResult; + Detector: TDetector; + points: TArray; + bits: TBitMatrix; + DetectorResult: TDetectorResult; + data: TQRCodeDecoderMetaData; + byteSegments: IByteSegments; +begin + Result := nil; + DecoderResult := nil; + + if ((image = nil) or (image.BlackMatrix = nil)) then + // something is wrong with the image + exit; + try + + if ((hints <> nil) and hints.ContainsKey(TDecodeHintType.PURE_BARCODE)) then + begin + bits := TQRCodeReader.extractPureBits(image.BlackMatrix); + if Assigned(bits) then + begin + DecoderResult := Decoder.decode(bits, hints); + points := NO_POINTS; + bits.Free; + end + else + exit; + end + else + begin + Detector := TDetector.Create(image.BlackMatrix); + try + DetectorResult := Detector.detect(hints); + if Assigned(DetectorResult) then + begin + DecoderResult := Decoder.decode(DetectorResult.bits, hints); + points := DetectorResult.points; + DetectorResult.Free; + end + else + exit; + finally + Detector.Free; + end; + end; + + if (DecoderResult = nil) then + exit; + + // If the code was mirrored: swap the bottom-left and the top-right points. + data := TQRCodeDecoderMetaData(DecoderResult.Other); + if (data <> nil) then + data.applyMirroredCorrection(points); + + Result := TReadResult.Create(DecoderResult.Text, DecoderResult.RawBytes, + points, TBarcodeFormat.QR_CODE); + + 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)); + + if (DecoderResult.StructuredAppend) then + begin + Result.putMetadata(TResultMetadataType.STRUCTURED_APPEND_SEQUENCE, + TResultMetaData.CreateIntegerMetadata(DecoderResult.StructuredAppendSequenceNumber)); + Result.putMetadata(TResultMetadataType.STRUCTURED_APPEND_PARITY, + TResultMetaData.CreateIntegerMetadata(DecoderResult.StructuredAppendParity)) + end; + + finally + + if Assigned(DecoderResult) then + FreeAndNil(DecoderResult); + + end; + +end; + +procedure TQRCodeReader.reset; +begin + // do nothing +end; + +class function TQRCodeReader.extractPureBits(const image: TBitMatrix) + : TBitMatrix; +var + moduleSize: Single; + leftTopBlack, rightBottomBlack: TArray; + top, bottom, left, right, matrixWidth, matrixHeight, nudge, x, y, iOffset, + nudgedTooFarRight, nudgedTooFarDown: Integer; + bits: TBitMatrix; +begin + Result := nil; + + leftTopBlack := image.getTopLeftOnBit; + rightBottomBlack := image.getBottomRightOnBit; + if ((leftTopBlack = nil) or (rightBottomBlack = nil)) then + exit; + + if (not TQRCodeReader.moduleSize(leftTopBlack, image, moduleSize)) then + exit; + + top := leftTopBlack[1]; + bottom := rightBottomBlack[1]; + left := leftTopBlack[0]; + right := rightBottomBlack[0]; + + // Sanity check! + if ((left >= right) or (top >= bottom)) then + exit; + + if ((bottom - top) <> (right - left)) then + // Special case, where bottom-right module wasn't black so we found something else in the last row + // Assume it's a square, so use height as the width + right := (left + (bottom - top)); + + matrixWidth := Round(((right - left) + 1) / moduleSize); + matrixHeight := Round(((bottom - top) + 1) / moduleSize); + if ((matrixWidth <= 0) or (matrixHeight <= 0)) then + exit; + + if (matrixHeight <> matrixWidth) then + // Only possibly decode square regions + 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 := Trunc(moduleSize / 2.0); + Inc(top, nudge); + Inc(left, nudge); + + // But careful that this does not sample off the edge + // "right" is the farthest-right valid pixel location -- right+1 is not necessarily + // This is positive by how much the inner x loop below would be too large + nudgedTooFarRight := left + Trunc((matrixWidth - 1) * moduleSize) - right; + if (nudgedTooFarRight > 0) then + begin + if (nudgedTooFarRight > nudge) then + // Neither way fits; abort + exit; + Dec(left, nudgedTooFarRight); + end; + // See logic above + nudgedTooFarDown := top + Trunc((matrixHeight - 1) * moduleSize) - bottom; + if (nudgedTooFarDown > 0) then + begin + if (nudgedTooFarDown > nudge) then + // Neither way fits; abort + exit; + Dec(top, nudgedTooFarDown); + end; + + // Now just read off the bits + bits := TBitMatrix.Create(matrixWidth, matrixHeight); + for y := 0 to Pred(matrixHeight) do + begin + iOffset := top + Trunc(y * moduleSize); + for x := 0 to Pred(matrixWidth) do + begin + if (image[left + Trunc((x * moduleSize)), iOffset]) then + bits[x, y] := true; + end; + end; + + Result := bits; +end; + +class function TQRCodeReader.moduleSize(const leftTopBlack: TArray; + const image: TBitMatrix; var msize: Single): Boolean; +var + height, width, x, y: Integer; + inBlack: Boolean; + transitions: Integer; +begin + Result := false; + + height := image.height; + width := image.width; + x := leftTopBlack[0]; + y := leftTopBlack[1]; + + inBlack := true; + transitions := 0; + while (((x < width) and (y < height))) do + begin + if (inBlack <> image[x, y]) then + begin + Inc(transitions); + if (transitions = 5) then + break; + inBlack := not inBlack; + end; + Inc(x); + Inc(y); + end; + + if ((x = width) or (y = height)) then + begin + msize := 0.0; + exit; + end; + + msize := ((x - leftTopBlack[0]) / 7.0); + Result := true; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/Detector/ZXing.Common.Detector.MathUtils.pas b/android-client/ThirdParty/ZXing/Common/Detector/ZXing.Common.Detector.MathUtils.pas new file mode 100644 index 0000000..c7a314e --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/Detector/ZXing.Common.Detector.MathUtils.pas @@ -0,0 +1,83 @@ +unit ZXing.Common.Detector.MathUtils; + +{ + * 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. + + * Implemented by E. Spelt for Delphi + * Restructured by K. Gossens +} +interface + +uses + System.SysUtils; + +type + TMathUtils = class sealed + public + class function distance(const aX, aY, bX, bY: Double): Single; static; + class function round(d: Single): Integer; static; + // class function Asr(x, y: integer): integer; overload; static; + class function Asr(Value: Int64; ShiftBits: integer): Int64; static; + end; + +implementation + +{ TMathUtils } + +class function TMathUtils.distance(const aX, aY, bX, bY: Double): Single; +var + xDiff, yDiff: double; +begin + xDiff := aX - bX; + yDiff := aY - bY; + result := Sqrt(xDiff * xDiff + yDiff * yDiff); +end; + +class function TMathUtils.round(d: Single): Integer; +begin + if (Single.IsNaN(d)) then + begin + Result := 0; + exit + end; + if (Single.IsPositiveInfinity(d)) then + begin + Result := $7fffffff; + exit; + end; + + + + if (d < 0) + then + Result := Trunc(d + (-0.5)) + else + Result := Trunc(d + 0.5); +end; + +{ + class function TMathUtils.Asr(x, y: integer): integer; + begin + result := x div (1 shl y); + end; +} +class function TMathUtils.Asr(Value: Int64; ShiftBits: integer): Int64; +begin + result := Value shr ShiftBits; + if (Value and $8000000000000000) > 0 then + result := result or ($FFFFFFFFFFFFFFFF shl (64 - ShiftBits)); +end; + +end. \ No newline at end of file diff --git a/android-client/ThirdParty/ZXing/Common/Detector/ZXing.Common.Detector.WhiteRectangleDetector.pas b/android-client/ThirdParty/ZXing/Common/Detector/ZXing.Common.Detector.WhiteRectangleDetector.pas new file mode 100644 index 0000000..04e4af1 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/Detector/ZXing.Common.Detector.WhiteRectangleDetector.pas @@ -0,0 +1,398 @@ +{ + * 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. + + * Implemented by E. Spelt for Delphi + * Restructured by K. Gossens +} + +unit ZXing.Common.Detector.WhiteRectangleDetector; + +interface + +uses + System.SysUtils, + ZXing.Common.BitMatrix, + ZXing.Common.Detector.MathUtils, + ZXing.ResultPoint; + +type + TWhiteRectangleDetector = class sealed + private const + CORR: Integer = 1; + INIT_SIZE: Integer = 10; + + var + downInit: Integer; + height: Integer; + image: TBitMatrix; + leftInit: Integer; + rightInit: Integer; + upInit: Integer; + width: Integer; + constructor Create(image: TBitMatrix); overload; + constructor Create(image: TBitMatrix; initSize: Integer; x: Integer; + y: Integer); overload; + function centerEdges(y: IResultPoint; z: IResultPoint; x: IResultPoint; + t: IResultPoint): TArray; + function containsBlackPoint(a: Integer; b: Integer; fixed: Integer; + horizontal: boolean): boolean; + function getBlackPointOnSegment(aX: Single; aY: Single; bX: Single; + bY: Single): IResultPoint; + public + class function New(image: TBitMatrix): TWhiteRectangleDetector; overload; + class function New(image: TBitMatrix; initSize: Integer; x: Integer; + y: Integer): TWhiteRectangleDetector; overload; static; + function detect(): TArray; + end; + +implementation + +{ TWhiteRectangleDetector } + +constructor TWhiteRectangleDetector.Create(image: TBitMatrix); +begin + Self.Create(image, 10, image.width div 2, image.height div 2); +end; + +constructor TWhiteRectangleDetector.Create(image: TBitMatrix; initSize: Integer; + x: Integer; y: Integer); +var + halfsize: Integer; +begin + Self.image := image; + Self.height := image.height; + Self.width := image.width; + halfsize := (initSize div 2); + Self.leftInit := (x - halfsize); + Self.rightInit := (x + halfsize); + Self.upInit := (y - halfsize); + Self.downInit := (y + halfsize); +end; + +function TWhiteRectangleDetector.centerEdges(y: IResultPoint; z: IResultPoint; + x: IResultPoint; t: IResultPoint): TArray; +var + yi, yj, zi, zj, xi, xj, ti, tj: Single; +begin + yi := y.x; + yj := y.y; + zi := z.x; + zj := z.y; + xi := x.x; + xj := x.y; + ti := t.x; + tj := t.y; + + if (yi < (Self.width div 2)) then + begin + Result := TArray.Create(TResultPointHelpers.CreateResultPoint((ti - 1), (tj + 1) + ), TResultPointHelpers.CreateResultPoint((zi + 1), (zj + 1)), TResultPointHelpers.CreateResultPoint((xi - 1), + (xj - 1)), TResultPointHelpers.CreateResultPoint((yi + 1), (yj - 1))); + exit; + end; + + Result := TArray.Create(TResultPointHelpers.CreateResultPoint((ti + 1), (tj + 1)), + TResultPointHelpers.CreateResultPoint((zi + 1), (zj - 1)), TResultPointHelpers.CreateResultPoint((xi - 1), + (xj + 1)), TResultPointHelpers.CreateResultPoint((yi - 1), (yj - 1))); + +end; + +function TWhiteRectangleDetector.containsBlackPoint(a: Integer; b: Integer; + fixed: Integer; horizontal: boolean): boolean; +var + x, y: Integer; +begin + if (horizontal) then + begin + x := a; + + while ((x <= b)) do + begin + if (Self.image[x, fixed]) then + begin + Result := true; + exit; + end; + Inc(x) + end; + end + else + begin + y := a; + + while ((y <= b)) do + begin + if (Self.image[fixed, y]) then + begin + Result := true; + exit; + end; + Inc(y); + end; + end; + + Result := false; +end; + +class function TWhiteRectangleDetector.New(image: TBitMatrix) + : TWhiteRectangleDetector; +var + instance: TWhiteRectangleDetector; +begin + Result := nil; + if (image <> nil) then + begin + instance := TWhiteRectangleDetector.Create(image); + if (((instance.upInit >= 0) and (instance.leftInit >= 0)) and + ((instance.downInit < instance.height) and + (instance.rightInit < instance.width))) then + Result := instance + else + instance.Free; + end; +end; + +class function TWhiteRectangleDetector.New(image: TBitMatrix; initSize: Integer; + x: Integer; y: Integer): TWhiteRectangleDetector; +var + instance: TWhiteRectangleDetector; +begin + instance := TWhiteRectangleDetector.Create(image, initSize, x, y); + if (((instance.upInit >= 0) and (instance.leftInit >= 0)) and + ((instance.downInit < instance.height) and + (instance.rightInit < instance.width))) then + Result := instance + else + begin + instance.Free; + Result := nil; + end; +end; + +function TWhiteRectangleDetector.detect: TArray; +var + left, right, up, down: Integer; + sizeExceeded, aBlackPointFoundOnBorder, atLeastOneBlackPointFoundOnBorder, + atLeastOneBlackPointFoundOnRight, atLeastOneBlackPointFoundOnBottom, + atLeastOneBlackPointFoundOnLeft, atLeastOneBlackPointFoundOnTop, + rightBorderNotWhite, bottomBorderNotWhite, leftBorderNotWhite, + topBorderNotWhite: boolean; + i: Integer; + z, t, x, y: IResultPoint; + maxSize: Integer; +begin + z := nil; + t := nil; + x := nil; + y := nil; + + left := Self.leftInit; + right := Self.rightInit; + up := Self.upInit; + down := Self.downInit; + sizeExceeded := false; + aBlackPointFoundOnBorder := true; + atLeastOneBlackPointFoundOnBorder := false; + atLeastOneBlackPointFoundOnRight := false; + atLeastOneBlackPointFoundOnBottom := false; + atLeastOneBlackPointFoundOnLeft := false; + atLeastOneBlackPointFoundOnTop := false; + while (aBlackPointFoundOnBorder) do + begin + aBlackPointFoundOnBorder := false; + rightBorderNotWhite := true; + while ((rightBorderNotWhite or (not atLeastOneBlackPointFoundOnRight)) and + (right < Self.width)) do + begin + rightBorderNotWhite := Self.containsBlackPoint(up, down, right, false); + if (rightBorderNotWhite) then + begin + Inc(right); + aBlackPointFoundOnBorder := true; + atLeastOneBlackPointFoundOnRight := true; + end + else if (not atLeastOneBlackPointFoundOnRight) then + Inc(right); + end; + + if (right >= Self.width) then + begin + sizeExceeded := true; + break; + end; + + bottomBorderNotWhite := true; + while ((bottomBorderNotWhite or (not atLeastOneBlackPointFoundOnBottom)) and + (down < Self.height)) do + begin + bottomBorderNotWhite := Self.containsBlackPoint(left, right, down, true); + if (bottomBorderNotWhite) then + begin + Inc(down); + aBlackPointFoundOnBorder := true; + atLeastOneBlackPointFoundOnBottom := true; + end + else if (not atLeastOneBlackPointFoundOnBottom) then + Inc(down); + end; + + if (down >= Self.height) then + begin + sizeExceeded := true; + break; + end; + + leftBorderNotWhite := true; + while ((leftBorderNotWhite or (not atLeastOneBlackPointFoundOnLeft)) and + (left >= 0)) do + begin + leftBorderNotWhite := Self.containsBlackPoint(up, down, left, false); + if (leftBorderNotWhite) then + begin + Dec(left); + aBlackPointFoundOnBorder := true; + atLeastOneBlackPointFoundOnLeft := true; + end + else if (not atLeastOneBlackPointFoundOnLeft) then + Dec(left); + end; + + if (left < 0) then + begin + sizeExceeded := true; + break; + end; + + topBorderNotWhite := true; + while ((topBorderNotWhite or (not atLeastOneBlackPointFoundOnTop)) and + (up >= 0)) do + begin + topBorderNotWhite := Self.containsBlackPoint(left, right, up, true); + if (topBorderNotWhite) then + begin + Dec(up); + aBlackPointFoundOnBorder := true; + atLeastOneBlackPointFoundOnTop := true; + end + else if (not atLeastOneBlackPointFoundOnTop) then + Dec(up); + end; + + if (up < 0) then + begin + sizeExceeded := true; + break; + end; + + if (aBlackPointFoundOnBorder) then + atLeastOneBlackPointFoundOnBorder := true; + end; + + if (not(not sizeExceeded and atLeastOneBlackPointFoundOnBorder)) then + begin + Result := nil; + exit; + end; + + maxSize := (right - left); + i := 1; + while ((i < maxSize)) do + begin + z := Self.getBlackPointOnSegment(left, (down - i), (left + i), down); + if (z <> nil) then + break; + Inc(i); + end; + + if (z = nil) then + begin + Result := nil; + exit; + end; + + i := 1; + while ((i < maxSize)) do + begin + t := Self.getBlackPointOnSegment(left, (up + i), (left + i), up); + if (t <> nil) then + break; + Inc(i); + end; + + if (t = nil) then + begin + Result := nil; + exit; + end; + + i := 1; + while ((i < maxSize)) do + begin + x := Self.getBlackPointOnSegment(right, (up + i), (right - i), up); + if (x <> nil) then + break; + Inc(i); + end; + + if (x = nil) then + begin + Result := nil; + exit; + end; + + y := nil; + i := 1; + while ((i < maxSize)) do + begin + y := Self.getBlackPointOnSegment(right, (down - i), (right - i), down); + if (y <> nil) then + break; + Inc(i); + end; + + if (y = nil) then + begin + Result := nil; + exit; + end; + + Result := Self.centerEdges(y, z, x, t); +end; + +function TWhiteRectangleDetector.getBlackPointOnSegment(aX: Single; aY: Single; + bX: Single; bY: Single): IResultPoint; +var + i, x, y, dist: Integer; + xStep, yStep: Single; +begin + dist := TMathUtils.round(TMathUtils.distance(aX, aY, bX, bY)); + xStep := ((bX - aX) / dist); + yStep := ((bY - aY) / dist); + i := 0; + while ((i < dist)) do + begin + x := TMathUtils.round((aX + (i * xStep))); + y := TMathUtils.round((aY + (i * yStep))); + if (Self.image[x, y]) then + begin + Result := TResultPointHelpers.CreateResultPoint(x, y); + exit; + end; + Inc(i); + end; + Result := nil; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ReedSolomon/ZXing.Common.ReedSolomon.GenericGF.pas b/android-client/ThirdParty/ZXing/Common/ReedSolomon/ZXing.Common.ReedSolomon.GenericGF.pas new file mode 100644 index 0000000..a1caf9f --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ReedSolomon/ZXing.Common.ReedSolomon.GenericGF.pas @@ -0,0 +1,693 @@ +unit ZXing.Common.ReedSolomon.GenericGF; + +{ + * 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: Sean Owen + * Delphi Implementation by E. Spelt and K. Gossens +} + +// ES: two classes in one unit. This is to avoid circulair reference. + +interface + +uses SysUtils; + +type + TGenericGF = class; + + IGenericGFPoly = interface + ['{9E56C626-16C5-4A5A-99B5-84559780EB9D}'] + + function get_Degree: Integer; + function get_isZero: boolean; + function get_field: TGenericGF; + function get_coefficients: TArray; + + property coefficients: TArray read get_coefficients; + property degree: Integer read get_Degree; + property isZero: boolean read get_isZero; + property Field: TGenericGF read get_field; + + function addOrSubtract(other: IGenericGFPoly): IGenericGFPoly; + function divide(other: IGenericGFPoly): TArray; + function evaluateAt(a: Integer): Integer; + function getCoefficient(degree: Integer): Integer; + + function multiply(scalar: Integer): IGenericGFPoly; overload; + function multiply(other: IGenericGFPoly): IGenericGFPoly; overload; + + function multiplyByMonomial(degree: Integer; coefficient: Integer) + : IGenericGFPoly; + + function ToString: string; + end; + + /// + ///

This class contains utility methods for performing mathematical operations over + /// the Galois Fields. Operations use a given primitive polynomial in calculations.

+ ///

Throughout this package, elements of the GF are represented as an {@code int} + /// for convenience and speed (but at the cost of memory). + ///

+ ///
+ TGenericGF = class sealed + private + FexpTable: TArray; + FGeneratorBase: Integer; + FlogTable: TArray; + FZero: IGenericGFPoly; + FOne: IGenericGFPoly; + Fprimitive: Integer; + Fsize: Integer; + + function get_GeneratorBase: Integer; + function get_One: IGenericGFPoly; + function get_Zero: IGenericGFPoly; + function get_Size: Integer; + + class function get_AZTEC_DATA_10: TGenericGF; static; + class function get_AZTEC_DATA_12: TGenericGF; static; + class function get_AZTEC_DATA_6: TGenericGF; static; + class function get_AZTEC_PARAM: TGenericGF; static; + class function get_QR_CODE_FIELD_256: TGenericGF; static; + class function get_DATA_MATRIX_FIELD_256: TGenericGF; static; + class procedure InitializeClass(); static; + class procedure FinalizeClass(); static; + public + class var AZTEC_DATA_10: TGenericGF; + class var AZTEC_DATA_12: TGenericGF; + class var AZTEC_DATA_6: TGenericGF; + class var AZTEC_PARAM: TGenericGF; + class var DATA_MATRIX_FIELD_256: TGenericGF; + class var QR_CODE_FIELD_256: TGenericGF; + class var MAXICODE_FIELD_64: TGenericGF; + class var AZTEC_DATA_8: TGenericGF; + + constructor Create(primitive, size, genBase: Integer); + destructor Destroy(); override; + + function ToString: string; override; + + class function addOrSubtract(a: Integer; b: Integer): Integer; static; + function multiply(a: Integer; b: Integer): Integer; + function buildMonomial(degree: Integer; coefficient: Integer) + : IGenericGFPoly; + function log(a: Integer): Integer; + function exp(a: Integer): Integer; + function inverse(a: Integer): Integer; + + property GeneratorBase: Integer read get_GeneratorBase; + property size: Integer read get_Size; + property One: IGenericGFPoly read get_One; + property Zero: IGenericGFPoly read get_Zero; + + end; + + TGenericGFPoly = class sealed(TInterfacedObject, IGenericGFPoly) + private + Fcoefficients: TArray; + Ffield: TGenericGF; + public + function get_Degree: Integer; + function get_isZero: boolean; + function get_field: TGenericGF; + function get_coefficients: TArray; + + property coefficients: TArray read get_coefficients; + property degree: Integer read get_Degree; + property isZero: boolean read get_isZero; + property Field: TGenericGF read get_field; + + constructor Create(Field: TGenericGF; coefficients: TArray); + destructor Destroy(); override; + function addOrSubtract(other: IGenericGFPoly): IGenericGFPoly; + function divide(other: IGenericGFPoly): TArray; + function evaluateAt(a: Integer): Integer; + function getCoefficient(degree: Integer): Integer; + + function multiply(scalar: Integer): IGenericGFPoly; overload; + function multiply(other: IGenericGFPoly): IGenericGFPoly; overload; + + function multiplyByMonomial(degree: Integer; coefficient: Integer) + : IGenericGFPoly; + + function ToString: string; override; + + end; + +implementation + +{ TGenericGF } + +class procedure TGenericGF.InitializeClass(); +begin + AZTEC_DATA_10 := get_AZTEC_DATA_10(); + AZTEC_DATA_12 := get_AZTEC_DATA_12; + AZTEC_DATA_6 := get_AZTEC_DATA_6; + AZTEC_PARAM := get_AZTEC_PARAM; + DATA_MATRIX_FIELD_256 := get_DATA_MATRIX_FIELD_256; + QR_CODE_FIELD_256 := get_QR_CODE_FIELD_256; + MAXICODE_FIELD_64 := get_AZTEC_DATA_6; + AZTEC_DATA_8 := get_DATA_MATRIX_FIELD_256; +end; + +class procedure TGenericGF.FinalizeClass; +begin + FreeAndNil(AZTEC_DATA_10); + FreeAndNil(AZTEC_DATA_12); + FreeAndNil(AZTEC_DATA_6); + FreeAndNil(AZTEC_PARAM); + FreeAndNil(DATA_MATRIX_FIELD_256); + FreeAndNil(QR_CODE_FIELD_256); + FreeAndNil(MAXICODE_FIELD_64); + FreeAndNil(AZTEC_DATA_8); +end; + +constructor TGenericGF.Create(primitive, size, genBase: Integer); +var + x, i: Integer; +begin + self.Fprimitive := primitive; + Fsize := size; + + FGeneratorBase := genBase; + self.FexpTable := TArray.Create(); + self.FlogTable := TArray.Create(); + + SetLength(self.FexpTable, size); + SetLength(self.FlogTable, size); + + x := 1; + i := 0; + + while ((i < size)) do + begin + self.FexpTable[i] := x; + x := (x shl 1); + if (x >= size) then + begin + x := (x xor primitive); + x := (x and (size - 1)) + end; + inc(i) + end; + + i := 0; + while ((i < (size - 1))) do + begin + self.FlogTable[self.FexpTable[i]] := i; + inc(i) + end; + + FZero := TGenericGFPoly.Create(self, TArray.Create(0)); + FOne := TGenericGFPoly.Create(self, TArray.Create(1)); +end; + +destructor TGenericGF.Destroy; +begin + self.FexpTable := nil; + self.FlogTable := nil; + inherited; +end; + +class function TGenericGF.addOrSubtract(a, b: Integer): Integer; +begin + Result := (a xor b) +end; + +function TGenericGF.buildMonomial(degree, coefficient: Integer): IGenericGFPoly; +var + coefficients: TArray; +begin + if (degree < 0) then + raise EArgumentException.Create('Wrong argument'); + + if (coefficient = 0) then + begin + Result := self.Zero; + exit + end; + + coefficients := TArray.Create(); + SetLength(coefficients, degree + 1); + coefficients[0] := coefficient; + + Result := TGenericGFPoly.Create(self, coefficients); + +end; + +function TGenericGF.exp(a: Integer): Integer; +begin + Result := self.FexpTable[a] +end; + +class function TGenericGF.get_AZTEC_DATA_10: TGenericGF; +begin + Result := TGenericGF.Create($409, $400, 1); +end; + +class function TGenericGF.get_AZTEC_DATA_12: TGenericGF; +begin + Result := TGenericGF.Create($1069, $1000, 1); +end; + +class function TGenericGF.get_AZTEC_DATA_6: TGenericGF; +begin + Result := TGenericGF.Create($43, $40, 1); +end; + +class function TGenericGF.get_AZTEC_PARAM: TGenericGF; +begin + Result := TGenericGF.Create($13, $10, 1); +end; + +class function TGenericGF.get_DATA_MATRIX_FIELD_256: TGenericGF; +begin + Result := TGenericGF.Create($12D, $100, 1); +end; + +function TGenericGF.get_GeneratorBase: Integer; +begin + Result := FGeneratorBase; +end; + +function TGenericGF.get_One: IGenericGFPoly; +begin + Result := FOne; +end; + +class function TGenericGF.get_QR_CODE_FIELD_256: TGenericGF; +begin + Result := TGenericGF.Create($11D, $100, 0); +end; + +function TGenericGF.get_Size: Integer; +begin + Result := Fsize; +end; + +function TGenericGF.get_Zero: IGenericGFPoly; +begin + Result := FZero; +end; + +function TGenericGF.inverse(a: Integer): Integer; +begin + if (a = 0) then + raise Exception.Create('Artithmetic Exception'); + + Result := self.FexpTable[((self.size - self.FlogTable[a]) - 1)]; +end; + +function TGenericGF.log(a: Integer): Integer; +begin + if (a = 0) then + raise EArgumentException.Create('wrong argument'); + + Result := self.FlogTable[a]; +end; + +function TGenericGF.multiply(a, b: Integer): Integer; +begin + if ((a = 0) or (b = 0)) then + begin + Result := 0; + exit + end; + + Result := self.FexpTable + [((self.FlogTable[a] + self.FlogTable[b]) mod (self.Fsize - 1))]; + +end; + +function TGenericGF.ToString: string; +begin + Result := 'GF(0x' + Fprimitive.ToString() + ',' + size.ToString() + ')'; +end; + +/// ///////////////////////////////////////////////////////////////////////////// + +constructor TGenericGFPoly.Create(Field: TGenericGF; + coefficients: TArray); +var + coefficientsLength, firstNonZero: Integer; + +begin + + coefficientsLength := Length(coefficients); + if (coefficientsLength = 0) then + raise EArgumentException.Create('Wrong arguments'); + + self.Ffield := Field; + + if ((coefficientsLength > 1) and (coefficients[0] = 0)) then + begin + firstNonZero := 1; + while (((firstNonZero < coefficientsLength) and + (coefficients[firstNonZero] = 0))) do + begin + inc(firstNonZero) + end; + + Fcoefficients := TArray.Create(); + if (firstNonZero = coefficientsLength) then + begin + SetLength(Fcoefficients, 1); + end + else + begin + SetLength(Fcoefficients, coefficientsLength - firstNonZero); + Fcoefficients := Copy(coefficients, firstNonZero, Length(Fcoefficients)); + end + end + else + Fcoefficients := coefficients +end; + +destructor TGenericGFPoly.Destroy; +begin + SetLength(Fcoefficients, 0); + Fcoefficients := nil; + + Ffield := nil; + + inherited; +end; + +function TGenericGFPoly.addOrSubtract(other: IGenericGFPoly): IGenericGFPoly; +var + lengthDiff, i, y: Integer; + smallerCoefficients, largerCoefficients, temp, sumDiff: TArray; +begin + + if (not self.Ffield.Equals(other.field)) then + raise EArgumentException.Create + ('GenericGFPolys do not have same GenericGF field'); + + if (self.isZero) then + begin + Result := other; + exit + end; + + if (other.isZero) then + begin + Result := self; + exit + end; + + smallerCoefficients := self.coefficients; + largerCoefficients := other.coefficients; + if (Length(smallerCoefficients) > Length(largerCoefficients)) then + begin + temp := smallerCoefficients; + smallerCoefficients := largerCoefficients; + largerCoefficients := temp + end; + + sumDiff := TArray.Create(); + SetLength(sumDiff, Length(largerCoefficients)); + lengthDiff := Length(largerCoefficients) - Length(smallerCoefficients); + + for y := 0 to lengthDiff - 1 do + begin + sumDiff[y] := largerCoefficients[y] + end; + + i := lengthDiff; + while (i < Length(largerCoefficients)) do + begin + sumDiff[i] := TGenericGF.addOrSubtract(smallerCoefficients[(i - lengthDiff) + ], largerCoefficients[i]); + inc(i) + end; + + Result := TGenericGFPoly.Create(self.Ffield, sumDiff); +end; + +function TGenericGFPoly.divide(other: IGenericGFPoly): TArray; +var + term, quotient, remainder, iterationQuotient: IGenericGFPoly; + degreeDifference, denominatorLeadingTerm, scale, + inverseDenominatorLeadingTerm: Integer; +begin + if (not self.Ffield.Equals(other.field)) then + raise EArgumentException.Create + ('GenericGFPolys do not have same GenericGF field'); + + if (other.isZero) then + raise EArgumentException.Create('Divide by 0'); + + quotient := self.Ffield.Zero; + remainder := self; + denominatorLeadingTerm := other.getCoefficient(other.degree); + inverseDenominatorLeadingTerm := self.Ffield.inverse(denominatorLeadingTerm); + + while (((remainder.degree >= other.degree) and not remainder.isZero)) do + begin + degreeDifference := (remainder.degree - other.degree); + scale := self.Ffield.multiply(remainder.getCoefficient(remainder.degree), + inverseDenominatorLeadingTerm); + term := other.multiplyByMonomial(degreeDifference, scale); + iterationQuotient := self.Ffield.buildMonomial(degreeDifference, scale); + quotient := quotient.addOrSubtract(iterationQuotient); + remainder := remainder.addOrSubtract(term) + end; + + Result := TArray.Create(quotient, remainder); +end; + +function TGenericGFPoly.evaluateAt(a: Integer): Integer; +var + size, coefficient, i, y, l: Integer; + +begin + Result := 0; + if (a = 0) then + begin + Result := self.getCoefficient(0); + exit + end; + + size := Length(self.coefficients); + if (a = 1) then + begin + + l := Length(self.coefficients) - 1; + for y := 0 to l do + begin + coefficient := coefficients[y]; + Result := TGenericGF.addOrSubtract(Result, coefficient) + end; + + exit + end; + + Result := self.coefficients[0]; + i := 1; + while ((i < size)) do + begin + Result := TGenericGF.addOrSubtract(self.Ffield.multiply(a, Result), + self.coefficients[i]); + inc(i) + end; + +end; + +function TGenericGFPoly.getCoefficient(degree: Integer): Integer; +begin + Result := Fcoefficients[Length(Fcoefficients) - 1 - degree] +end; + +function TGenericGFPoly.get_coefficients: TArray; +begin + Result := fcoefficients; +end; + +function TGenericGFPoly.get_Degree: Integer; +begin + Result := Length(Fcoefficients) - 1; +end; + +function TGenericGFPoly.get_field: TGenericGF; +begin + Result := FField; +end; + +function TGenericGFPoly.get_isZero: boolean; +begin + Result := Fcoefficients[0] = 0; +end; + +function TGenericGFPoly.multiply(other: IGenericGFPoly): IGenericGFPoly; +var + product, aCoefficients, bCoefficients: TArray; + aLength, bLength, i, aCoeff, j: Integer; +begin + + if (not self.Ffield.Equals(other.field)) then + raise EArgumentException.Create + ('GenericGFPolys do not have same GenericGF field'); + + if (self.isZero or other.isZero) then + begin + Result := self.Ffield.Zero; + exit + end; + + aCoefficients := self.coefficients; + aLength := Length(aCoefficients); + bCoefficients := other.coefficients; + bLength := Length(bCoefficients); + product := TArray.Create(); + SetLength(product, (aLength + bLength) - 1); + i := 0; + + while ((i < aLength)) do + begin + aCoeff := aCoefficients[i]; + j := 0; + while ((j < bLength)) do + begin + product[(i + j)] := TGenericGF.addOrSubtract(product[(i + j)], + self.Ffield.multiply(aCoeff, bCoefficients[j])); + inc(j) + end; + inc(i) + end; + + Result := TGenericGFPoly.Create(self.Ffield, product); + +end; + +function TGenericGFPoly.multiply(scalar: Integer): IGenericGFPoly; +var + product: TArray; + size, i: Integer; +begin + + if (scalar = 0) then + begin + Result := self.Ffield.Zero; + exit + end; + + if (scalar = 1) then + begin + Result := self; + exit + end; + + size := Length(self.coefficients); + product := TArray.Create(); + SetLength(product, size); + i := 0; + while ((i < size)) do + begin + product[i] := self.Ffield.multiply(self.coefficients[i], scalar); + inc(i) + end; + + Result := TGenericGFPoly.Create(self.Ffield, product); + +end; + +function TGenericGFPoly.multiplyByMonomial(degree, coefficient: Integer) + : IGenericGFPoly; +var + product: TArray; + size, i: Integer; +begin + if (degree < 0) then + raise EArgumentException.Create('Wrong arguments'); + + if (coefficient = 0) then + begin + Result := self.Ffield.Zero; + exit + end; + + size := Length(self.coefficients); + product := TArray.Create(); + SetLength(product, size + degree); + i := 0; + + while ((i < size)) do + begin + product[i] := self.Ffield.multiply(self.coefficients[i], coefficient); + inc(i) + end; + + Result := TGenericGFPoly.Create(self.Ffield, product); +end; + +function TGenericGFPoly.ToString: string; +var + lResult: TStringBuilder; + degree, coefficient, alphaPower: Integer; + +begin + lResult := TStringBuilder.Create((8 * self.degree)); + degree := self.degree; + + while ((degree >= 0)) do + begin + + coefficient := self.getCoefficient(degree); + if (coefficient <> 0) then + begin + + if (coefficient < 0) then + begin + lResult.Append(' - '); + coefficient := -1 * coefficient + end + else if (Result.Length > 0) then + lResult.Append(' + '); + + if ((degree = 0) or (coefficient <> 1)) then + begin + alphaPower := self.Ffield.log(coefficient); + if (alphaPower = 0) then + lResult.Append('1') + else if (alphaPower = 1) then + lResult.Append('a') + else + begin + lResult.Append('a^'); + lResult.Append(alphaPower) + end + end; + + if (degree <> 0) then + if (degree = 1) then + lResult.Append('x') + else + begin + lResult.Append('x^'); + lResult.Append(degree) + end + end; + dec(degree) + end; + + Result := lResult.ToString(); +end; + +initialization + TGenericGF.InitializeClass(); +finalization + TGenericGF.FinalizeClass(); +end. diff --git a/android-client/ThirdParty/ZXing/Common/ReedSolomon/ZXing.Common.ReedSolomon.ReedSolomonDecoder.pas b/android-client/ThirdParty/ZXing/Common/ReedSolomon/ZXing.Common.ReedSolomon.ReedSolomonDecoder.pas new file mode 100644 index 0000000..0a68398 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ReedSolomon/ZXing.Common.ReedSolomon.ReedSolomonDecoder.pas @@ -0,0 +1,297 @@ +{ + * 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 Authors: Sean Owen and William Rucklidge + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.Common.ReedSolomon.ReedSolomonDecoder; + +interface + +uses + System.SysUtils, + // Hint: ZXing.Common.ReedSolomon.GenericGFPoly is implemented in GenericGF as second class + ZXing.Common.ReedSolomon.GenericGF; + +type + /// + /// Implements Reed-Solomon encoding, as the name implies. + /// + TReedSolomonDecoder = class sealed + public + constructor Create(field: TGenericGF); + public + function decode(received: TArray; twoS: Integer): boolean; + strict private + function findErrorLocations(errorLocator: IGenericGFPoly): TArray; + strict private + function findErrorMagnitudes(errorEvaluator: IGenericGFPoly; + errorLocations: TArray): TArray; + private + function runEuclideanAlgorithm(a: IGenericGFPoly; b: IGenericGFPoly; + pR: Integer): TArray; + + strict private + field: TGenericGF; + end; + +implementation + +{ TReedSolomonDecoder } + +constructor TReedSolomonDecoder.Create(field: TGenericGF); +begin + self.field := field +end; + +function TReedSolomonDecoder.decode(received: TArray; + twoS: Integer): boolean; +var + i, eval, position: Integer; + poly, syndrome, sigma, omega: IGenericGFPoly; + sigmaOmega: TArray; + errorLocations: TArray; + + syndromeCoefficients, errorMagnitudes: TArray; + noError: boolean; +begin + poly := TGenericGFPoly.Create(self.field, received); + + syndromeCoefficients := TArray.Create(); + SetLength(syndromeCoefficients, twoS); + + try + + noError := true; + i := 0; + while ((i < twoS)) do + begin + eval := poly.evaluateAt(self.field.exp((i + self.field.GeneratorBase))); + syndromeCoefficients[((Length(syndromeCoefficients) - 1) - i)] := eval; + if (eval <> 0) then + noError := false; + inc(i) + end; + + if (noError) then + begin + Result := true; + Exit; + end; + + syndrome := TGenericGFPoly.Create(self.field, syndromeCoefficients); + sigmaOmega := self.runEuclideanAlgorithm(self.field.buildMonomial(twoS, 1), + syndrome, twoS); + + if (sigmaOmega = nil) then + begin + Result := false; + Exit + end; + + sigma := sigmaOmega[0]; + errorLocations := self.findErrorLocations(sigma); + if (errorLocations = nil) then + begin + Result := false; + Exit + end; + + omega := sigmaOmega[1]; + errorMagnitudes := self.findErrorMagnitudes(omega, errorLocations); + i := 0; + while (i < Length(errorLocations)) do + begin + position := ((Length(received) - 1) - self.field.log(errorLocations[i])); + if (position < 0) then + begin + Result := false; + Exit + end; + received[position] := TGenericGF.addOrSubtract(received[position], + errorMagnitudes[i]); + inc(i) + end; + + finally + SetLength(sigmaOmega, 0); + SetLength(syndromeCoefficients, 0); + end; + + Result := true; + +end; + +function TReedSolomonDecoder.findErrorLocations(errorLocator: IGenericGFPoly) + : TArray; +var + numErrors, e, i: Integer; + +begin + numErrors := errorLocator.Degree; + + if (numErrors = 1) then + begin + Result := TArray.Create(errorLocator.getCoefficient(1)); + Exit + end; + + Result := TArray.Create(); + SetLength(Result, numErrors); + + e := 0; + i := 1; + + while (((i < self.field.Size) and (e < numErrors))) do + begin + + if (errorLocator.evaluateAt(i) = 0) then + begin + Result[e] := self.field.inverse(i); + inc(e) + end; + + inc(i); + + end; + + if (e <> numErrors) then + begin + Result := nil; + end; + +end; + +function TReedSolomonDecoder.findErrorMagnitudes(errorEvaluator: IGenericGFPoly; + errorLocations: TArray): TArray; +var + s, i, xiInverse, denominator, j, term, termPlus1: Integer; + +begin + s := Length(errorLocations); + Result := TArray.Create(); + SetLength(Result, s); + + i := 0; + while ((i < s)) do + begin + xiInverse := self.field.inverse(errorLocations[i]); + denominator := 1; + j := 0; + while ((j < s)) do + begin + if (i <> j) then + begin + term := self.field.multiply(errorLocations[j], xiInverse); + + if ((term and 1) = 0) then + begin + termPlus1 := (term or 1) + end + else + begin + termPlus1 := (term and (not 1)); + end; + + denominator := self.field.multiply(denominator, termPlus1) + + end; + inc(j) + end; + + Result[i] := self.field.multiply(errorEvaluator.evaluateAt(xiInverse), + self.field.inverse(denominator)); + + if (self.field.GeneratorBase <> 0) then + Result[i] := self.field.multiply(Result[i], xiInverse); + + inc(i) + end; + +end; + +function TReedSolomonDecoder.runEuclideanAlgorithm(a, b: IGenericGFPoly; + pR: Integer): TArray; +var + temp, rLastLast, tLastLast, rLast, tLast, t, q, sigma, omega, + R: IGenericGFPoly; + denominatorLeadingTerm, dltInverse, degreeDiff, scale, inverse, + sigmaTildeAtZero: Integer; +begin + + if (a.Degree < b.Degree) then + begin + temp := a; + a := b; + b := temp + end; + + rLast := a; + R := b; + tLast := self.field.Zero; + t := self.field.One; + + while ((R.Degree >= (pR div 2))) do + begin + rLastLast := rLast; + tLastLast := tLast; + rLast := R; + tLast := t; + + if (rLast.isZero) then + begin + Result := nil; + Exit + end; + + R := rLastLast; + q := self.field.Zero; + denominatorLeadingTerm := rLast.getCoefficient(rLast.Degree); + dltInverse := self.field.inverse(denominatorLeadingTerm); + + while (((R.Degree >= rLast.Degree) and not R.isZero)) do + begin + degreeDiff := (R.Degree - rLast.Degree); + scale := self.field.multiply(R.getCoefficient(R.Degree), dltInverse); + q := q.addOrSubtract(self.field.buildMonomial(degreeDiff, scale)); + R := R.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)) + end; + + t := q.multiply(tLast).addOrSubtract(tLastLast); + + if (R.Degree >= rLast.Degree) then + begin + Result := nil; + Exit + end + end; + + sigmaTildeAtZero := t.getCoefficient(0); + if (sigmaTildeAtZero = 0) then + begin + Result := nil; + Exit + end; + + inverse := self.field.inverse(sigmaTildeAtZero); + sigma := t.multiply(inverse); + omega := R.multiply(inverse); + + Result := TArray.Create(sigma, omega); + +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXIng.ByteSegments.pas b/android-client/ThirdParty/ZXing/Common/ZXIng.ByteSegments.pas new file mode 100644 index 0000000..cad8a76 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXIng.ByteSegments.pas @@ -0,0 +1,96 @@ +unit ZXIng.ByteSegments; +interface + +type + /// + /// implements the ByteSegments (which was declared as a TList> + /// throughout the code as reference-counted interface object) + /// + IByteSegments = Interface + ['{0994FC90-E8F5-40D8-8A48-9B05DFFF2635}'] + function Count:integer; + procedure Clear; + function GetCapacity: integer; + procedure SetCapacity(const Value: integer); + property Capacity:integer read GetCapacity write SetCapacity; + function Add(const item:TArray):integer; + function Get(index: integer):TArray; + end; + + +function ByteSegmentsCreate:IByteSegments; + +implementation +uses system.SysUtils, + Generics.Collections; + +type + TByteSegments = class(TInterfacedObject,IByteSegments) + private + FList: TList>; + function Count:integer; + procedure Clear; + constructor Create; + function GetCapacity: integer; + procedure SetCapacity(const Value: integer); + function Add(const item:TArray):integer; + function Get(index: integer):TArray; + public + destructor Destroy; override; + end; + + + + +function ByteSegmentsCreate:IByteSegments; +begin + result := TByteSegments.Create; + +end; + + +{ TByteSegments } + +function TByteSegments.Add(const item: TArray): integer; +begin + result := FList.Add(item); +end; + +procedure TByteSegments.Clear; +begin + FList.Clear; +end; + +function TByteSegments.Count: integer; +begin + result := FList.Count; +end; + +constructor TByteSegments.Create; +begin + FList := TList>.Create; + inherited Create; +end; + +destructor TByteSegments.Destroy; +begin + FList.Free; + inherited; +end; + +function TByteSegments.GetCapacity: integer; +begin + result := FList.Capacity; +end; + +procedure TByteSegments.SetCapacity(const Value: integer); +begin + FList.Capacity := value; +end; + +function TByteSegments.Get(index: Integer) : TArray; +begin + Result := FList[index]; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.BarcodeFormat.pas b/android-client/ThirdParty/ZXing/Common/ZXing.BarcodeFormat.pas new file mode 100644 index 0000000..f5035d5 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.BarcodeFormat.pas @@ -0,0 +1,89 @@ +{ + * 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. + + * Implemented by E. Spelt for Delphi +} + +unit ZXing.BarcodeFormat; + +interface + +type + TBarcodeFormat = ( + /// No format set. All formats will be used + Auto = 0, + + /// Aztec 2D barcode format. + AZTEC = 1, + + /// CODABAR 1D format. + CODABAR = 2, + + /// Code 39 1D format. + CODE_39 = 4, + + /// Code 93 1D format. + CODE_93 = 8, + + /// Code 128 1D format. + CODE_128 = 16, + + /// Data Matrix 2D barcode format. + DATA_MATRIX = 32, + + /// EAN-8 1D format. + EAN_8 = 64, + + /// EAN-13 1D format. + EAN_13 = 128, + + /// ITF (Interleaved Two of Five) 1D format. + ITF = 256, + + /// MaxiCode 2D barcode format. + MAXICODE = 512, + + /// PDF417 format. + PDF_417 = 1024, + + /// QR Code 2D barcode format. + QR_CODE = 2048, + + /// RSS 14 + RSS_14 = 4096, + + /// RSS EXPANDED + RSS_EXPANDED = 8192, + + /// UPC-A 1D format. + UPC_A = 16384, + + /// UPC-E 1D format. + UPC_E = 32768, + + /// UPC/EAN extension format. Not a stand-alone format. + UPC_EAN_EXTENSION = 65536, + + /// MSI + MSI = 131072, + + /// Plessey + PLESSEY = 262144 + + ); + +implementation + +end. \ No newline at end of file diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.BitSource.pas b/android-client/ThirdParty/ZXing/Common/ZXing.BitSource.pas new file mode 100644 index 0000000..22a7442 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.BitSource.pas @@ -0,0 +1,110 @@ +unit ZXing.BitSource; + +{ + * 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. + + * Implemented by E. Spelt for Delphi +} +interface + +uses + SysUtils, + ZXing.Common.Detector.MathUtils; + +type + + TBitSource = class sealed + private + bytes: TArray; + public + BitOffset: Integer; + ByteOffset: Integer; + constructor Create(bytes: TArray); + function available: Integer; + function readBits(numBits: Integer): Integer; + end; + +implementation + +{ TBitSource } + +function TBitSource.available: Integer; +begin + Result := 8 * (Length(self.bytes) - self.ByteOffset) - self.BitOffset; +end; + +constructor TBitSource.Create(bytes: TArray); +begin + self.bytes := bytes; +end; + +function TBitSource.readBits(numBits: Integer): Integer; +var + bitsToNotRead, bitsLeft, toRead, mask: Integer; +begin + if (((numBits < 1) or (numBits > $20)) or (numBits > available())) then + raise EArgumentException.Create(numBits.ToString + 'numBits'); + + Result := 0; + if (BitOffset > 0) then + begin + + bitsLeft := 8 - BitOffset; + if (numBits < bitsLeft) then + toRead := numBits + else + toRead := bitsLeft; + + bitsToNotRead := (bitsLeft - toRead); + mask := TMathUtils.Asr($FF, ((8 - toRead) and $1F)) shl bitsToNotRead; + Result := TMathUtils.Asr((self.bytes[self.ByteOffset] and mask), + bitsToNotRead); + + dec(numBits, toRead); + inc(BitOffset, toRead); + + if (BitOffset = 8) then + begin + BitOffset := 0; + inc(ByteOffset) + end + end; + + if (numBits > 0) then + begin + + while ((numBits >= 8)) do + begin + Result := ((Result shl 8) or (self.bytes[self.ByteOffset] and $FF)); + inc(self.ByteOffset); + dec(numBits, 8) + end; + + if (numBits > 0) then + begin + bitsToNotRead := 8 - numBits; + mask := TMathUtils.Asr($FF, bitsToNotRead) shl bitsToNotRead; + + Result := (Result shl numBits) or + TMathUtils.Asr((bytes[ByteOffset] and mask), bitsToNotRead); + + inc(BitOffset, numBits) + end + + end; + +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.CharacterSetECI.pas b/android-client/ThirdParty/ZXing/Common/ZXing.CharacterSetECI.pas new file mode 100644 index 0000000..db71937 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.CharacterSetECI.pas @@ -0,0 +1,180 @@ +unit ZXing.CharacterSetECI; + +{ + * 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. + + * Implemented by E. Spelt for Delphi +} +interface + +uses SysUtils, Generics.Collections; + +type + + TECI = class abstract + private + value_Renamed: Integer; + constructor Create(value_Renamed: Integer); + public + class function getECIByValue(value_Renamed: Integer): TECI; static; + property value: Integer read value_Renamed; + end; + + TCharacterSetECI = class sealed(TECI) + strict private + FEncodingName: string; + class var NAME_TO_ECI: TDictionary; + class var VALUE_TO_ECI: TDictionary; + /// + /// this objectlist is just for doing proper deallocation of TCharacterSetECI instances under Win32/Win64, + /// without having to mess with TInterfacedObject. Since instances are meant to exist for the whole program life, there's no need of doing + /// anything much more complicated than this. + /// + class var AllocatedInstances:TObjectList; + + class constructor Create; + constructor Create(value: Integer; encodingName: string); overload; + class destructor Destroy; + + class procedure addCharacterSet(value: Integer; encodingNames: TArray); static; + + public + + property encodingName: string read FEncodingName; + + class function getCharacterSetECIByName(name: string) + : TCharacterSetECI; static; + class function getCharacterSetECIByValue(value: Integer) + : TCharacterSetECI; static; + + end; + +implementation + +{ TECI } + +constructor TECI.Create(value_Renamed: Integer); +begin + self.value_Renamed := value_Renamed +end; + +class function TECI.getECIByValue(value_Renamed: Integer): TECI; +begin + if ((value_Renamed < 0) or (value_Renamed > $F423F)) then + raise EArgumentException.Create('Bad ECI value: ' + + value_Renamed.ToString()); + + if (value_Renamed < 900) then + begin + Result := TCharacterSetECI.getCharacterSetECIByValue(value_Renamed); + exit + end; + + Result := nil; +end; + +{ TCharacterSetECI } + +constructor TCharacterSetECI.Create(value: Integer; encodingName: string); +begin + inherited Create(value); + FEncodingName := encodingName; + AllocatedInstances.Add(self); // add the instance to the global list of all created instances +end; + +class destructor TCharacterSetECI.Destroy; +begin + NAME_TO_ECI.Free; + VALUE_TO_ECI.Free; + + if AllocatedInstances<>nil then begin + AllocatedInstances.Clear; + AllocatedInstances.Free; +end; + +end; + +class constructor TCharacterSetECI.Create; +begin + NAME_TO_ECI:=TDictionary.Create; + VALUE_TO_ECI:=TDictionary.Create; + // under Win32/64 TObjectList by default "OWNS" the objects it contains: + // if we clear the list, the objects contained get automatically destroyed + AllocatedInstances:= TObjectList.Create; + + TCharacterSetECI.addCharacterSet( 0, ['CP437']); + TCharacterSetECI.addCharacterSet( 1, ['ISO-8859-1','ISO8859_1']); + TCharacterSetECI.addCharacterSet( 2, ['CP437']); + TCharacterSetECI.addCharacterSet( 3, ['ISO-8859-1', 'ISO8859_1']); + TCharacterSetECI.addCharacterSet( 4, ['ISO-8859-2', 'ISO8859_2']); + TCharacterSetECI.addCharacterSet( 5, ['ISO-8859-3', 'ISO8859_3']); + TCharacterSetECI.addCharacterSet( 6, ['ISO-8859-4', 'ISO8859_4']); + TCharacterSetECI.addCharacterSet( 7, ['ISO-8859-5', 'ISO8859_5']); + TCharacterSetECI.addCharacterSet( 8, ['ISO-8859-6', 'ISO8859_6']); + TCharacterSetECI.addCharacterSet( 9, ['ISO-8859-7', 'ISO8859_7']); + TCharacterSetECI.addCharacterSet( 10, ['ISO-8859-8', 'ISO8859_8']); + TCharacterSetECI.addCharacterSet( 11, ['ISO-8859-9', 'ISO8859_9']); + TCharacterSetECI.addCharacterSet( 12, ['ISO-8859-4', 'ISO-8859-10', 'ISO8859_10']); + TCharacterSetECI.addCharacterSet( 13, ['ISO-8859-11', 'ISO8859_11']); + TCharacterSetECI.addCharacterSet( 15, ['ISO-8859-13', 'ISO8859_13']); + TCharacterSetECI.addCharacterSet($10, ['ISO-8859-1', 'ISO-8859-14', 'ISO8859_14']); + TCharacterSetECI.addCharacterSet($11, ['ISO-8859-15', 'ISO8859_15']); + TCharacterSetECI.addCharacterSet($12, ['ISO-8859-3', 'ISO-8859-16', 'ISO8859_16']); + TCharacterSetECI.addCharacterSet( 20, ['SJIS', 'Shift_JIS']); + TCharacterSetECI.addCharacterSet($15, ['WINDOWS-1250','CP1250']); + TCharacterSetECI.addCharacterSet($16, ['WINDOWS-1251','CP1251']); + TCharacterSetECI.addCharacterSet($17, ['WINDOWS-1252','CP1252']); + TCharacterSetECI.addCharacterSet($18, ['WINDOWS-1256', 'CP1256']); + TCharacterSetECI.addCharacterSet($19, ['UTF-16BE','UNICODEBIG']); + TCharacterSetECI.addCharacterSet($1A, ['UTF-8', 'UTF8']); + TCharacterSetECI.addCharacterSet($1B, ['US-ASCII']); + TCharacterSetECI.addCharacterSet(170, ['US-ASCII']); + TCharacterSetECI.addCharacterSet($1C, ['BIG5']); + TCharacterSetECI.addCharacterSet($1D, ['GB18030', 'GB2312', 'EUC_CN', 'GBK'] ); + TCharacterSetECI.addCharacterSet( 30, ['EUC-KR', 'EUC_KR']); + +end; + +class procedure TCharacterSetECI.addCharacterSet(value: Integer; encodingNames: TArray); +var + t: string; + Eci: TCharacterSetECI; +begin + Eci := TCharacterSetECI.Create(value, encodingNames[0]); + TCharacterSetECI.VALUE_TO_ECI.AddOrSetValue(value,Eci); // note : VALUE_TO_ECI[value] := Eci raises "key not found exception": it cant' be used for adding not existing values + + for t in encodingNames do + TCharacterSetECI.NAME_TO_ECI.AddOrSetValue(t,Eci); +end; + +class function TCharacterSetECI.getCharacterSetECIByName(name: string) + : TCharacterSetECI; +begin + Result := TCharacterSetECI.NAME_TO_ECI[name.ToUpper] +end; + +class function TCharacterSetECI.getCharacterSetECIByValue(value: Integer) + : TCharacterSetECI; +begin + if ((value < 0) or (value >= 900)) then + begin + Result := nil; + exit + end; + + Result := TCharacterSetECI.VALUE_TO_ECI[value]; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitArray.pas b/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitArray.pas new file mode 100644 index 0000000..f18fc8c --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitArray.pas @@ -0,0 +1,70 @@ +{ + * 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 E. Spelt and K. Gossens +} + +unit ZXing.Common.BitArray; + +interface + +type + IBitArray = interface + ['{3D65F451-E408-4015-A637-73CD05877BCB}'] + // property getters and setters + function GetBit(i: Integer): Boolean; + procedure SetBit(i: Integer; Value: Boolean); + function GetBits: TArray; + + function Size: Integer; + function SizeInBytes: Integer; + + property Self[i: Integer]: Boolean read GetBit write SetBit; default; + property Bits: TArray read GetBits; + + function getNextSet(from: Integer): Integer; + function getNextUnset(from: Integer): Integer; + + procedure setBulk(i, newBits: Integer); + procedure setRange(start, ending: Integer); + procedure appendBit(bit: Boolean); + procedure Reverse(); + procedure clear(); + + function isRange(start, ending: Integer; const value: Boolean): Boolean; + end; + + TBitArrayHelpers = class + class function CreateBitArray:IBitArray; overload; + class function CreateBitArray(const Size: Integer):IBitArray; overload; + end; + +implementation +uses ZXing.Common.BitArrayImplementation; + +class function TBitArrayHelpers.CreateBitArray:IBitArray; +begin + result := ZXing.Common.BitArrayImplementation.NewBitArray; +end; + + +class function TBitArrayHelpers.CreateBitArray(const Size: Integer):IBitArray; +begin + result := ZXing.Common.BitArrayImplementation.NewBitArray(size); +end; + + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitArrayImplementation.pas b/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitArrayImplementation.pas new file mode 100644 index 0000000..a7222c7 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitArrayImplementation.pas @@ -0,0 +1,468 @@ +unit ZXing.Common.BitArrayImplementation; + +interface +uses ZXing.Common.BitArray; + +function NewBitArray:IBitArray; overload; +function NewBitArray(const Size: Integer):IBitArray; overload; + +implementation +uses + System.SysUtils, + ZXing.Common.Detector.MathUtils, + Math; + + +type + /// + /// A simple, fast array of bits, represented compactly by an array of ints internally. + /// + TBitArrayImplementation = class(TInterfacedObject, IBitArray) + strict private + _lookup: TArray; + Fbits: TArray; + Fsize: Integer; + procedure InitLookup(); + function GetBit(i: Integer): Boolean; + procedure SetBit(i: Integer; Value: Boolean); + function makeArray(Size: Integer): TArray; + procedure ensureCapacity(size: Integer); + + + function numberOfTrailingZeros(num: Integer): Integer; + function GetBits: TArray; + + private + constructor Create(); overload; + constructor Create(const Size: Integer); overload; + + public + function Size: Integer; + function SizeInBytes: Integer; + + property Self[i: Integer]: Boolean read GetBit write SetBit; default; + property Bits: TArray read Fbits; + + destructor Destroy; override; + function getNextSet(from: Integer): Integer; + function getNextUnset(from: Integer): Integer; + + procedure setBulk(i, newBits: Integer); + procedure setRange(start, ending: Integer); + procedure appendBit(bit: Boolean); + procedure Reverse(); + procedure clear(); + + function isRange(start, ending: Integer; + const value: Boolean): Boolean; + end; + + +constructor TBitArrayImplementation.Create; +begin + Fsize := 0; + SetLength(Fbits, 1); + InitLookup(); +end; + +constructor TBitArrayImplementation.Create(const Size: Integer); +begin + if (Size < 1) + then + raise EArgumentException.Create('size must be at least 1.'); + + Fsize := Size; + Fbits := makeArray(Size); + InitLookup(); +end; + +procedure TBitArrayImplementation.ensureCapacity(size: Integer); +var + newBits : TArray; +begin + if (size > TMathUtils.Asr(Length(Fbits), 5)) then + begin + newBits := makeArray(size); + Move(Fbits[0], newBits[0], Length(Fbits) * SizeOf(Fbits[0])); + Fbits := newBits; + end; +end; + +destructor TBitArrayImplementation.Destroy; +begin + Fbits := nil; + _lookup := nil; + inherited; +end; + +function TBitArrayImplementation.GetBit(i: Integer): Boolean; +begin + Result := ((Fbits[TMathUtils.Asr(i, 5)]) and (1 shl (i and $1F))) <> 0; +end; + +function TBitArrayImplementation.GetBits: TArray; +begin + result := FBits; +end; + +/// +/// Gets the next set. +/// +/// first bit to check +/// index of first bit that is set, starting from the given index, or size if none are set +/// at or beyond this given index +function TBitArrayImplementation.getNextSet(from: Integer): Integer; +var + bitsOffset, + currentBits : Integer; +begin + if (from >= Fsize) then + Exit(FSize); + + bitsOffset := TMathUtils.Asr(from, 5); + currentBits := Fbits[bitsOffset]; + // mask off lesser bits first + {$OVERFLOWCHECKS OFF} + currentBits := currentBits and -(1 shl (from and $1F)); + {$OVERFLOWCHECKS ON} + + while (currentBits = 0) do + begin + Inc(bitsOffset); + if (bitsOffset = Length(Fbits)) then + Exit(FSize); + + currentBits := Fbits[bitsOffset]; + end; + + Result := (bitsOffset shl 5) + numberOfTrailingZeros(currentBits); + Result := Math.Min(Result, FSize); +end; + +/// +/// see getNextSet(int) +/// +/// index to start looking for unset bit +/// index of next unset bit, or if none are unset until the end +function TBitArrayImplementation.getNextUnset(from: Integer): Integer; +var + bitsOffset, + currentBits: Integer; +begin + if (from >= Fsize) then + begin + Result := Fsize; + exit; + end; + bitsOffset := TMathUtils.Asr(from, 5); + currentBits := not Fbits[bitsOffset]; + + // mask off lesser bits first + {$OVERFLOWCHECKS OFF} + currentBits := currentBits and -(1 shl (from and $1F)); + {$OVERFLOWCHECKS ON} + + while (currentBits = 0) do + begin + Inc(bitsOffset); + if (bitsOffset = Length(Fbits)) then + begin + Result := Size; + exit; + end; + currentBits := not Fbits[bitsOffset]; + end; + Result := (bitsOffset shl 5) + numberOfTrailingZeros(currentBits); + + if (Result > Size) + then + Result := Size; +end; + +procedure TBitArrayImplementation.InitLookup; +begin + _lookup := TArray.Create(32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, + 28, 11, 0, 13, 4, 7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, + 20, 8, 19, 18); +end; + +function TBitArrayImplementation.makeArray(Size: Integer): TArray; +var + ar: TArray; +begin + SetLength(ar, TMathUtils.Asr((Size + 31), 5)); + Result := ar; +end; + +function TBitArrayImplementation.numberOfTrailingZeros(num: Integer): Integer; +var + index: Integer; +begin + Result := 0; + +{$OVERFLOWCHECKS OFF} + index := (-num and num) mod 37; + if (index < 0) then + begin + index := index * -1; + end; + + if (index >= Low(_lookup)) and (index <= High(_lookup)) then + Result := _lookup[index]; +{$OVERFLOWCHECKS ON} +end; + +procedure TBitArrayImplementation.Reverse; +var + newBits: TArray; + i, len, oldBitsLen, leftOffset, mask, nextInt, currentInt: Integer; + x: Int64; +begin + + SetLength(newBits, Length(Fbits)); + // reverse all int's first + len := TMathUtils.Asr((Size - 1), 5); + oldBitsLen := len + 1; + for i := 0 to oldBitsLen - 1 do + begin + x := Fbits[i]; + x := (TMathUtils.Asr(x, 1) and $55555555) or ((x and $55555555) shl 1); + x := (TMathUtils.Asr(x, 2) and $33333333) or ((x and $33333333) shl 2); + x := (TMathUtils.Asr(x, 4) and $0F0F0F0F) or ((x and $0F0F0F0F) shl 4); + x := (TMathUtils.Asr(x, 8) and $00FF00FF) or ((x and $00FF00FF) shl 8); + x := (TMathUtils.Asr(x, 16) and $0000FFFF) or ((x and $0000FFFF) shl 16); + newBits[len - i] := integer(x) ; + end; + // now correct the int's if the bit size isn't a multiple of 32 + if (Size <> oldBitsLen * 32) then + begin + leftOffset := oldBitsLen * 32 - Size; + mask := 1; + for i := 0 to 31 - leftOffset - 1 do + begin + mask := (mask shl 1) or 1; + end; + + currentInt := TMathUtils.Asr(newBits[0], leftOffset) and mask; + for i := 1 to oldBitsLen - 1 do + begin + nextInt := newBits[i]; + currentInt := currentInt or (nextInt shl (32 - leftOffset)); + newBits[i - 1] := currentInt; + currentInt := TMathUtils.Asr(nextInt, leftOffset) and mask; + end; + newBits[oldBitsLen - 1] := currentInt; + end; + + Fbits := newBits; +end; + +procedure TBitArrayImplementation.SetBit(i: Integer; Value: Boolean); +var + index: Integer; +begin + if (Value) then + begin + index := TMathUtils.Asr(i, 5); + Fbits[index] := Fbits[index] or 1 shl (i and $1F); + end; +end; + +function TBitArrayImplementation.Size: Integer; +begin + result := FSize; +end; + +function TBitArrayImplementation.SizeInBytes: Integer; +begin + Result := TMathUtils.Asr(Size + 7, 3); +end; + +/// Sets a block of 32 bits, starting at bit i. +/// +/// +/// first bit to set +/// +/// the new value of the next 32 bits. Note again that the least-significant bit +/// corresponds to bit i, the next-least-significant to i+1, and so on. +/// +procedure TBitArrayImplementation.setBulk(i, newBits: Integer); +var + r: Integer; +begin + r := TMathUtils.Asr(i, 5); + Fbits[r] := newBits; +end; + +/// +/// Sets a range of bits. +/// +/// start of range, inclusive. +/// end of range, exclusive +procedure TBitArrayImplementation.setRange(start, ending: Integer); +var + firstInt, + lastInt, + mask, + i, j : Integer; + firstBit, + lastBit : Integer; +begin + if (ending < start) + then + raise EArgumentException.Create('Start is greater than end'); + + if (ending = start) + then + exit; + Dec(ending); // will be easier to treat this as the last actually set bit -- inclusive + firstInt := TMathUtils.Asr(start, 5); + lastInt := TMathUtils.Asr(ending, 5); + for i := firstInt to lastInt do + begin + if (i > firstInt) + then + firstBit := start + else + firstBit := $1F; + if (i < lastInt) + then + lastBit := 31 + else + lastBit := (ending and $1F); + + if ((firstBit = 0) and (lastBit = 31)) + then + mask := -1 + else + begin + mask := 0; + for j := firstBit to lastBit do + begin + mask := (mask or (1 shl j)); + end; + end; + bits[i] := (bits[i] or mask); + end; +end; + +/// Clears all bits (sets to false). +procedure TBitArrayImplementation.Clear; +var + max, + i: Integer; +begin + max := Length(Fbits); + for i := 0 to Pred(max) do + begin + Fbits[i] := 0; + end; +end; + +/// Efficient method to check if a range of bits is set, or not set. +/// +/// +/// start of range, inclusive. +/// +/// end of range, exclusive +/// +/// if true, checks that bits in range are set, otherwise checks that they are not set +/// +/// true iff all bits are set or not set in range, according to value argument +/// +/// EIllegalArgumentException if end is less than or equal to start +function TBitArrayImplementation.isRange(start, ending: Integer; + const value: Boolean): Boolean; +var + firstInt, + lastInt, + firstBit, + lastBit, + mask, + i, j, + temp: Integer; +begin + if (ending = start) then + begin + Result := true; // empty range matches + exit; + end; + Dec(ending); // will be easier to treat this as the last actually set bit -- inclusive + + firstInt := TMathUtils.Asr(start, 5); + lastInt := TMathUtils.Asr(ending, 5); + for i := firstInt to lastInt do + begin + if (i > firstInt) + then + firstBit := 0 + else + firstBit := (start and $1F); + + if (i < lastInt) + then + lastBit := 31 + else + lastBit := (ending and $1F); + + if ((firstBit = 0) and (lastBit = 31)) + then + mask := -1 + else + begin + mask := 0; + for j := firstBit to lastBit do + mask := mask or (1 shl j); + end; + + // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, + // equals the mask, or we're looking for 0s and the masked portion is not all 0s + if (Value) + then + temp := mask + else + temp := 0; + + if ((Fbits[i] and mask) <> (temp)) then + begin + Result := False; + exit; + end; + end; + + Result := true; +end; + +/// +/// Appends the bit. +/// +/// The bit. +procedure TBitArrayImplementation.appendBit(bit: Boolean); +var + i: Integer; +begin + ensureCapacity(Fsize + 1); + if (bit) then + begin + i := TMathUtils.Asr(Fsize, 5); + bits[i] := (bits[i] or (Fsize and $1F)); + end; + Dec(Fsize); +end; + + + + +function NewBitArray:IBitArray; +begin + result := TBitArrayImplementation.Create; +end; + + +function NewBitArray(const Size: Integer):IBitArray; +begin + result := TBitArrayImplementation.Create(size); +end; + + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitMatrix.pas b/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitMatrix.pas new file mode 100644 index 0000000..509717d --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.Common.BitMatrix.pas @@ -0,0 +1,480 @@ +{ + * 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 Authors: Sean Owen and dswitkin@google.com (Daniel Switkin) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.Common.BitMatrix; + +interface + +uses + SysUtils, +{$IFDEF FRAMEWORK_FMX} + FMX.Graphics, +{$ENDIF} +{$IFDEF FRAMEWORK_VCL} + VCL.Graphics, +{$ENDIF} + Generics.Collections, + ZXing.Common.BitArray, + ZXing.BarcodeFormat, + ZXing.Helpers, + ZXing.Common.Detector.MathUtils; + +type + /// + ///

Represents a 2D matrix of bits. In function arguments below, and throughout the common + /// module, x is the column position, and y is the row position. The ordering is always x, y. + /// The origin is at the top-left.

+ ///

Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins + /// with a new int. This is done intentionally so that we can copy out a row into a BitArray very + /// efficiently.

+ ///

The ordering of bits is row-major. Within each int, the least significant bits are used first, + /// meaning they represent lower x values. This is compatible with BitArray's implementation.

+ ///
+ TBitMatrix = class sealed + private + Fbits: TArray; + Fheight: Integer; + FrowSize: Integer; + Fwidth: Integer; + + function getBit(x, y: Integer): Boolean; + procedure setBit(x, y: Integer; const value: Boolean); + + constructor Create(const width, height, rowSize: Integer; + const bits: TArray); overload; + public + constructor Create(const width, height: Integer); overload; + constructor Create(const dimension: Integer); overload; + destructor Destroy; override; + + procedure clear; + function Clone: TObject; + function Equals(obj: TObject): Boolean; override; + procedure flip(x: Integer; y: Integer); + function getBottomRightOnBit: TArray; + function getEnclosingRectangle: TArray; + function GetHashCode: Integer; override; + function getRow(const y: Integer; row: IBitArray): IBitArray; + function getTopLeftOnBit: TArray; + procedure Rotate180; + procedure setRegion(left: Integer; top: Integer; width: Integer; + height: Integer); + procedure setRow(y: Integer; row: IBitArray); + function ToBitmap: TBitmap; overload; + function ToBitmap(format: TBarcodeFormat; content: string) + : TBitmap; overload; + + property width: Integer read Fwidth; + property height: Integer read Fheight; + property Matrix[x, y: Integer]: Boolean read getBit write setBit; default; + // added for debugging + function ToString: string; override; + end; + +implementation + +{ TBitMatrix } + +function TBitMatrix.getBit(x, y: Integer): Boolean; +var + offset, v, bits, shift: Int64; + uBits: Cardinal; +begin + offset := y * FrowSize + TMathUtils.Asr(x, 5); + if ( offset >= Low( FBits ) ) and ( offset <= High( FBits ) ) then + begin + bits := Fbits[offset]; + uBits := Cardinal(bits); + shift := (x and $1F); + v := TMathUtils.Asr(uBits, shift); + Result := (v and 1) <> 0; + end + else + Result := False; +end; + +procedure TBitMatrix.setBit(x, y: Integer; const value: Boolean); +var + offset: NativeInt; +begin + if (value) then + begin + offset := y * FrowSize + TMathUtils.Asr(x, 5); + Fbits[offset] := Fbits[offset] or (1 shl (x and $1F)); + end + else + begin + offset := Trunc(y * FrowSize + (x / 32)); + Fbits[offset] := Fbits[offset] and (not(1 shl (x and $1F))); + end; +end; + +procedure TBitMatrix.clear; +var + max, i: Integer; +begin + max := Length(Fbits); + i := 0; + while ((i < max)) do + begin + Fbits[i] := 0; + Inc(i); + end; +end; + +function TBitMatrix.Clone: TObject; +var + b: TArray; +begin + b := TArray.Clone(Fbits); + Result := TBitMatrix.Create(Self.Fwidth, Self.Fheight, Self.FrowSize, b); +end; + +constructor TBitMatrix.Create(const width, height, rowSize: Integer; + const bits: TArray); +begin + if ((width < 1) or (height < 1)) then + raise EArgumentException.Create('Both dimensions must be greater than 0'); + + Self.Fwidth := width; + Self.Fheight := height; + Self.FrowSize := rowSize; + Self.Fbits := bits; +end; + +constructor TBitMatrix.Create(const width, height: Integer); +begin + if ((width < 1) or (height < 1)) then + raise EArgumentException.Create('Both dimensions must be greater than 0'); + + Self.Fwidth := width; + Self.Fheight := height; + Self.FrowSize := TMathUtils.Asr((width + $1F), 5); + SetLength(Self.Fbits, Self.FrowSize * height); + Self.clear; +end; + +constructor TBitMatrix.Create(const dimension: Integer); +begin + Self.Create(dimension, dimension); +end; + +destructor TBitMatrix.Destroy; +begin + Self.Fbits := nil; + inherited; +end; + +function TBitMatrix.Equals(obj: TObject): Boolean; +var + other: TBitMatrix; + i, l: Integer; +begin + if (not(obj is TBitMatrix)) then + begin + Result := false; + exit; + end; + + other := (obj as TBitMatrix); + if ((((Fwidth <> other.Fwidth) or (Fheight <> other.Fheight)) or + (FrowSize <> other.FrowSize)) or (Length(Fbits) <> Length(other.Fbits))) + then + begin + Result := false; + exit + end; + + i := 0; + l := Length(Fbits); + + while ((i < l)) do + begin + if (Fbits[i] <> other.Fbits[i]) then + begin + Result := false; + exit + end; + Inc(i) + end; + + Result := true; +end; + +procedure TBitMatrix.flip(x, y: Integer); +var + offset, s: Integer; +begin + s := TMathUtils.Asr(x, 5); + offset := ((y * FrowSize) + s); + Fbits[offset] := (Fbits[offset] xor (1 shl x)) +end; + +function TBitMatrix.getBottomRightOnBit: TArray; +var + bitsOffset, x, y, theBits, bit: Integer; +begin + bitsOffset := Length(Fbits) - 1; + while ((bitsOffset >= 0) and (Self.Fbits[bitsOffset] = 0)) do + begin + dec(bitsOffset) + end; + + if (bitsOffset < 0) then + begin + Result := nil; + exit + end; + + y := (bitsOffset div FrowSize); + x := ((bitsOffset mod FrowSize) shl 5); + theBits := Fbits[bitsOffset]; + bit := $1F; + + while ((TMathUtils.Asr(theBits, bit) = 0)) do + begin + dec(bit); + end; + + Inc(x, bit); + Result := TArray.Create(x, y); +end; + +function TBitMatrix.getEnclosingRectangle: TArray; +var + bit, left, top, right, bottom, y, x32, theBits, widthTmp, heightTmp: Integer; +begin + left := Self.Fwidth; + top := Self.Fheight; + right := -1; + bottom := -1; + y := 0; + + while ((y < Self.Fheight)) do + begin + x32 := 0; + + while ((x32 < Self.FrowSize)) do + begin + theBits := Self.Fbits[((y * Self.FrowSize) + x32)]; + + if (theBits <> 0) then + begin + + if (y < top) then + top := y; + + if (y > bottom) then + bottom := y; + + if ((x32 * $20) < left) then + begin + bit := 0; + while (((theBits shl ($1F - bit)) = 0)) do + begin + Inc(bit) + end; + if (((x32 * $20) + bit) < left) then + left := ((x32 * $20) + bit) + end; + + if (((x32 * $20) + $1F) > right) then + begin + bit := $1F; + while ((TMathUtils.Asr(theBits, bit) = 0)) do + begin + dec(bit) + end; + if (((x32 * $20) + bit) > right) then + right := ((x32 * $20) + bit) + end + end; + Inc(x32) + end; + Inc(y) + end; + + widthTmp := (right - left); + heightTmp := (bottom - top); + + if ((widthTmp < 0) or (heightTmp < 0)) then + begin + Result := nil; + exit; + end; + + Result := TArray.Create(left, top, widthTmp, heightTmp); +end; + +function TBitMatrix.GetHashCode: Integer; +var + bit, hash: Integer; +begin + hash := Self.Fwidth; + hash := (($1F * hash) + Self.Fwidth); + hash := (($1F * hash) + Self.Fheight); + hash := (($1F * hash) + Self.FrowSize); + + for bit in Self.Fbits do + begin + hash := (($1F * hash) + bit); // .GetHashCode + end; + + Result := hash; +end; + +function TBitMatrix.getRow(const y: Integer; row: IBitArray): IBitArray; +var + x, offset: Integer; +begin + if ((row = nil) or (row.Size < Self.Fwidth)) then + row := TBitArrayHelpers.CreateBitArray(Self.Fwidth) + else + row.clear; + offset := (y * Self.FrowSize); + x := 0; + + while ((x < Self.FrowSize)) do + begin + row.setBulk((x shl 5), Self.Fbits[(offset + x)]); + Inc(x) + end; + + Result := row; +end; + +function TBitMatrix.getTopLeftOnBit: TArray; +var + bitsOffset, x, y, theBits, bit: Integer; +begin + bitsOffset := 0; + + while (((bitsOffset < Length(Fbits)) and (Fbits[bitsOffset] = 0))) do + begin + Inc(bitsOffset) + end; + + if (bitsOffset = Length(Fbits)) then + begin + Result := nil; + exit + end; + + y := (bitsOffset div Self.FrowSize); + x := ((bitsOffset mod Self.FrowSize) shl 5); + theBits := Self.Fbits[bitsOffset]; + bit := 0; + + while (((theBits shl ($1F - bit)) = 0)) do + begin + Inc(bit) + end; + + Inc(x, bit); + Result := TArray.Create(x, y); +end; + +procedure TBitMatrix.Rotate180; +var + i, width, height: Integer; + topRow, bottomRow: IBitArray; +begin + width := Self.Fwidth; + height := Self.Fheight; + topRow := TBitArrayHelpers.CreateBitArray(width); + bottomRow := TBitArrayHelpers.CreateBitArray(width); + i := 0; + + while ((i < ((height + 1) div 2))) do + begin + topRow := Self.getRow(i, topRow); + bottomRow := Self.getRow(((height - 1) - i), bottomRow); + topRow.reverse; + bottomRow.reverse; + Self.setRow(i, bottomRow); + Self.setRow(((height - 1) - i), topRow); + Inc(i) + end; +end; + +procedure TBitMatrix.setRegion(left, top, width, height: Integer); +var + x, y, offset, right, bottom: Integer; +begin + if ((top < 0) or (left < 0)) then + raise EArgumentException.Create('Left and top must be non-negative'); + + if ((height < 1) or (width < 1)) then + raise EArgumentException.Create('Height and width must be at least 1'); + + right := (left + width); + bottom := (top + height); + + if ((bottom > Self.Fheight) or (right > Self.Fwidth)) then + raise EArgumentException.Create('The region must fit inside the matrix'); + + y := top; + + while ((y < bottom)) do + begin + offset := (y * Self.FrowSize); + x := left; + while ((x < right)) do + begin + Fbits[(offset + TMathUtils.Asr(x, 5))] := + (Fbits[(offset + TMathUtils.Asr(x, 5))] or (1 shl x)); + Inc(x) + end; + Inc(y) + end; +end; + +procedure TBitMatrix.setRow(y: Integer; row: IBitArray); +begin + Fbits := System.Copy(row.bits, (y * FrowSize), FrowSize); +end; + +function TBitMatrix.ToBitmap(format: TBarcodeFormat; content: string): TBitmap; +begin + raise ENotImplemented.Create('Converting to bitmap is not implemented yet!'); +end; + +function TBitMatrix.ToString: string; +var + r, c: Integer; +begin + for r := 0 to Fheight - 1 do + begin + for c := 0 to Fwidth - 1 do + begin + if Matrix[r, c] then + Result := Result + '*' + else + Result := Result + '.'; + end; + Result := Result + #13#10; + end; +end; + +function TBitMatrix.ToBitmap: TBitmap; +begin + Result := ToBitmap(TBarcodeFormat.CODE_128, '') +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.Common.DetectorResult.pas b/android-client/ThirdParty/ZXing/Common/ZXing.Common.DetectorResult.pas new file mode 100644 index 0000000..ba09002 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.Common.DetectorResult.pas @@ -0,0 +1,63 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.Common.DetectorResult; + +interface + +uses + System.SysUtils, + ZXing.Common.BitMatrix, + ZXing.ResultPoint; + +type + ///

Encapsulates the result of detecting a barcode in an image. This includes the raw + /// matrix of black/white pixels corresponding to the barcode, and possibly points of interest + /// in the image, like the location of finder patterns or corners of the barcode in the image.

+ ///
+ TDetectorResult = class + private + Fbits: TBitmatrix; + Fpoints: TArray; + public + constructor Create(const bits: TBitmatrix; const points: TArray); + destructor Destroy; override; + + property bits: TBitmatrix read Fbits; + property points: TArray read Fpoints; + end; + +implementation + +constructor TDetectorResult.Create(const bits: TBitmatrix; + const points: TArray); +begin + Fbits := bits; + Fpoints := points; +end; + +destructor TDetectorResult.Destroy; +begin + FPoints := nil; + FBits.Free; + inherited; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.Common.GridSampler.pas b/android-client/ThirdParty/ZXing/Common/ZXing.Common.GridSampler.pas new file mode 100644 index 0000000..10a42ad --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.Common.GridSampler.pas @@ -0,0 +1,159 @@ +{ + * 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. + + * Implemented by K. Gossens for Delphi +} + +unit ZXing.Common.GridSampler; + +interface + +uses + System.SysUtils, + ZXing.Common.Bitmatrix, + ZXing.Common.PerspectiveTransform; + +type + TGridSampler = class abstract + private + class var FgridSampler: TGridSampler; + //class constructor Create; + protected + constructor Create; + class function checkAndNudgePoints(image: TBitMatrix; points: TArray): boolean; static; + public + function sampleGrid(image: TBitMatrix; dimensionX: Integer; + dimensionY: Integer; transform: TPerspectiveTransform): TBitMatrix; overload; virtual; + function sampleGrid(image: TBitMatrix; dimensionX: Integer; + dimensionY: Integer; p1ToX: Single; p1ToY: Single; p2ToX: Single; + p2ToY: Single; p3ToX: Single; p3ToY: Single; p4ToX: Single; p4ToY: Single; + p1FromX: Single; p1FromY: Single; p2FromX: Single; p2FromY: Single; + p3FromX: Single; p3FromY: Single; p4FromX: Single; p4FromY: Single): TBitMatrix; overload; virtual; abstract; + procedure setGridSampler(newGridSampler: TGridSampler); //static; + + class property Instance: TGridSampler read FgridSampler; + end; + +implementation + +{ TGridSampler } + +constructor TGridSampler.Create; +begin + inherited Create; +end; + +class function TGridSampler.checkAndNudgePoints(image: TBitMatrix; + points: TArray): boolean; +var + width, + height : Integer; + nudged : Boolean; + offset, maxOffset : Integer; + x, y : Single; +begin + width := image.Width; + height := image.Height; + nudged := true; + offset := 0; + maxOffset := Length(points) - 1; // points.length must be even + + while ((offset < maxOffset) and nudged) do + begin + x := points[offset]; + y := points[(offset + 1)]; + if (((x < -1) or (x > width)) or ((y < -1) or (y > height))) then + begin + Result := false; + exit; + end; + nudged := false; + if (x = -1) then + begin + points[offset] := 0; + nudged := true; + end + else + if (x = width) then + begin + points[offset] := (width - 1); + nudged := true; + end; + if (y = -1) then + begin + points[(offset + 1)] := 0; + nudged := true; + end + else + if (y = height) then + begin + points[(offset + 1)] := (height - 1); + nudged := true; + end; + Inc(offset, 2) + end; + nudged := true; + offset := (Length(points) - 2); + while (((offset >= 0) and nudged)) do + begin + x := points[offset]; + y := points[(offset + 1)]; + if (((x < -1) or (x > width)) or ((y < -1) or (y > height))) then + begin + Result := false; + exit; + end; + nudged := false; + if (x = -1) then + begin + points[offset] := 0; + nudged := true; + end else + if (x = width) then + begin + points[offset] := (width - 1); + nudged := true; + end; + if (y = -1) then + begin + points[(offset + 1)] := 0; + nudged := true + end else + if (y = height) then + begin + points[(offset + 1)] := (height - 1); + nudged := true; + end; + dec(offset, 2) + end; + + Result := true; +end; + +function TGridSampler.sampleGrid(image: TBitMatrix; dimensionX: Integer; + dimensionY: Integer; transform: TPerspectiveTransform): TBitMatrix; +begin + raise ENotSupportedException.Create('Not yet supported'); +end; + +procedure TGridSampler.setGridSampler(newGridSampler: TGridSampler); +begin + if (newGridSampler = nil) + then + raise EArgumentException.Create('Missing arguments'); + FgridSampler := newGridSampler; +end; + +end. \ No newline at end of file diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.Common.PerspectiveTransform.pas b/android-client/ThirdParty/ZXing/Common/ZXing.Common.PerspectiveTransform.pas new file mode 100644 index 0000000..84fc3ef --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.Common.PerspectiveTransform.pas @@ -0,0 +1,248 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.Common.PerspectiveTransform; + +interface + +uses + System.SysUtils; + +type + ///

This class implements a perspective transform in two dimensions. Given four source and four + /// destination points, it will compute the transformation implied between them. The code is based + /// directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.

+ ///
+ TPerspectiveTransform = class sealed + private + a11: Single; + a12: Single; + a13: Single; + a21: Single; + a22: Single; + a23: Single; + a31: Single; + a32: Single; + a33: Single; + + function buildAdjoint(): TPerspectiveTransform; + function times(const other: TPerspectiveTransform): TPerspectiveTransform; + public + constructor Create(const a11, a21, a31, a12, a22, a32, a13, + a23, a33: Single); + + class function quadrilateralToQuadrilateral(const x0, y0, x1, y1, x2, y2, + x3, y3, x0p, y0p, x1p, y1p, x2p, y2p, + x3p, y3p: Single): TPerspectiveTransform; static; + + class function quadrilateralToSquare(x0: Single; y0: Single; x1: Single; + y1: Single; x2: Single; y2: Single; x3: Single; y3: Single) + : TPerspectiveTransform; static; + + class function squareToQuadrilateral(const x0, y0, x1, y1, x2, y2, + x3, y3: Single): TPerspectiveTransform; static; + + procedure transformPoints(var points: TArray); overload; + + /// Convenience method, not optimized for performance. + procedure transformPoints(const xValues, yValues: TArray); overload; + end; + +implementation + +constructor TPerspectiveTransform.Create(const a11, a21, a31, a12, a22, a32, + a13, a23, a33: Single); +begin + Self.a11 := a11; + Self.a12 := a12; + Self.a13 := a13; + Self.a21 := a21; + Self.a22 := a22; + Self.a23 := a23; + Self.a31 := a31; + Self.a32 := a32; + Self.a33 := a33; +end; + +class function TPerspectiveTransform.quadrilateralToQuadrilateral(const x0, y0, + x1, y1, x2, y2, x3, y3, x0p, y0p, x1p, y1p, x2p, y2p, + x3p, y3p: Single): TPerspectiveTransform; +var + qToS, + SToQ : TPerspectiveTransform; +begin + qToS := nil; + SToQ := nil; + try + qToS := TPerspectiveTransform.quadrilateralToSquare(x0, y0, x1, y1, x2, + y2, x3, y3); + SToQ := TPerspectiveTransform.squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, + y2p, x3p, y3p); + + Result := SToQ.times(qToS); + finally + + //if (SToQ <> nil) + //then + SToQ.Free; + + //if (qToS <> nil) + //then + qToS.Free; + end; +end; + +class function TPerspectiveTransform.quadrilateralToSquare(x0: Single; + y0: Single; x1: Single; y1: Single; x2: Single; y2: Single; x3: Single; + y3: Single): TPerspectiveTransform; +var + SToQ: TPerspectiveTransform; +begin + SToQ := nil; + // Here, the adjoint serves as the inverse: + try + SToQ := TPerspectiveTransform.squareToQuadrilateral(x0, y0, x1, y1, x2, + y2, x3, y3); + + Result := SToQ.buildAdjoint; + finally + //if (SToQ <> nil) + //then + SToQ.Free; + end; +end; + +class function TPerspectiveTransform.squareToQuadrilateral(const x0, y0, + x1, y1, x2, y2, x3, y3: Single): TPerspectiveTransform; +var + dx1, dx2, + dx3, dy1, + dy2, dy3, + a13, a23, + denominator: Single; +begin + dx3 := (((x0 - x1) + x2) - x3); + dy3 := (((y0 - y1) + y2) - y3); + + if ((dx3 = 0) and (dy3 = 0)) then + begin + Result := TPerspectiveTransform.Create((x1 - x0), (x2 - x1), x0, (y1 - y0), + (y2 - y1), y0, 0, 0, 1); + end else + begin + dx1 := (x1 - x2); + dx2 := (x3 - x2); + dy1 := (y1 - y2); + dy2 := (y3 - y2); + denominator := ((dx1 * dy2) - (dx2 * dy1)); + if denominator = 0 then + begin + a13 := 0; + a23 := 0; + end + else + begin + a13 := (((dx3 * dy2) - (dx2 * dy3)) / denominator); + a23 := (((dx1 * dy3) - (dx3 * dy1)) / denominator); + end; + Result := TPerspectiveTransform.Create(((x1 - x0) + (a13 * x1)), + ((x3 - x0) + (a23 * x3)), x0, ((y1 - y0) + (a13 * y1)), + ((y3 - y0) + (a23 * y3)), y0, a13, a23, 1); + end; +end; + +procedure TPerspectiveTransform.transformPoints(var points: TArray); +var + max, i: Integer; + x, y, + denominator: Single; +begin + + + a11 := Self.a11; + a12 := Self.a12; + a13 := Self.a13; + a21 := Self.a21; + a22 := Self.a22; + a23 := Self.a23; + a31 := Self.a31; + a32 := Self.a32; + a33 := Self.a33; + i := 0; + max := Length(points) - 1; + while ((i < max)) do + begin + x := points[i]; + y := points[(i + 1)]; + denominator := (((a13 * x) + (a23 * y)) + a33); + points[i] := ((((a11 * x) + (a21 * y)) + a31) / denominator); + points[(i + 1)] := ((((a12 * x) + (a22 * y)) + a32) / denominator); + Inc(i, 2); + end +end; + +procedure TPerspectiveTransform.transformPoints(const xValues, + yValues: TArray); +var + n, i: Integer; + x, y, denominator: Single; +begin + n := Length(xValues); + for i := 0 to Pred(n) do + begin + x := xValues[i]; + y := yValues[i]; + denominator := (((self.a13 * x) + (self.a23 * y)) + self.a33); + xValues[i] := ((((self.a11 * x) + (self.a21 * y)) + self.a31) / + denominator); + yValues[i] := ((((self.a12 * x) + (self.a22 * y)) + self.a32) / + denominator); + end +end; + +function TPerspectiveTransform.buildAdjoint(): TPerspectiveTransform; +begin + // Adjoint is the transpose of the cofactor matrix: + Result := TPerspectiveTransform.Create(a22 * a33 - a23 * a32, + a23 * a31 - a21 * a33, + a21 * a32 - a22 * a31, + a13 * a32 - a12 * a33, + a11 * a33 - a13 * a31, + a12 * a31 - a11 * a32, + a12 * a23 - a13 * a22, + a13 * a21 - a11 * a23, + a11 * a22 - a12 * a21); +end; + +function TPerspectiveTransform.times( + const other: TPerspectiveTransform): TPerspectiveTransform; +begin + Result := TPerspectiveTransform.Create(a11 * other.a11 + a21 * other.a12 + a31 * other.a13, + a11 * other.a21 + a21 * other.a22 + a31 * other.a23, + a11 * other.a31 + a21 * other.a32 + a31 * other.a33, + a12 * other.a11 + a22 * other.a12 + a32 * other.a13, + a12 * other.a21 + a22 * other.a22 + a32 * other.a23, + a12 * other.a31 + a22 * other.a32 + a32 * other.a33, + a13 * other.a11 + a23 * other.a12 + a33 * other.a13, + a13 * other.a21 + a23 * other.a22 + a33 * other.a23, + a13 * other.a31 + a23 * other.a32 + a33 * other.a33); +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.DecodeHintType.pas b/android-client/ThirdParty/ZXing/Common/ZXing.DecodeHintType.pas new file mode 100644 index 0000000..7dd16d2 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.DecodeHintType.pas @@ -0,0 +1,127 @@ +{ + * 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. + + * Implemented by E. Spelt for Delphi + * Restructured by K. Gossens +} + +unit ZXing.DecodeHintType; + +interface + +type + TDecodeHintType = ( + /// + /// Unspecified, application-specific hint. Maps to an unspecified . + /// + OTHER, + + /// + /// Image is a pure monochrome image of a barcode. Doesn't matter what it maps to; + /// use = true. + /// + PURE_BARCODE, + + /// + /// Image is known to be of one of a few possible formats. + /// Maps to a of s. + /// + POSSIBLE_FORMATS, + + /// + /// Spend more time to try to find a barcode; optimize for accuracy, not speed. + /// Doesn't matter what it maps to; use = true. + /// + TRY_HARDER, + + /// + /// Specifies what character encoding to use when decoding, where applicable (type String) + /// + CHARACTER_SET, + + /// + /// Allowed lengths of encoded data -- reject anything else. Maps to an int[]. + /// + ALLOWED_LENGTHS, + + /// + /// Assume Code 39 codes employ a check digit. Maps to . + /// + ASSUME_CODE_39_CHECK_DIGIT, + + /// + /// The caller needs to be notified via callback when a possible + /// is found. Maps to a . + /// + NEED_RESULT_POINT_CALLBACK, + + /// + /// Assume MSI codes employ a check digit. Maps to . + /// + ASSUME_MSI_CHECK_DIGIT, + + /// + /// if Code39 could be detected try to use extended mode for full ASCII character set + /// Maps to . + /// + USE_CODE_39_EXTENDED_MODE, + + /// + /// Don't fail if a Code39 is detected but can't be decoded in extended mode. + /// Return the raw Code39 result instead. Maps to . + /// + RELAXED_CODE_39_EXTENDED_MODE, + + /// + /// 1D readers supporting rotation with TRY_HARDER enabled. + /// But BarcodeReader class can do auto-rotating for 1D and 2D codes. + /// Enabling that option prevents 1D readers doing double rotation. + /// BarcodeReader enables that option automatically if "global" auto-rotation is enabled. + /// Maps to . + /// + TRY_HARDER_WITHOUT_ROTATION, + + /// + /// Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed. + /// For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to; + /// use . + /// + ASSUME_GS1, + + /// + /// If true, return the start and end digits in a Codabar barcode instead of stripping them. They + /// are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them + /// to not be. Doesn't matter what it maps to; use . + /// + RETURN_CODABAR_START_END, + + /// + /// Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this. + /// Maps to an of the allowed extension lengths, for example [2], [5], or [2, 5]. + /// If it is optional to have an extension, do not set this hint. If this is set, + /// and a UPC or EAN barcode is found but an extension is not, then no result will be returned + /// at all. + /// + ALLOWED_EAN_EXTENSIONS, + /// + /// Allowes for inversion of an image. + /// Add the to invert the image + /// + ENABLE_INVERSION + ); + +implementation + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.DecoderResult.pas b/android-client/ThirdParty/ZXing/Common/ZXing.DecoderResult.pas new file mode 100644 index 0000000..17ec223 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.DecoderResult.pas @@ -0,0 +1,90 @@ +unit ZXing.DecoderResult; + +{ + * 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. + + * Implemented by E. Spelt for Delphi +} +interface + +uses SysUtils, + Generics.Collections, + ZXIng.ByteSegments; + +type + TDecoderResult = class + private + function GetStructuredAppend: boolean; + public + ByteSegments: IByteSegments; + ECLevel: string; + Erasures: Integer; + ErrorsCorrected: Integer; + Other: TObject; + RawBytes: TArray; + StructuredAppendParity: Integer; + StructuredAppendSequenceNumber: Integer; + Text: string; + + constructor Create(RawBytes: TArray; const Text: string; + ByteSegments: IByteSegments; ECLevel: string); overload; + constructor Create(RawBytes: TArray; const Text: string; + ByteSegments: IByteSegments; ECLevel: string; saSequence: Integer; + saParity: Integer); overload; + destructor Destroy; override; + + property StructuredAppend: boolean read GetStructuredAppend; + end; + +implementation + +{ TDecoderResult } + +constructor TDecoderResult.Create(RawBytes: TArray; const Text: String; + ByteSegments: IByteSegments; ECLevel: String); +begin + Self.Create(RawBytes, Text, ByteSegments, ECLevel, -1, -1); +end; + +constructor TDecoderResult.Create(RawBytes: TArray; const Text: string; + ByteSegments: IByteSegments; ECLevel: string; + saSequence, saParity: Integer); +begin + if ((RawBytes = nil) and (Text = '')) + then + raise EArgumentException.Create('Text or rawbytes cannot be nil or empty'); + + Self.RawBytes := RawBytes; + Self.Text := Text; + Self.ByteSegments := ByteSegments; + Self.ECLevel := ECLevel; + Self.StructuredAppendParity := saParity; + Self.StructuredAppendSequenceNumber := saSequence +end; + +destructor TDecoderResult.Destroy; +begin + RawBytes := nil; + FreeAndNil(Other); + inherited; +end; + +function TDecoderResult.GetStructuredAppend: boolean; +begin + result := (StructuredAppendParity >= 0) and + (StructuredAppendSequenceNumber >= 0); +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.DefaultGridSampler.pas b/android-client/ThirdParty/ZXing/Common/ZXing.DefaultGridSampler.pas new file mode 100644 index 0000000..62a8c52 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.DefaultGridSampler.pas @@ -0,0 +1,266 @@ +{ + * 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: Sean Owen + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.DefaultGridSampler; + +interface + +uses + System.SysUtils, + System.Math, + ZXing.Common.BitMatrix, + ZXing.Common.PerspectiveTransform, + ZXing.Common.Detector.MathUtils; + +type + // TODO(KG) Add GridSampler basis class + TDefaultGridSampler = class //(TGridSampler) + private + class var GridSampler: TDefaultGridSampler; + class function get_Instance(): TDefaultGridSampler; static; + protected + ///

Checks a set of points that have been transformed to sample points on an image against + /// the image's dimensions to see if the point are even within the image.

+ /// + ///

This method will actually "nudge" the endpoints back onto the image if they are found to be + /// barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder + /// patterns in an image where the QR Code runs all the way to the image border.

+ /// + ///

For efficiency, the method will check points from either end of the line until one is found + /// to be within the image. Because the set of points are assumed to be linear, this is valid.

+ /// + ///
+ /// image into which the points should map + /// + /// actual points in x1,y1,...,xn,yn form + /// + class function checkAndNudgePoints(const image: TBitMatrix; + const points: TArray): boolean; static; + public + class function sampleGrid(const image: TBitMatrix; + const dimensionX, dimensionY: Integer; + const p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, + p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, + p4FromY: Single): TBitMatrix; overload; static; + + class function sampleGrid(const image: TBitMatrix; + const dimensionX, dimensionY: Integer; + const transform: TPerspectiveTransform): TBitMatrix; overload; static; + + class procedure setGridSampler(newGridSampler: TDefaultGridSampler); static; + + // Properties + class property Instance: TDefaultGridSampler read get_Instance; + + end; + +implementation + +{ TDefaultGridSampler } + +class function TDefaultGridSampler.sampleGrid(const image: TBitMatrix; + const dimensionX, dimensionY: Integer; const p1ToX, p1ToY, p2ToX, p2ToY, + p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, + p3FromY, p4FromX, p4FromY: Single): TBitMatrix; +var + transform: TPerspectiveTransform; +begin + transform := TPerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, + p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, + p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); + + try + Result := sampleGrid(image, dimensionX, dimensionY, transform); + finally + transform.free; + end; + +end; + +class function TDefaultGridSampler.sampleGrid(const image: TBitMatrix; + const dimensionX, dimensionY: Integer; + const transform: TPerspectiveTransform) : TBitMatrix; +var + bits: TBitMatrix; + points: TArray; + y, x, max: Integer; + iValue: Single; +begin + Result := nil; + + if ((dimensionX <= 0) or + (dimensionY <= 0)) + then + exit; + + bits := TBitMatrix.Create(dimensionX, dimensionY); + points := TArray.Create(); + SetLength(points, dimensionX shl 1); + + try + for y := 0 to Pred(dimensionY) do + begin + max := Length(points) - 1; + iValue := (y + 0.5); + x := 0; + while ((x < max)) do + begin + points[x] := TMathUtils.Asr(x, 1) + 0.5; + points[(x + 1)] := iValue; + Inc(x, 2); + end; + transform.transformPoints(points); + + // Quick check to see if points transformed to something inside the image; + // sufficient to check the endpoints + if (not checkAndNudgePoints(image, points)) then + begin + bits.Free; + exit; + end; + + try + x := 0; + while (x < max) do + begin + bits[(TMathUtils.Asr(x, 1)), y] := image[Floor(points[x]), Floor(points[x + 1])]; + Inc(x, 2); + end + except + // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting + // transform gets "twisted" such that it maps a straight line of points to a set of points + // whose endpoints are in bounds, but others are not. There is probably some mathematical + // way to detect this about the transformation that I don't know yet. + // This results in an ugly runtime exception despite our clever checks above -- can't have + // that. We could check each point's coordinates but that feels duplicative. We settle for + // catching and wrapping ArrayIndexOutOfBoundsException. + exit; + end; + end; + finally + points := nil; + end; + Result := bits; +end; + +class function TDefaultGridSampler.checkAndNudgePoints(const image: TBitMatrix; + const points: TArray): Boolean; +var + offset, + x, y, + width, height : Integer; + nudged : Boolean; +begin + width := image.width; + height := image.height; + // Check and nudge points from start until we see some that are OK: + nudged := true; + offset := 0; + + while ((offset < (Length(points) - 1)) and nudged) do + begin + x := Floor(points[offset]); + y := Floor(points[(offset + 1)]); + if ((((x < -1) or (x > width)) or (y < -1)) or (y > height)) then + begin + Result := false; + exit + end; + nudged := false; + if (x = -1) then + begin + points[offset] := 0; + nudged := true + end + else if (x = width) then + begin + points[offset] := (width - 1); + nudged := true + end; + if (y = -1) then + begin + points[(offset + 1)] := 0; + nudged := true + end + else if (y = height) then + begin + points[(offset + 1)] := (height - 1); + nudged := true + end; + inc(offset, 2) + end; + + // Check and nudge points from end: + nudged := true; + offset := (Length(points) - 2); + while ((offset >= 0) and nudged) do + begin + x := Floor(points[offset]); + y := Floor(points[(offset + 1)]); + if ((((x < -1) or (x > width)) or (y < -1)) or (y > height)) then + begin + Result := false; + exit + end; + nudged := false; + if (x = -1) then + begin + points[offset] := 0; + nudged := true + end + else if (x = width) then + begin + points[offset] := (width - 1); + nudged := true + end; + if (y = -1) then + begin + points[(offset + 1)] := 0; + nudged := true + end + else if (y = height) then + begin + points[(offset + 1)] := (height - 1); + nudged := true + end; + Dec(offset, 2); + end; + + Result := true; +end; + +class function TDefaultGridSampler.get_Instance: TDefaultGridSampler; +begin + GridSampler := TDefaultGridSampler.Create(); + Result := GridSampler; +end; + +class procedure TDefaultGridSampler.setGridSampler(newGridSampler + : TDefaultGridSampler); +begin + if (newGridSampler = nil) then + begin + raise EArgumentException.Create('Arguments in error'); + end; + + GridSampler := newGridSampler; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.EncodeHintType.pas b/android-client/ThirdParty/ZXing/Common/ZXing.EncodeHintType.pas new file mode 100644 index 0000000..426b801 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.EncodeHintType.pas @@ -0,0 +1,43 @@ +{ + * 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. + + * Implemented by E. Spelt for Delphi + * Restructured by K. Gossens +} + +unit ZXing.EncodeHintType; + +interface + +type + TEncodeHintType = (AZTEC_LAYERS = 15, + CHARACTER_SET = 4, + CODE128_FORCE_CODESET_B = 13, + DATA_MATRIX_DEFAULT_ENCODATION = 14, + DATA_MATRIX_SHAPE = 10, + DISABLE_ECI = 9, + ERROR_CORRECTION = 3, + HEIGHT = 1, + MARGIN = 5, + MAX_SIZE = 12, + MIN_SIZE = 11, + PDF417_COMPACTION = 7, + PDF417_DIMENSIONS = 8, + PURE_BARCODE = 2, + WIDTH = 0); + +implementation + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.Helpers.pas b/android-client/ThirdParty/ZXing/Common/ZXing.Helpers.pas new file mode 100644 index 0000000..d9c7a02 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.Helpers.pas @@ -0,0 +1,62 @@ +unit ZXing.Helpers; + +{ + * 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. + + * Implemented by E. Spelt for Delphi +} +interface + +type + TArray = class + class function Clone(original: TArray): TArray; static; + class function CopyInSameArray(const Input: TArray; + StartIndex: Integer; Len: Integer): TArray; static; + end; + +implementation + +class function TArray.Clone(original: TArray): TArray; +var + i: Integer; + l: SmallInt; +begin + l := Length(original); + Result := TArray.Create(); + SetLength(Result, l); + + for i := 0 to l - 1 do + begin + Result[i] := original[i]; + end; +end; + +class function TArray.CopyInSameArray(const Input: TArray; + StartIndex: Integer; Len: Integer): TArray; +var + i, y: Integer; +begin + Result := TArray.Clone(Input); + + y := 0; + for i := StartIndex to (StartIndex + Len -1) do + begin + Result[y] := Input[i]; + inc(y); + end; + +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.MultiFormatReader.pas b/android-client/ThirdParty/ZXing/Common/ZXing.MultiFormatReader.pas new file mode 100644 index 0000000..536d039 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.MultiFormatReader.pas @@ -0,0 +1,350 @@ +{ + * 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 Authors: Sean Owen and dswitkin@google.com (Daniel Switkin) + * Ported from ZXING Java Source: www.Redivivus.in (suraj.supekar@redivivus.in) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.MultiFormatReader; + +interface + +uses + System.SysUtils, + System.Rtti, + System.Generics.Collections, + System.RegularExpressions, + ZXing.ReadResult, + ZXing.Reader, + ZXing.DecodeHintType, + ZXing.BinaryBitmap, + ZXing.BarcodeFormat, + ZXing.ResultPoint, + + // 1D Barcodes + ZXing.OneD.OneDReader, + ZXing.OneD.Code128Reader, + ZXing.OneD.Code93Reader, + ZXing.OneD.ITFReader, + ZXing.OneD.EAN13Reader, + ZXing.OneD.EAN8Reader, + ZXing.OneD.UPCAReader, + ZXing.OneD.UPCEReader, + ZXing.OneD.Code39Reader, + + // 2D Codes + ZXing.QrCode.QRCodeReader, + ZXing.Datamatrix.DataMatrixReader; + +/// +/// MultiFormatReader is a convenience class and the main entry point into the library for most uses. +/// By default it attempts to decode all barcode formats that the library supports. Optionally, you +/// can provide a hints object to request different behavior, for example only decoding QR codes. +/// +/// Sean Owen +/// dswitkin@google.com (Daniel Switkin) +/// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source +type + + TMultiFormatReader = class(TInterfacedObject, IReader) + private + + FHints: TDictionary; + readers: TList; + + function DecodeInternal(image: TBinaryBitmap): TReadResult; + procedure Set_Hints(const Value: TDictionary); + function Get_Hints: TDictionary; + + /// This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it + /// passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly. + /// Use setHints() followed by decodeWithState() for continuous scan applications. + /// + /// + /// The pixel data to decode + /// + /// The contents of the image + /// + /// ReaderException Any errors which occurred + public + function decode(const image: TBinaryBitmap): TReadResult; overload; + function decode(const image: TBinaryBitmap; WithHints: Boolean) + : TReadResult; overload; + /// Decode an image using the hints provided. Does not honor existing state. + /// + /// + /// The pixel data to decode + /// + /// The hints to use, clearing the previous state. + /// + /// The contents of the image + /// + /// ReaderException Any errors which occurred + function decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; overload; + + /// Decode an image using the state set up by calling setHints() previously. Continuous scan + /// clients will get a large speed increase by using this instead of decode(). + /// + /// + /// The pixel data to decode + /// + /// The contents of the image + /// + /// ReaderException Any errors which occurred + function DecodeWithState(image: TBinaryBitmap): TReadResult; + destructor Destroy; override; + + /// This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls + /// to decodeWithState(image) can reuse the same set of readers without reallocating memory. This + /// is important for performance in continuous scan clients. + /// + /// + /// The set of hints to use for subsequent calls to decode(image) + /// + property hints: TDictionary read Get_Hints + write Set_Hints; + + procedure Reset; + procedure FreeReaders(); + + end; + +implementation + +function TMultiFormatReader.decode(const image: TBinaryBitmap): TReadResult; +begin + hints := nil; + result := DecodeInternal(image) +end; + +function TMultiFormatReader.decode(const image: TBinaryBitmap; + WithHints: Boolean): TReadResult; +begin + result := DecodeInternal(image) +end; + +function TMultiFormatReader.decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; +begin + FHints := hints; + result := DecodeInternal(image) +end; + +function TMultiFormatReader.DecodeWithState(image: TBinaryBitmap): TReadResult; +begin + // Make sure to set up the default state so we don't crash + if readers = nil then + begin + hints := nil + end; + + result := DecodeInternal(image); + +end; + +destructor TMultiFormatReader.Destroy; +begin + FreeReaders; + inherited; +end; + +procedure TMultiFormatReader.FreeReaders; +begin + if readers <> nil then + readers.Clear(); + + readers.Free; + readers := nil; +end; + +function TMultiFormatReader.Get_Hints: TDictionary; +begin + result := FHints; +end; + +procedure TMultiFormatReader.Set_Hints(const Value: TDictionary); +var + useCode39CheckDigit, useCode39ExtendedMode: Boolean; + formats: TList; +begin + FHints := Value; + + // tryHarder := (Value <> nil) and + // (Value.ContainsKey(ZXing.DecodeHintType.TRY_HARDER)); + + if ((Value = nil) or + (not Value.ContainsKey(ZXing.DecodeHintType.POSSIBLE_FORMATS))) then + begin + formats := nil; + end + else + begin + formats := Value[ZXing.DecodeHintType.POSSIBLE_FORMATS] + as TList + end; + + // add readers from the hints + readers := TList.Create; + if formats <> nil then + begin + + // 1D readers + + if (formats.Contains(TBarcodeFormat.CODE_128)) then + begin + readers.Add(TCode128Reader.Create()) + end; + + if (formats.Contains(TBarcodeFormat.CODE_93)) then + begin + readers.Add(TCode93Reader.Create()) + end; + + if (formats.Contains(TBarcodeFormat.ITF)) then + begin + readers.Add(TITFReader.Create()) + end; + + // 2D readers + if (formats.Contains(TBarcodeFormat.QR_CODE)) then + begin + readers.Add(TQRCodeReader.Create()) + end; + + if formats.Contains(TBarcodeFormat.DATA_MATRIX) then + readers.Add(TDataMatrixReader.Create); + + if (formats.Contains(TBarcodeFormat.EAN_13)) then + readers.Add(TEAN13Reader.Create()); + + if (formats.Contains(TBarcodeFormat.EAN_8)) then + readers.Add(TEAN8Reader.Create()); + + if (formats.Contains(TBarcodeFormat.UPC_A)) then + readers.Add(TUPCAReader.Create()); + + if (formats.Contains(TBarcodeFormat.UPC_E)) then + readers.Add(TUPCEReader.Create()); + + if (formats.Contains(TBarcodeFormat.CODE_39)) then + begin + useCode39CheckDigit := hints.ContainsKey + (TDecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) and + hints.ContainsKey(TDecodeHintType.ASSUME_CODE_39_CHECK_DIGIT); + + useCode39ExtendedMode := hints.ContainsKey + (TDecodeHintType.USE_CODE_39_EXTENDED_MODE) and + hints.ContainsKey(TDecodeHintType.USE_CODE_39_EXTENDED_MODE); + + readers.Add(TCode39Reader.Create(useCode39CheckDigit, + useCode39ExtendedMode)); + + end; + end; + + if (readers.Count = 0) then // must be auto, add them all + begin + + // 1D readers + readers.Add(TCode128Reader.Create()); + readers.Add(TUPCAReader.Create()); + readers.Add(TUPCEReader.Create()); + readers.Add(TEAN13Reader.Create()); + readers.Add(TEAN8Reader.Create()); + readers.Add(TCode93Reader.Create()); + readers.Add(TITFReader.Create()); + useCode39CheckDigit := hints.ContainsKey + (TDecodeHintType.ASSUME_CODE_39_CHECK_DIGIT) and hints.ContainsKey + (TDecodeHintType.ASSUME_CODE_39_CHECK_DIGIT); + + useCode39ExtendedMode := hints.ContainsKey + (TDecodeHintType.USE_CODE_39_EXTENDED_MODE) and hints.ContainsKey + (TDecodeHintType.USE_CODE_39_EXTENDED_MODE); + + readers.Add(TCode39Reader.Create(useCode39CheckDigit, + useCode39ExtendedMode)); + + + // 2D readers + readers.Add(TQRCodeReader.Create()); + readers.Add(TDataMatrixReader.Create) + end; + +end; + +procedure TMultiFormatReader.Reset; +var + Reader: IReader; +begin + if readers <> nil then + begin + for Reader in readers do + begin + Reader.Reset(); + end + end +end; + +function TMultiFormatReader.DecodeInternal(image: TBinaryBitmap): TReadResult; +var + rpCallBack: TResultPointCallback; + i: integer; + Reader: IReader; +begin + + result := nil; + if (readers = nil) then + begin + Exit; + end; + + rpCallBack := nil; + if ((FHints <> nil) and + (FHints.ContainsKey(ZXing.DecodeHintType.NEED_RESULT_POINT_CALLBACK))) then + begin + // rpCallBack := FHints[DecodeHintType.NEED_RESULT_POINT_CALLBACK] + // as TResultPointCallback(nil); + end; + + for i := 0 to readers.Count - 1 do + begin + + Reader := readers[i]; + Reader.Reset(); + result := Reader.decode(image, FHints); + if result <> nil then + begin + + // found a barcode, pushing the successful reader up front + // I assume that the same type of barcode is read multiple times + // so the reordering of the readers list should speed up the next reading + // a little bit + + readers.Delete(i); + readers.Insert(0, Reader); + Exit; + end; + + // if rpCallBack <> nil then + // rpCallBack(nil) + + end; + +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.ReadResult.pas b/android-client/ThirdParty/ZXing/Common/ZXing.ReadResult.pas new file mode 100644 index 0000000..f07abff --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.ReadResult.pas @@ -0,0 +1,344 @@ +{ + * 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 E. Spelt and K. Gossens +} +unit ZXing.ReadResult; + +interface + +uses + System.SysUtils, + Generics.Collections, + ZXing.ResultPoint, + ZXing.ResultMetadataType, + ZXing.BarcodeFormat, + ZXing.ByteSegments; + +type + + IMetaData = Interface + ['{27AEB2C5-D775-44C6-9816-3E69025CA57C}'] + end; + + IStringMetadata = interface(IMetaData) + ['{8073F897-30AD-49B7-AE0B-B187D3373163}'] + function Value:String; + end; + + IIntegerMetadata = interface(IMetaData) + ['{CA60A23A-57ED-4C8E-9886-4F23B832A90C}'] + function Value:Integer; + end; + + IByteSegmentsMetadata = interface(IMetaData) + ['{CA60A23A-57ED-4C8E-9886-4F23B832A90C}'] + function Value:IByteSegments; + end; + + /// + /// represents the metadata contained in a TReadResult and provides the + /// helping functions needed to create them + /// + TResultMetaData = class(TDictionary) + public + constructor Create; + class function CreateStringMetadata(const Value:string) :IStringMetaData; + class function CreateIntegerMetadata(const Value:integer) :IIntegerMetaData; + class function CreateByteSegmentsMetadata(const Value:IByteSegments) :IByteSegmentsMetadata; + end; + + TReadResult = class + private + FText: string; + FTimeStamp: TDateTime; + FResultMetadata: TResultMetaData; + FRawBytes: TArray; + FResultPoints: TArray; + FFormat: TBarcodeFormat; + + procedure SetText(const AValue: String); + procedure SetMetaData( const Value: TResultMetadata); + public + /// + /// Initializes a new instance of the class. + /// + /// The text. + /// The raw bytes. + /// The result points. + /// The format. + constructor Create(const text: string; const rawBytes: TArray; + const resultPoints: TArray; + const format: TBarcodeFormat); overload; + + /// + /// Initializes a new instance of the class. + /// + /// The text. + /// The raw bytes. + /// The result points. + /// The format. + /// The timestamp. + constructor Create(const text: string; const rawBytes: TArray; + const resultPoints: TArray; const format: TBarcodeFormat; + const timeStamp: TDateTime); overload; + destructor Destroy; override; + + function ToString: String; override; + + // we need a "write" procedure accessor because we need to properly deallocate + // existing instance if we overwrite it with another one + property ResultMetaData: TResultMetadata + read FResultMetadata write SetMetaData; + + /// + /// Adds one metadata to the result + /// + /// The type. + /// The value. + procedure putMetadata(const ResultMetadataType: TResultMetadataType; + const Value: IMetaData); + + /// + /// Adds a list of metadata to the result + /// + /// The metadata. + procedure putAllMetaData(const metaData: TResultMetadata); + + /// + /// Adds the result points. + /// + /// The new points. + procedure addResultPoints(const newPoints: TArray); + + /// raw text encoded by the barcode, if applicable, otherwise null + property text: String read FText write SetText; + + /// raw bytes encoded by the barcode, if applicable, otherwise null + property rawBytes: TArray read FRawBytes write FRawBytes; + + /// + /// points related to the barcode in the image. These are typically points + /// identifying finder patterns or the corners of the barcode. The exact meaning is + /// specific to the type of barcode that was decoded. + /// + property resultPoints: TArray read FResultPoints + write FResultPoints; + + /// {@link TBarcodeFormat} representing the format of the barcode that was decoded + property BarcodeFormat: TBarcodeFormat read FFormat write FFormat; + + /// + /// Gets the timestamp. + /// + property timeStamp: TDateTime read FTimeStamp; + end; + +implementation + + +{$REGION 'IMetaData implementations'} + +{ TStringMetadata } +type + TStringMetadata = class(TInterfacedObject,IMetaData,IStringMetadata) + strict private + FValue: String; + function Value: String; + private + constructor Create(const AValue: String); + end; + +function TStringMetadata.Value: String; +begin + result := FValue +end; + +constructor TStringMetadata.Create(const AValue: string); +begin + inherited Create; + FValue := AValue; +end; + +{ TIntegerMetadata } +type + TIntegerMetadata = class(TInterfacedObject,IMetaData,IIntegerMetadata) + strict private + FValue: Integer; + function Value: Integer; + private + constructor Create(const AValue: Integer); + end; + +function TIntegerMetadata.Value: Integer; +begin + result := FValue +end; + +constructor TIntegerMetadata.Create(const AValue: Integer); +begin + inherited Create; + FValue := AValue; +end; + + +{ TByteSegmentsMetadata } +type + TByteSegmentsMetadata = class(TInterfacedObject,IMetaData,IByteSegmentsMetadata) + strict private + FValue: IByteSegments; + function Value: IByteSegments; + private + constructor Create(const AValue: IByteSegments); + end; + +function TByteSegmentsMetadata.Value: IByteSegments; +begin + result := FValue +end; + +constructor TByteSegmentsMetadata.Create(const AValue: IByteSegments); +begin + inherited Create; + FValue := AValue; +end; + +{ TResultMetadata } +constructor TResultMetaData.Create; +begin + inherited Create; +end; + +class function TResultMetadata.CreateStringMetadata(const Value:string) :IStringMetaData; +begin + result := TStringMetadata.Create(Value); +end; + +class function TResultMetaData.CreateByteSegmentsMetadata( + const Value: IByteSegments): IByteSegmentsMetadata; +begin + result := TByteSegmentsMetadata.Create(value); +end; + +class function TResultMetadata.CreateIntegerMetadata(const Value:integer) :IIntegerMetaData; +begin + result := TIntegerMetadata.Create(Value); +end; + +{$ENDREGION 'IMetaData implementations'} + + +{ TReadResult } + +constructor TReadResult.Create(const text: String; const rawBytes: TArray; + const resultPoints: TArray; const format: TBarcodeFormat); +begin + Self.Create(text, rawBytes, resultPoints, format, Now); +end; + +constructor TReadResult.Create(const text: String; const rawBytes: TArray; + const resultPoints: TArray; const format: TBarcodeFormat; + const timeStamp: TDateTime); +begin + if ((text = '') and (rawBytes = nil)) then + raise EArgumentException.Create('Text and bytes are null.'); + + SetText(text); + FRawBytes := rawBytes; + FResultPoints := resultPoints; + FResultMetadata := nil; + FFormat := format; + FResultMetadata := nil; + FTimeStamp := timeStamp; +end; + +destructor TReadResult.Destroy; +var i:Integer; +begin + + for I := Low(FResultPoints) to High(FResultPoints) do + begin + FResultPoints[i] := nil; + end; + + FResultPoints := nil; + FRawBytes := nil; + + if FResultMetadata <> nil then + begin + FResultMetadata.Clear; + FreeAndNil(FResultMetadata); + end; + + inherited; +end; + +// Added (KG): UTF-8 compatiblity +procedure TReadResult.SetMetaData(const Value: TResultMetadata); +begin + if value = FResultMetadata then + exit; // no change + if FResultMetadata<>nil then + FResultMetadata.Free; // we need to free existing object instance, for old-gen compilers + FResultMetadata := Value; +end; + +procedure TReadResult.SetText(const AValue: String); +begin + FText := AValue; +end; + +procedure TReadResult.putMetadata(const ResultMetadataType: TResultMetadataType; + const Value: IMetaData); +begin + if (FResultMetadata = nil) then + FResultMetadata := TResultMetadata.Create(); + FResultMetadata.AddOrSetValue(ResultMetadataType, Value); +end; + +procedure TReadResult.putAllMetaData(const metaData: TResultMetadata); +var + key: TResultMetadataType; +begin + if (metaData <> nil) then + begin + if (FResultMetadata = nil) then + FResultMetadata := TResultMetadata.Create(); + for key in metaData.Keys do + FResultMetadata.AddOrSetValue(key, metaData[key]); + end; +end; + +procedure TReadResult.addResultPoints(const newPoints: TArray); +begin + FResultPoints := FResultPoints + newPoints; +end; + +/// +/// Returns a that represents this instance. +/// +/// +/// A that represents this instance. +/// +function TReadResult.ToString(): String; +begin + if (text = '') then + Result := '[' + IntToStr(Length(rawBytes)) + ' bytes]' + else + Result := text; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.Reader.pas b/android-client/ThirdParty/ZXing/Common/ZXing.Reader.pas new file mode 100644 index 0000000..d9bbeca --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.Reader.pas @@ -0,0 +1,71 @@ +{ + * 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 Authors: Sean Owen and dswitkin@google.com (Daniel Switkin) + * Delphi Implementation by E. Spelt and K. Gossens +} + +unit ZXing.Reader; + +interface + +uses + System.SysUtils, + System.Generics.Collections, + ZXing.BinaryBitmap, + ZXing.ReadResult, + ZXing.DecodeHintType; + +type + /// + /// Implementations of this interface can decode an image of a barcode in some format into + /// the String it encodes. For example, can + /// decode a QR code. The decoder may optionally receive hints from the caller which may help + /// it decode more quickly or accurately. + /// + /// See , which attempts to determine what barcode + /// format is present within the image as well, and then decodes it accordingly. + /// + IReader = interface + /// + /// Locates and decodes a barcode in some format within an image. + /// + /// image of barcode to decode + /// String which the barcode encodes + function decode(const image: TBinaryBitmap): TReadResult; overload; + + /// Locates and decodes a barcode in some format within an image. This method also accepts + /// hints, each possibly associated to some data, which may help the implementation decode. + /// + /// image of barcode to decode + /// passed as a from + /// to arbitrary data. The + /// meaning of the data depends upon the hint type. The implementation may or may not do + /// anything with these hints. + /// + /// String which the barcode encodes + function decode(const image: TBinaryBitmap; + hints: TDictionary): TReadResult; overload; + + /// + /// Resets any internal state the implementation has after a decode, to prepare it + /// for reuse. + /// + procedure Reset(); + end; + +implementation + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.ResultMetadataType.pas b/android-client/ThirdParty/ZXing/Common/ZXing.ResultMetadataType.pas new file mode 100644 index 0000000..5a4dae1 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.ResultMetadataType.pas @@ -0,0 +1,108 @@ +{ + * 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. + + * Implemented by E. Spelt for Delphi +} + +unit ZXing.ResultMetadataType; + +interface + +type + /// + /// Represents some type of metadata about the result of the decoding that the decoder + /// wishes to communicate back to the caller. + /// + /// Sean Owen + TResultMetadataType = ( + /// + /// Unspecified, application-specific metadata. Maps to an unspecified {@link Object}. + /// + OTHER, + + /// + /// Denotes the likely approximate orientation of the barcode in the image. This value + /// is given as degrees rotated clockwise from the normal, upright orientation. + /// For example a 1D barcode which was found by reading top-to-bottom would be + /// said to have orientation "90". This key maps to an {@link Integer} whose + /// value is in the range [0,360). + /// + ORIENTATION, + + /// + ///

2D barcode formats typically encode text, but allow for a sort of 'byte mode' + /// which is sometimes used to encode binary data. While {@link Result} makes available + /// the complete raw bytes in the barcode for these formats, it does not offer the bytes + /// from the byte segments alone.

+ ///

This maps to a {@link java.util.List} of byte arrays corresponding to the + /// raw bytes in the byte segments in the barcode, in order.

+ ///
+ BYTE_SEGMENTS, + + /// + /// Error correction level used, if applicable. The value type depends on the + /// format, but is typically a String. + /// + ERROR_CORRECTION_LEVEL, + + /// + /// For some periodicals, indicates the issue number as an {@link Integer}. + /// + ISSUE_NUMBER, + + /// + /// For some products, indicates the suggested retail price in the barcode as a + /// formatted {@link String}. + /// + SUGGESTED_PRICE, + + /// + /// For some products, the possible country of manufacture as a {@link String} denoting the + /// ISO country code. Some map to multiple possible countries, like "US/CA". + /// + POSSIBLE_COUNTRY, + + /// + /// For some products, the extension text + /// + UPC_EAN_EXTENSION, + + /// + /// If the code format supports structured append and + /// the current scanned code is part of one then the + /// sequence number is given with it. + /// + STRUCTURED_APPEND_SEQUENCE, + + /// + /// If the code format supports structured append and + /// the current scanned code is part of one then the + /// parity is given with it. + /// + STRUCTURED_APPEND_PARITY, + + /// + /// PDF417-specific metadata + /// + PDF417_EXTRA_METADATA, + + /// + /// Aztec-specific metadata + /// + AZTEC_EXTRA_METADATA); + +implementation + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.ResultPoint.pas b/android-client/ThirdParty/ZXing/Common/ZXing.ResultPoint.pas new file mode 100644 index 0000000..e16102d --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.ResultPoint.pas @@ -0,0 +1,206 @@ +{ + * 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 E. Spelt and K. Gossens +} + +unit ZXing.ResultPoint; + +interface + +uses + System.SysUtils, + ZXing.Common.Detector.MathUtils; + +type + /// + /// To mimic "garbage collection" (or ARC) with old-gen compilers we have to use + /// interfaces. IResultPoint is the interface that maps TResultPoint which is now + /// implemented as a TInterfacedObject descendant which supports automatic deallocation + /// based on reference counting of interface variables. + /// See ZXing.ResultPointImplementation to see the actual implementation of this interface. + /// since we are using automatic reference counting, we don't need the Clone method any more. + /// + + IResultPoint = interface + ['{1E60EDAB-0387-440C-9D8E-4E0CC772C820}'] + // property accessors, for interfaces, MUST be functions or procedures (interfaces cannot contain data) + procedure SetX(const AValue: Single); + procedure SetY(const AValue: Single); + function GetX: Single; + function GetY: Single; + + function Equals(other: TObject): Boolean; + function GetHashCode(): Integer; + function ToString(): String; + + property x: Single read GetX write SetX; + property y: Single read GetY write SetY; + end; + + /// + /// in order to implement TResultPoint as an interface all static methods + /// have been moved in this static class. + /// this class contains also the CreateResultPoint method that must be used + /// in place of the actual class constructor + /// + TResultPointHelpers = class + protected + /// + /// Returns the z component of the cross product between vectors BC and BA. + /// + class function crossProductZ(const pointA, pointB, pointC: IResultPoint): Single; static; + public + /// + /// Initializes a new instance of and returns + /// its interface + /// + class function CreateResultPoint:IResultPoint; overload; + /// + /// Initializes a new instance of and returns + /// its interface + /// + /// The x. + /// The y. + class function CreateResultPoint(const pX, pY: Single):IResultPoint; overload; + /// + /// Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC and + /// BC is less than AC and the angle between BC and BA is less than 180 degrees. + /// + /// array of three to order + class procedure orderBestPatterns(const patterns : TArray); static; + /// + /// calculates the distance between two points + /// + /// first pattern + /// second pattern + /// + /// distance between two points + /// + class function distance(const pattern1, pattern2: IResultPoint) : Single; static; + end; + + + + /// Callback which is invoked when a possible result point (significant + /// point in the barcode image such as a corner) is found. + /// + /// + /// + /// + TResultPointCallback = procedure(const point: IResultPoint) of object; + + TResultPointEventObject = class(TObject) + private + FResultPointCallback: TResultPointCallback; + public + constructor Create(const AEvent: TResultPointCallback); + + property Event: TResultPointCallback read FResultPointCallback; + end; + +implementation +uses ZXing.ResultPointImplementation; + +class function TResultPointHelpers.CreateResultPoint:IResultPoint; +begin + result := ZXing.ResultPointImplementation.NewResultPoint; +end; + +class function TResultPointHelpers.CreateResultPoint(const pX, pY: Single):IResultPoint; +begin + result := ZXing.ResultPointImplementation.NewResultPoint(px,py); +end; + + +class function TResultPointHelpers.crossProductZ(const pointA, pointB, + pointC: IResultPoint): Single; +var + bX, bY: Single; +begin + bX := pointB.x; + bY := pointB.y; + Result := ((pointC.x - bX) * (pointA.y - bY)) - + ((pointC.y - bY) * (pointA.x - bX)); +end; + + +class function TResultPointHelpers.distance(const pattern1, + pattern2: IResultPoint): Single; +begin + Result := TMathUtils.distance(pattern1.x, pattern1.y, pattern2.x, pattern2.y); +end; + + +class procedure TResultPointHelpers.orderBestPatterns(const patterns + : TArray); +var + zeroOneDistance, oneTwoDistance, zeroTwoDistance: Single; + pointA, pointB, pointC, temp: IResultPoint; +begin + // Find distances between pattern centers + zeroOneDistance := distance(patterns[0], patterns[1]); + oneTwoDistance := distance(patterns[1], patterns[2]); + zeroTwoDistance := distance(patterns[0], patterns[2]); + + // Assume one closest to other two is B; A and C will just be guesses at first + if ((oneTwoDistance >= zeroOneDistance) and + (oneTwoDistance >= zeroTwoDistance)) then + begin + pointB := patterns[0]; + pointA := patterns[1]; + pointC := patterns[2]; + end + else if ((zeroTwoDistance >= oneTwoDistance) and + (zeroTwoDistance >= zeroOneDistance)) then + begin + pointB := patterns[1]; + pointA := patterns[0]; + pointC := patterns[2]; + end + else + begin + pointB := patterns[2]; + pointA := patterns[0]; + pointC := patterns[1]; + end; + + // Use cross product to figure out whether A and C are correct or flipped. + // This asks whether BC x BA has a positive z component, which is the arrangement + // we want for A, B, C. If it's negative, then we've got it flipped around and + // should swap A and C. + if (crossProductZ(pointA, pointB, pointC) < 0) then + begin + temp := pointA; + pointA := pointC; + pointC := temp; + end; + + patterns[0] := pointA; + patterns[1] := pointB; + patterns[2] := pointC; +end; + + +{ TResultPointEventObject } + +constructor TResultPointEventObject.Create(const AEvent: TResultPointCallback); +begin + Self.FResultPointCallback := AEvent; +end; + + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.ResultPointImplementation.pas b/android-client/ThirdParty/ZXing/Common/ZXing.ResultPointImplementation.pas new file mode 100644 index 0000000..42d662c --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.ResultPointImplementation.pas @@ -0,0 +1,168 @@ +unit ZXing.ResultPointImplementation; + +interface +uses system.SysUtils, + ZXing.ResultPoint; + +type + /// + /// Encapsulates a point of interest in an image containing a barcode. Typically, this + /// would be the location of a finder pattern or the corner of the barcode, for example. + /// this class is meant to be used only indirectly, via the IResultPoint reference-counted interface + // it implements. It is exposed in the interface section just to allow the declaration of its derived classes + /// + TResultPoint = class(TInterfacedObject,IResultPoint) + private type + TSingleArray = array [0 .. Pred(SizeOf(Single))] of Byte; + var + Fx, Fy: Single; + bytesX, bytesY: TSingleArray; + FToString: String; + procedure SetX(const AValue: Single); + procedure SetY(const AValue: Single); + function GetX: Single; + function GetY: Single; + public + /// + /// Initializes a new instance of the class. + /// + constructor Create; overload; + /// + /// Initializes a new instance of the class. + /// + /// The x. + /// The y. + constructor Create(const pX, pY: Single); overload; + destructor Destroy; override; + + /// + /// Determines whether the specified is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + function Equals(other: TObject): Boolean; override; + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + function GetHashCode(): Integer; override; + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + function ToString(): String; override; + + property x: Single read GetX write SetX; + property y: Single read GetY write SetY; + end; + +// these are the helping functions that actually create a new instance. +// The actual constructor cannot be called outside of this unit +function NewResultPoint:IResultPoint; overload; +function NewResultPoint(const pX, pY: Single):IResultPoint; overload; + + +implementation + +function NewResultPoint:IResultPoint; +begin + result := TResultPoint.Create; +end; + +function NewResultPoint(const pX, pY: Single):IResultPoint; +begin + result := TResultPoint.Create(px,py); +end; + + +{ TResultPoint } + + +constructor TResultPoint.Create; +begin + inherited; +end; + +constructor TResultPoint.Create(const pX, pY: Single); +begin + inherited Create; + + Fx := pX; + Fy := pY; + bytesX := TSingleArray(pX); + bytesY := TSingleArray(pY); +end; + +destructor TResultPoint.Destroy; +var + n: Single; +begin + n := 0; + bytesX := TSingleArray(n); + bytesY := TSingleArray(n); + inherited; +end; + +procedure TResultPoint.SetX(const AValue: Single); +begin + if (AValue <> Fx) then + begin + Fx := AValue; + bytesX := TSingleArray(Fx); + end; +end; + +procedure TResultPoint.SetY(const AValue: Single); +begin + if (AValue <> Fy) then + begin + Fy := AValue; + bytesY := TSingleArray(Fy); + end; +end; + +function TResultPoint.GetX: Single; +begin + result := Fx; +end; + +function TResultPoint.GetY: Single; +begin + result := Fy; +end; + +function TResultPoint.Equals(other: TObject): Boolean; +var + otherPoint: TResultPoint; +begin + otherPoint := other as TResultPoint; + if (otherPoint = nil) then + Result := false + else + Result := ((otherPoint.x = Fx) and (otherPoint.y = Fy)); +end; + +function TResultPoint.GetHashCode: Integer; +begin + Result := 31 * ((bytesX[0] shl 24) + (bytesX[1] shl 16) + (bytesX[2] shl 8) + + bytesX[3]) + (bytesY[0] shl 24) + (bytesY[1] shl 16) + (bytesY[2] shl 8) + + bytesY[3]; +end; + + +function TResultPoint.ToString: String; +begin + if (FToString = '') then + FToString := Format('(%g),(%g)', [Fx, Fy]); + Result := FToString; +end; + + + +end. diff --git a/android-client/ThirdParty/ZXing/Common/ZXing.StringUtils.pas b/android-client/ThirdParty/ZXing/Common/ZXing.StringUtils.pas new file mode 100644 index 0000000..74624aa --- /dev/null +++ b/android-client/ThirdParty/ZXing/Common/ZXing.StringUtils.pas @@ -0,0 +1,229 @@ +unit ZXing.StringUtils; + +{ + * 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. + + * Implemented by E. Spelt for Delphi +} +interface + +uses SysUtils, Generics.Collections, ZXing.DecodeHintType; + +type + + TStringUtils = class abstract + const + UTF8 = 'UTF-8'; + EUC_JP = 'EUC-JP'; + ISO88591 = 'ISO-8859-1'; + class procedure ClassInit; + class var ASSUME_SHIFT_JIS: boolean; + class var PLATFORM_DEFAULT_ENCODING: string; + public + class var GB2312: string; + class var SHIFT_JIS: string; + class function guessEncoding(bytes: TArray; + hints: TDictionary): string; static; + + end; + +implementation + +class procedure TStringUtils.ClassInit; +begin + PLATFORM_DEFAULT_ENCODING := 'ISO-8859-1'; // 'ISO 8859-15'; + SHIFT_JIS := 'SJIS'; + GB2312 := 'GB2312'; + + ASSUME_SHIFT_JIS := (string.Compare(TStringUtils.SHIFT_JIS, + TStringUtils.PLATFORM_DEFAULT_ENCODING, true) = 0) or + (string.Compare('EUC-JP', TStringUtils.PLATFORM_DEFAULT_ENCODING, + true) = 0); + +end; + +class function TStringUtils.guessEncoding(bytes: TArray; + hints: TDictionary): string; + +var + characterSet: string; + utf8BytesLeft, utf2BytesChars, utf3BytesChars, utf4BytesChars, sjisBytesLeft, + sjisKatakanaChars, sjisCurKatakanaWordLength, sjisCurDoubleBytesWordLength, + sjisMaxKatakanaWordLength, sjisMaxDoubleBytesWordLength, isoHighOther, len, + i, value: Integer; + utf8bom, canBeISO88591, canBeShiftJIS, canBeUTF8: boolean; + +begin + if ((hints <> nil) and hints.ContainsKey(ZXing.DecodeHintType.CHARACTER_SET)) then + begin + characterSet := string(hints[ZXing.DecodeHintType.CHARACTER_SET]); + if (characterSet <> '') then + begin + Result := characterSet; + exit + end + end; + + len := length(bytes); + canBeISO88591 := true; + canBeShiftJIS := true; + canBeUTF8 := true; + utf8BytesLeft := 0; + utf2BytesChars := 0; + utf3BytesChars := 0; + utf4BytesChars := 0; + sjisBytesLeft := 0; + sjisKatakanaChars := 0; + sjisCurKatakanaWordLength := 0; + sjisCurDoubleBytesWordLength := 0; + sjisMaxKatakanaWordLength := 0; + sjisMaxDoubleBytesWordLength := 0; + isoHighOther := 0; + + utf8bom := ((((length(bytes) > 3) and (bytes[0] = $EF)) and (bytes[1] = $BB)) + and (bytes[2] = $BF)); + + i := 0; + while (((i < len) and ((canBeISO88591 or canBeShiftJIS) or canBeUTF8))) do + begin + value := (bytes[i] and $FF); + if (canBeUTF8) then + if (utf8BytesLeft > 0) then + if ((value and $80) = 0) then + canBeUTF8 := false + else + dec(utf8BytesLeft) + else if ((value and $80) <> 0) then + if ((value and $40) = 0) then + canBeUTF8 := false + else + begin + inc(utf8BytesLeft); + if ((value and $20) = 0) then + inc(utf2BytesChars) + else + begin + inc(utf8BytesLeft); + if ((value and $10) = 0) then + inc(utf3BytesChars) + else + begin + inc(utf8BytesLeft); + if ((value and 8) = 0) then + inc(utf4BytesChars) + else + canBeUTF8 := false + end + end + end; + + if (canBeISO88591) then + if ((value > $7F) and (value < 160)) then + canBeISO88591 := false + else if ((value > $9F) and (((value < $C0) or (value = $D7)) or + (value = $F7))) then + inc(isoHighOther); + + if (canBeShiftJIS) then + if (sjisBytesLeft > 0) then + if (((value < $40) or (value = $7F)) or (value > $FC)) then + canBeShiftJIS := false + else + dec(sjisBytesLeft) + else if (((value = $80) or (value = 160)) or (value > $EF)) then + canBeShiftJIS := false + else if ((value > 160) and (value < $E0)) then + begin + inc(sjisKatakanaChars); + sjisCurDoubleBytesWordLength := 0; + inc(sjisCurKatakanaWordLength); + if (sjisCurKatakanaWordLength > sjisMaxKatakanaWordLength) then + sjisMaxKatakanaWordLength := sjisCurKatakanaWordLength + end + else if (value > $7F) then + begin + inc(sjisBytesLeft); + sjisCurKatakanaWordLength := 0; + inc(sjisCurDoubleBytesWordLength); + if (sjisCurDoubleBytesWordLength > sjisMaxDoubleBytesWordLength) then + sjisMaxDoubleBytesWordLength := sjisCurDoubleBytesWordLength + end + else + begin + sjisCurKatakanaWordLength := 0; + sjisCurDoubleBytesWordLength := 0 + end; + inc(i) + end; + + if (canBeUTF8 and (utf8BytesLeft > 0)) then + canBeUTF8 := false; + + if (canBeShiftJIS and (sjisBytesLeft > 0)) then + canBeShiftJIS := false; + + if (canBeUTF8 and (utf8bom or (((utf2BytesChars + utf3BytesChars) + + utf4BytesChars) > 0))) then + begin + Result := 'UTF-8'; + exit + end; + + if (canBeShiftJIS and ((TStringUtils.ASSUME_SHIFT_JIS or + (sjisMaxKatakanaWordLength >= 3)) or (sjisMaxDoubleBytesWordLength >= 3))) + then + begin + Result := TStringUtils.SHIFT_JIS; + exit + end; + + if (canBeISO88591 and canBeShiftJIS) then + begin + + if (((sjisMaxKatakanaWordLength = 2) and (sjisKatakanaChars = 2)) or + ((isoHighOther * 10) >= len)) then + Result := TStringUtils.SHIFT_JIS + else + Result := 'ISO-8859-1'; + exit + end; + + if (canBeISO88591) then + begin + Result := 'ISO-8859-1'; + exit + end; + + if (canBeShiftJIS) then + begin + Result := TStringUtils.SHIFT_JIS; + exit + end; + + if (canBeUTF8) then + begin + Result := 'UTF-8'; + exit + end; + + Result := TStringUtils.PLATFORM_DEFAULT_ENCODING; + +end; + +Initialization + +TStringUtils.ClassInit; + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.BaseLuminanceSource.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.BaseLuminanceSource.pas new file mode 100644 index 0000000..ad08219 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.BaseLuminanceSource.pas @@ -0,0 +1,254 @@ +{ + * 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: dswitkin@google.com (Daniel Switkin) + * Delphi Implementation by K. Gossens +} + +unit ZXing.BaseLuminanceSource; + +interface +uses + System.SysUtils, + System.UITypes, +{$IFDEF FRAMEWORK_FMX} + FMX.Graphics, +{$ENDIF} +{$IFDEF FRAMEWORK_VCL} + VCL.Graphics, +{$ENDIF} + ZXing.LuminanceSource, + ZXing.InvertedLuminanceSource; + +type + /// + /// The base class for luminance sources which supports + /// cropping and rotating based upon the luminance values. + /// + TBaseLuminanceSource = class abstract (TLuminanceSource) + protected + luminances: TArray; + + const + RChannelWeight : Integer = 19562; + GChannelWeight : Integer = 38550; + BChannelWeight : Integer = 7424; + ChannelWeight : Integer = 16; + + function CreateLuminanceSource(const newLuminances: TArray; + const width, height: Integer): TLuminanceSource; virtual; abstract; + public + + // added the "reintroduce" keyword to shut off the "method hides another method with the same name in the base class" + constructor Create(const width, height: Integer); reintroduce; overload; + constructor Create(const luminanceArray: TArray; const width, height: Integer); reintroduce; overload; + + function getRow(const y: Integer; row: TArray): TArray; override; + function rotateCounterClockwise(): TLuminanceSource; override; + function rotateCounterClockwise45(): TLuminanceSource; override; + function crop(const left, top, + width, height: Integer): TLuminanceSource; override; + + function Matrix: TArray; override; + function RotateSupported: Boolean; override; + function InversionSupported: Boolean; override; + function CropSupported: Boolean; override; + function invert(): TLuminanceSource; override; + end; + +implementation + +{ TBaseLuminanceSource } + +constructor TBaseLuminanceSource.Create(const width, height: Integer); +begin + inherited Create(width, height); + + luminances := TArray.Create(); + SetLength(luminances, (width * height)); +end; + +/// +/// Initializes a new instance of the class. +/// +/// The luminance array. +/// The width. +/// The height. +constructor TBaseLuminanceSource.Create(const luminanceArray: TArray; + const width, height: Integer); +begin + Self.Create(width, height); + Copy(luminanceArray, 0, Length(luminances)); +end; + +/// +/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from +/// 0 (black) to 255 (white). It is preferable for implementations of this method +/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and +/// getMatrix() may never be called. +/// +/// The row to fetch, 0 <= y < Height. +/// An optional preallocated array. If null or too small, it will be ignored. +/// Always use the returned object, and ignore the .length of the array. +/// +/// An array containing the luminance data. +/// +function TBaseLuminanceSource.getRow(const y: Integer; + row: TArray): TArray; +var + i, width: Integer; +begin + width := Self.Width; + if ((row = nil) or (Length(row) < width)) then + begin + row := nil; + row := TArray.Create(); + SetLength(row, width); + end; + + for i := 0 to Pred(width) do + row[i] := luminances[y * width + i]; + + Result := row; +end; + +function TBaseLuminanceSource.Matrix: TArray; +begin + Result := luminances; +end; + +/// +/// Returns a new object with rotated image data by 90 degrees counterclockwise. +/// Only callable if {@link #isRotateSupported()} is true. +/// +/// +/// A rotated version of this object. +/// +function TBaseLuminanceSource.rotateCounterClockwise(): TLuminanceSource; +var + rotatedLuminances : TArray; + newWidth, + newHeight : Integer; + localLuminances : TArray; + yold, ynew, + xold, xnew : Integer; +begin + rotatedLuminances := TArray.Create(); + SetLength(rotatedLuminances, (Width * Height)); + + newWidth := Height; + newHeight := Width; + localLuminances := Matrix; + for yold := 0 to Pred(Height) do + begin + for xold := 0 to Pred(Width) do + begin + ynew := newHeight - xold - 1; + xnew := yold; + rotatedLuminances[ynew * newWidth + xnew] := localLuminances[yold * Width + xold]; + end; + end; + Result := CreateLuminanceSource(rotatedLuminances, newWidth, newHeight); +end; + +/// +/// TODO: not implemented yet +/// +/// +/// A rotated version of this object. +/// +function TBaseLuminanceSource.rotateCounterClockwise45(): TLuminanceSource; +begin + // TODO: implement a good 45 degrees rotation without lost of information + Result := inherited rotateCounterClockwise45(); +end; + +/// +/// +/// Whether this subclass supports counter-clockwise rotation. +function TBaseLuminanceSource.RotateSupported: Boolean; +begin + Result := true; +end; + +/// +/// Returns a new object with cropped image data. Implementations may keep a reference to the +/// original data rather than a copy. Only callable if CropSupported is true. +/// +/// The left coordinate, 0 <= left < Width. +/// The top coordinate, 0 <= top <= Height. +/// The width of the rectangle to crop. +/// The height of the rectangle to crop. +/// +/// A cropped version of this object. +/// +function TBaseLuminanceSource.Crop(const left, top, + width, height: Integer): TLuminanceSource; +var + croppedLuminances, + oldLuminances : TArray; + oldWidth, + oldRightBound, + oldBottomBound : Integer; + yold, ynew, + xold, xnew : Integer; +begin + if ((left + width > Self.Width) or (top + height > Self.Height)) + then + raise EArgumentException.Create('Crop rectangle does not fit within image data.'); + + croppedLuminances := TArray.Create(); + SetLength(croppedLuminances, (width * height)); + oldLuminances := Self.Matrix; + oldWidth := Self.Width; + oldRightBound := left + width; + oldBottomBound := top + height; + ynew := 0; + for yold := top to Pred(oldBottomBound) do + begin + xnew := 0; + for xold := left to Pred(oldRightBound) do + croppedLuminances[ynew * width + xnew] := oldLuminances[yold * oldWidth + xold]; + Inc(ynew); + end; + + Result := CreateLuminanceSource(croppedLuminances, width, height); +end; + +/// +/// +/// Whether this subclass supports cropping. +function TBaseLuminanceSource.CropSupported: Boolean; +begin + Result := true; +end; + +/// +/// +/// Whether this subclass supports invertion. +function TBaseLuminanceSource.InversionSupported: Boolean; +begin + Result := true; +end; + + /// +/// Inverts the luminance values (newValue = 255 - oldValue) +/// +function TBaseLuminanceSource.invert(): TLuminanceSource; +begin + Result := TInvertedLuminanceSource.Create(Self); +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.Binarizer.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.Binarizer.pas new file mode 100644 index 0000000..f39a141 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.Binarizer.pas @@ -0,0 +1,121 @@ +unit ZXing.Binarizer; +{ + * Copyright 2009 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. + + * 2015-3 Adapted for Delphi/Object Pascal FireMonkey XE7 mobile by E.Spelt +} + +interface + +uses + System.SysUtils, + ZXing.LuminanceSource, + ZXing.Common.BitArray, + ZXing.Common.BitMatrix; + +type + + /// This class hierarchy provides a set of methods to convert luminance data to 1 bit data. + /// It allows the algorithm to vary polymorphically, for example allowing a very expensive + /// thresholding technique for servers and a fast one for mobile. It also permits the implementation + /// to vary, e.g. a JNI version for Android and a Java fallback version for other platforms. + /// + /// dswitkin@google.com (Daniel Switkin) + /// + TBinarizer = class + private + FSource: TLuminanceSource; + function GetWidth: Integer; + function GetHeight: Integer; + protected + /// + /// Initializes a new instance of the class. + /// + /// The source. + constructor Create(source: TLuminanceSource); + + /// Converts one row of luminance data to 1 bit data. May actually do the conversion, or return + /// cached data. Callers should assume this method is expensive and call it as seldom as possible. + /// This method is intended for decoding 1D barcodes and may choose to apply sharpening. + /// For callers which only examine one row of pixels at a time, the same BitArray should be reused + /// and passed in with each call for performance. However it is legal to keep more than one row + /// at a time if needed. + /// + /// The row to fetch, which must be in [0, bitmap height) + /// An optional preallocated array. If null or too small, it will be ignored. + /// If used, the Binarizer will call BitArray.clear(). Always use the returned object. + /// + /// The array of bits for this row (true means black). + public + function LuminanceSource(): TLuminanceSource; + function GetBlackRow(y: Integer; row: IBitArray): IBitArray; + virtual; abstract; + + function BlackMatrix: TBitMatrix; virtual; abstract; + destructor Destroy();override; + + /// Creates a new object with the same type as this Binarizer implementation, but with pristine + /// state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache + /// of 1 bit data. See Effective Java for why we can't use Java's clone() method. + /// + /// The LuminanceSource this Binarizer will operate on. + /// A new concrete Binarizer implementation object. + function createBinarizer(source: TLuminanceSource): TBinarizer; + virtual; abstract; + + property Width: Integer read GetWidth; + property Height: Integer read GetHeight; + + + + end; + +implementation + +{ TBinarizer } + +constructor TBinarizer.Create(source: TLuminanceSource); +begin + + if (source = nil) then + begin + raise EArgumentException.Create('Source must be non-null.'); + end; + + Self.FSource := source; + +end; + +destructor TBinarizer.Destroy; +begin + inherited; +end; + +function TBinarizer.GetHeight: Integer; +begin + Result:= FSource.Height; +end; + +function TBinarizer.GetWidth: Integer; +begin + result := FSource.Width; +end; + +function TBinarizer.LuminanceSource: TLuminanceSource; +begin + result := Self.FSource; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.BinaryBitmap.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.BinaryBitmap.pas new file mode 100644 index 0000000..bafd0e5 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.BinaryBitmap.pas @@ -0,0 +1,124 @@ +{ + * 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. + + * Implemented by E. Spelt for Delphi +} + +unit ZXing.BinaryBitmap; + +interface + +uses + System.SysUtils, + ZXing.Binarizer, + ZXing.LuminanceSource, + ZXing.Common.BitArray, + ZXing.Common.BitMatrix; + +type + TBinaryBitmap = class + private + Binarizer: TBinarizer; + Matrix: TBitMatrix; + function GetWidth: Integer; + function GetHeight: Integer; + function GetBlackMatrix: TBitMatrix; + public + constructor Create(Binarizer: TBinarizer); + destructor Destroy(); override; + /// + /// Converts one row of luminance data to 1 bit data. May actually do the conversion, or return + /// cached data. Callers should assume this method is expensive and call it as seldom as possible. + /// This method is intended for decoding 1D barcodes and may choose to apply sharpening. + /// + /// The row to fetch, which must be in [0, bitmap height). + /// An optional preallocated array. If null or too small, it will be ignored. + /// If used, the Binarizer will call BitArray.clear(). Always use the returned object. + /// + /// The array of bits for this row (true means black). + function getBlackRow(y: Integer; row: IBitArray): IBitArray; + function RotateSupported: Boolean; + function rotateCounterClockwise(): TBinaryBitmap; + + property Width: Integer read GetWidth; + property Height: Integer read GetHeight; + property BlackMatrix: TBitMatrix read GetBlackMatrix; + end; + +implementation + +{ TBinaryBitmap } + +constructor TBinaryBitmap.Create(Binarizer: TBinarizer); +begin + + if (Binarizer = nil) then + begin + raise EArgumentException.Create('Binarizer must be non-null.'); + end; + + Self.Binarizer := Binarizer; + +end; + +destructor TBinaryBitmap.Destroy; +begin + if Assigned(Matrix) then + FreeAndNil(Matrix); + + //FreeAndNil(Binarizer); + inherited; +end; + +function TBinaryBitmap.GetBlackMatrix: TBitMatrix; +begin + if (Matrix = nil) then + begin + Matrix := Binarizer.BlackMatrix(); + end; + + result := Matrix; + +end; + +function TBinaryBitmap.getBlackRow(y: Integer; row: IBitArray): IBitArray; +begin + result := Binarizer.getBlackRow(y, row); +end; + +function TBinaryBitmap.GetHeight: Integer; +begin + result := Binarizer.Height; +end; + +function TBinaryBitmap.GetWidth: Integer; +begin + result := Binarizer.Width; +end; + +function TBinaryBitmap.rotateCounterClockwise: TBinaryBitmap; +var + newSource: TLuminanceSource; +begin + newSource := Binarizer.LuminanceSource.rotateCounterClockwise(); + result := TBinaryBitmap.Create(Binarizer.createBinarizer(newSource)); +end; + +function TBinaryBitmap.RotateSupported: Boolean; +begin + result := Binarizer.LuminanceSource.RotateSupported(); +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.GlobalHistogramBinarizer.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.GlobalHistogramBinarizer.pas new file mode 100644 index 0000000..9ede1cd --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.GlobalHistogramBinarizer.pas @@ -0,0 +1,249 @@ +unit ZXing.GlobalHistogramBinarizer; +{ + * Copyright 2009 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. + + * 2015-3 Adapted for Delphi/Object Pascal FireMonkey XE7 mobile by E.Spelt +} + +interface + +uses + SysUtils, + ZXing.Binarizer, + ZXing.LuminanceSource, + ZXing.Common.BitArray, + ZXing.Common.Detector.MathUtils; + +type + TGlobalHistogramBinarizer = class(TBinarizer) + private + + class var LUMINANCE_BITS, LUMINANCE_SHIFT, LUMINANCE_BUCKETS: Integer; + EMPTY: TArray; + + luminances: TArray; + buckets: TArray; + procedure InitArrays(luminanceSize: Integer); + function estimateBlackPoint(buckets: TArray; + var blackPoint: Integer): Boolean; + class procedure ClassInit; static; + + public + constructor Create(source: TLuminanceSource); + + // constructor GlobalHistogramBinarizer(source: TLuminanceSource); + function GetBlackRow(y: Integer; row: IBitArray): IBitArray; override; + end; + +implementation + +{ TGlobalHistogramBinarizer } + +class procedure TGlobalHistogramBinarizer.ClassInit(); +begin + LUMINANCE_BITS := 5; + LUMINANCE_SHIFT := 8 - LUMINANCE_BITS; + LUMINANCE_BUCKETS := 1 shl LUMINANCE_BITS; + EMPTY := TArray.Create(); + SetLength(EMPTY, 0); +end; + +constructor TGlobalHistogramBinarizer.Create(source: TLuminanceSource); +begin + inherited Create(source); + luminances := EMPTY; + buckets := TArray.Create(); + SetLength(self.buckets, LUMINANCE_BUCKETS); +end; + +{ + constructor TGlobalHistogramBinarizer.GlobalHistogramBinarizer + (source: TLuminanceSource); + begin + Inherited Create(source); + + + + SetLength(luminances, 0); + SetLength(buckets, LUMINANCE_BUCKETS); + end; +} + +function TGlobalHistogramBinarizer.GetBlackRow(y: Integer; row: IBitArray) + : IBitArray; +var + localLuminances: TArray; + localBuckets: TArray; + i, w, blackPoint, x, pixel, left, right, center, luminance: Integer; +begin + w := width; + if ((row = nil) or (row.Size < w)) then + begin + row := TBitArrayHelpers.CreateBitArray(w); + end + else + begin + row.Clear(); + end; + + InitArrays(w); + localLuminances := LuminanceSource.getRow(y, luminances); + localBuckets := buckets; + + for x := 0 to w - 1 do + begin + pixel := localLuminances[x] and $FF; + i := TMathUtils.Asr(pixel, LUMINANCE_SHIFT); + localBuckets[i] := localBuckets[i] + 1; + end; + + if (not estimateBlackPoint(localBuckets, blackPoint)) then + begin + result := nil; + exit; + end; + + left := localLuminances[0] and $FF; + center := localLuminances[1] and $FF; + + for x := 1 to w - 2 do + begin + + right := localLuminances[x + 1] and $FF; + // A simple -1 4 -1 box filter with a weight of 2. + + luminance := (center shl 2) - left - right; + luminance := TMathUtils.Asr(luminance, 1); + row[x] := (luminance < blackPoint); + left := center; + center := right; + end; + + result := row; + +end; + +procedure TGlobalHistogramBinarizer.InitArrays(luminanceSize: Integer); +var + x: Integer; +begin + + if (Length(luminances) < luminanceSize) then + begin + SetLength(luminances, luminanceSize); + end; + + for x := 0 to LUMINANCE_BUCKETS - 1 do + begin + buckets[x] := 0; + end; + +end; + +function TGlobalHistogramBinarizer.estimateBlackPoint(buckets: TArray; + var blackPoint: Integer): Boolean; + +var + x, numBuckets, maxBucketCount, firstPeak, firstPeakSize, secondPeak, + secondPeakScore, distanceToBiggest, score, temp, bestValley, + bestValleyScore, fromFirst: Integer; + +begin + blackPoint := 0; + + // Find the tallest peak in the histogram. + numBuckets := Length(buckets); + maxBucketCount := 0; + firstPeak := 0; + firstPeakSize := 0; + + for x := 0 to numBuckets - 1 do + begin + + if (buckets[x] > firstPeakSize) then + begin + firstPeak := x; + firstPeakSize := buckets[x]; + end; + + if (buckets[x] > maxBucketCount) then + begin + maxBucketCount := buckets[x]; + end; + + end; + + // Find the second-tallest peak which is somewhat far from the tallest peak. + secondPeak := 0; + secondPeakScore := 0; + for x := 0 to numBuckets - 1 do + begin + distanceToBiggest := x - firstPeak; + // Encourage more distant second peaks by multiplying by square of distance. + score := buckets[x] * distanceToBiggest * distanceToBiggest; + if (score > secondPeakScore) then + begin + secondPeak := x; + secondPeakScore := score; + end; + end; + + // Make sure firstPeak corresponds to the black peak. + if (firstPeak > secondPeak) then + begin + temp := firstPeak; + firstPeak := secondPeak; + secondPeak := temp; + end; + + // If there is too little contrast in the image to pick a meaningful black point, throw rather + // than waste time trying to decode the image, and risk false positives. + // TODO: It might be worth comparing the brightest and darkest pixels seen, rather than the + // two peaks, to determine the contrast. + if ((secondPeak - firstPeak) <= (TMathUtils.Asr(numBuckets, 4))) then + begin + result := false; + exit; + end; + + // Find a valley between them that is low and closer to the white peak. + bestValley := secondPeak - 1; + bestValleyScore := -1; + + x := secondPeak - 1; + while (x > firstPeak) do + begin + fromFirst := x - firstPeak; + score := fromFirst * fromFirst * (secondPeak - x) * + (maxBucketCount - buckets[x]); + + if (score > bestValleyScore) then + begin + bestValley := x; + bestValleyScore := score; + end; + + Dec(x); + end; + + blackPoint := bestValley shl LUMINANCE_SHIFT; + result := true; +end; + +Initialization + +TGlobalHistogramBinarizer.ClassInit(); + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.HybridBinarizer.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.HybridBinarizer.pas new file mode 100644 index 0000000..c9daae2 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.HybridBinarizer.pas @@ -0,0 +1,330 @@ +unit ZXing.HybridBinarizer; +{ + * Copyright 2009 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. + + * 2015-3 Adapted for Delphi/Object Pascal FireMonkey XE7 mobile by E.Spelt +} + +interface + +uses + SysUtils, + ZXing.GlobalHistogramBinarizer, + ZXing.LuminanceSource, + ZXing.Common.BitMatrix, + ZXing.binarizer, + ZXing.Common.Detector.MathUtils; + +/// This class implements a local thresholding algorithm, which while slower than the +/// GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for +/// high frequency images of barcodes with black data on white backgrounds. For this application, +/// it does a much better job than a global blackpoint with severe shadows and gradients. +/// However it tends to produce artifacts on lower frequency images and is therefore not +/// a good general purpose binarizer for uses outside ZXing. +/// +/// This class extends GlobalHistogramBinarizer, using the older histogram approach for 1D readers, +/// and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already +/// inherently local, and only fails for horizontal gradients. We can revisit that problem later, +/// but for now it was not a win to use local blocks for 1D. +/// +/// This Binarizer is the default for the unit tests and the recommended class for library users. +/// +/// +/// dswitkin@google.com (Daniel Switkin) +/// +/// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source +/// +/// Adapted for Delphi/Object Pascal FireMonkey XE7 mobile by E.Spelt +/// + +type + TArrayIntOfInt = TArray>; + + THybridBinarizer = class(TGlobalHistogramBinarizer) + private + matrix: TBitMatrix; + procedure BinarizeEntireImage; + procedure calculateThresholdForBlock(luminances: TArray; + subWidth: Integer; subHeight: Integer; width: Integer; height: Integer; + blackPoints: TArrayIntOfInt; matrix: TBitMatrix); + function calculateBlackPoints(luminances: TArray; subWidth: Integer; + subHeight: Integer; width: Integer; height: Integer): TArrayIntOfInt; + procedure thresholdBlock(luminances: TArray; xoffset: Integer; + yoffset: Integer; threshold: Integer; stride: Integer; + matrix: TBitMatrix); + function cap(value: Integer; min: Integer; max: Integer): Integer; + protected + // + public + function createBinarizer(source: TLuminanceSource): TBinarizer; override; + + constructor Create(source: TLuminanceSource); + function BlackMatrix: TBitMatrix; override; + end; + +implementation + +{ THybridBinarizer } + +function THybridBinarizer.BlackMatrix: TBitMatrix; +begin + BinarizeEntireImage(); + result := matrix; +end; + +function THybridBinarizer.createBinarizer(source: TLuminanceSource): TBinarizer; +begin + result := THybridBinarizer.Create(source) +end; + +procedure THybridBinarizer.BinarizeEntireImage; +var + source: TLuminanceSource; + luminances: TArray; + subWidth, subHeight, width, height: Integer; + blackPoints: TArrayIntOfInt; + newMatrix: TBitMatrix; +begin + if (self.matrix <> nil) then + begin + inherited BlackMatrix; + Exit; + end; + + try + + source := self.LuminanceSource; + width := source.width; + height := source.height; + + if ((width >= 40) and (height >= 40)) then + begin + luminances := source.matrix; + subWidth := TMathUtils.Asr(width, 3); + + if ((width and 7) <> 0) then + inc(subWidth); + + subHeight := TMathUtils.Asr(height, 3); + + if ((height and 7) <> 0) then + inc(subHeight); + + blackPoints := calculateBlackPoints(luminances, subWidth, subHeight, + width, height); + + newMatrix := TBitMatrix.Create(width, height); + calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, + blackPoints, newMatrix); + + self.matrix := newMatrix; + end; + + finally + SetLength(blackPoints,0); + blackPoints := nil; + luminances := nil; + end; +end; + +function THybridBinarizer.calculateBlackPoints(luminances: TArray; + subWidth: Integer; subHeight: Integer; width: Integer; height: Integer) + : TArrayIntOfInt; +var + blackPoints: TArrayIntOfInt; + i, x, y, yoffset, maxYOffset, xoffset, maxXOffset, sum, min, max, yy, offset, + xx, pixel, average, averageNeighborBlackPoint: Integer; + +begin + blackPoints := TArrayIntOfInt.Create(); + SetLength(blackPoints, subHeight); + i := 0; + + while ((i < subHeight)) do + begin + blackPoints[i] := TArray.Create(); + SetLength(blackPoints[i], subWidth); + inc(i) + end; + + y := 0; + + while ((y < subHeight)) do + begin + + yoffset := (y shl 3); + maxYOffset := (height - 8); + + if (yoffset > maxYOffset) then + yoffset := maxYOffset; + x := 0; + + while ((x < subWidth)) do + begin + xoffset := (x shl 3); + maxXOffset := (width - 8); + if (xoffset > maxXOffset) then + xoffset := maxXOffset; + sum := 0; + min := $FF; + max := 0; + yy := 0; + offset := ((yoffset * width) + xoffset); + + while ((yy < 8)) do + begin + xx := 0; + while ((xx < 8)) do + begin + pixel := (luminances[(offset + xx)] and $FF); + inc(sum, pixel); + if (pixel < min) then + min := pixel; + if (pixel > max) then + max := pixel; + inc(xx) + end; + + if ((max - min) > $18) then + begin + inc(yy); + inc(offset, width); + while ((yy < 8)) do + begin + xx := 0; + while ((xx < 8)) do + begin + inc(sum, (luminances[(offset + xx)] and $FF)); + inc(xx) + end; + inc(yy); + inc(offset, width) + end + end; + inc(yy); + inc(offset, width) + end; + + average := TMathUtils.Asr(sum, 6); + if ((max - min) <= $18) then + begin + average := TMathUtils.Asr(min, 1); + if ((y > 0) and (x > 0)) then + begin + averageNeighborBlackPoint := + TMathUtils.Asr + (((blackPoints[(y - 1)][x] + (2 * blackPoints[y][(x - 1)])) + + blackPoints[(y - 1)][(x - 1)]), 2); + if (min < averageNeighborBlackPoint) then + average := averageNeighborBlackPoint + end + end; + blackPoints[y][x] := average; + inc(x) + end; + inc(y) + end; + + result := blackPoints; +end; + +procedure THybridBinarizer.calculateThresholdForBlock(luminances: TArray; + subWidth: Integer; subHeight: Integer; width: Integer; height: Integer; + blackPoints: TArrayIntOfInt; matrix: TBitMatrix); +var + y, yoffset, maxYOffset, x, xoffset, maxXOffset, left, top, sum, z, + average: Integer; + blackRow: TArray; +begin + y := 0; + while ((y < subHeight)) do + begin + yoffset := (y shl 3); + maxYOffset := (height - 8); + if (yoffset > maxYOffset) then + yoffset := maxYOffset; + x := 0; + while ((x < subWidth)) do + begin + xoffset := (x shl 3); + maxXOffset := (width - 8); + if (xoffset > maxXOffset) then + xoffset := maxXOffset; + left := cap(x, 2, (subWidth - 3)); + top := cap(y, 2, (subHeight - 3)); + sum := 0; + z := -2; + while ((z <= 2)) do + begin + blackRow := blackPoints[(top + z)]; + inc(sum, blackRow[(left - 2)]); + inc(sum, blackRow[(left - 1)]); + inc(sum, blackRow[left]); + inc(sum, blackRow[(left + 1)]); + inc(sum, blackRow[(left + 2)]); + inc(z) + end; + average := (sum div $19); + thresholdBlock(luminances, xoffset, yoffset, average, width, matrix); + inc(x) + end; + inc(y) + end +end; + +constructor THybridBinarizer.Create(source: TLuminanceSource); +begin + inherited Create(source); +end; + +procedure THybridBinarizer.thresholdBlock(luminances: TArray; + xoffset: Integer; yoffset: Integer; threshold: Integer; stride: Integer; + matrix: TBitMatrix); +var + offset, x, y, pixel: Integer; +begin + offset := ((yoffset * stride) + xoffset); + y := 0; + while ((y < 8)) do + begin + x := 0; + while ((x < 8)) do + begin + pixel := (luminances[(offset + x)] and $FF); + matrix[(xoffset + x), (yoffset + y)] := (pixel <= threshold); + inc(x) + end; + inc(y); + inc(offset, stride) + end +end; + +function THybridBinarizer.cap(value: Integer; min: Integer; + max: Integer): Integer; +begin + + if (value < min) then + begin + result := min + end + else if (value > max) then + begin + result := max + end + else + result := value +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.InvertedLuminanceSource.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.InvertedLuminanceSource.pas new file mode 100644 index 0000000..c67e549 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.InvertedLuminanceSource.pas @@ -0,0 +1,159 @@ +{ + * Copyright 2013 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: dswitkin@google.com (Daniel Switkin) + * Delphi Implementation by K. Gossens +} + +unit ZXing.InvertedLuminanceSource; + +interface + +uses + System.SysUtils, + ZXing.LuminanceSource; + +type + TInvertedLuminanceSource = class sealed(TLuminanceSource) + private + delegate: TLuminanceSource; + invertedMatrix: TArray; + public + constructor Create(delegate: TLuminanceSource); reintroduce; + + function crop(const left, top, width, height: Integer): TLuminanceSource; override; + function getRow(const y: Integer; row: TArray): TArray; override; + function rotateCounterClockwise(): TLuminanceSource; override; + function rotateCounterClockwise45(): TLuminanceSource; override; + + function invert: TLuminanceSource; override; + function Matrix: TArray; override; + function CropSupported: Boolean; override; + function RotateSupported: Boolean; override; + end; + +implementation + +{ TInvertedLuminanceSource } + +/// +/// Initializes a new instance of the class. +/// +/// The @delegate. +constructor TInvertedLuminanceSource.Create(delegate: TLuminanceSource); +begin + inherited Create(delegate.Width, delegate.Height); + Self.delegate := delegate; +end; + +/// +/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from +/// 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have +/// to bitwise and with 0xff for each value. It is preferable for implementations of this method +/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and +/// getMatrix() may never be called. +/// +/// The row to fetch, 0 <= y < Height. +/// An optional preallocated array. If null or too small, it will be ignored. +/// Always use the returned object, and ignore the .length of the array. +/// +/// An array containing the luminance data. +/// +function TInvertedLuminanceSource.getRow(const y: Integer; row: TArray): TArray; +var + rowArray : TArray; + i, width : Integer; +begin + rowArray := delegate.getRow(y, row); + width := Self.Width; + for i := 0 to Pred(width) do + rowArray[i] := (255 - (row[i] and $FF)); + + Result := rowArray; +end; + +/// +/// Fetches luminance data for the underlying bitmap. Values should be fetched using: +/// int luminance = array[y * width + x] & 0xff; +/// +/// A row-major 2D array of luminance values. Do not use result.length as it may be +/// larger than width * height bytes on some platforms. Do not modify the contents +/// of the result. +/// +function TInvertedLuminanceSource.Matrix: TArray; +var + matrixArray: TArray; + i, len: Integer; +begin + if (invertedMatrix = nil) then + begin + matrixArray := delegate.Matrix; + len := Self.Width * Self.Height; + invertedMatrix := TArray.Create(); + SetLength(invertedMatrix, len); + for i := 0 to Pred(len) do + invertedMatrix[i] := (255 - (matrixArray[i] and $FF)); + + Result := invertedMatrix; + end; +end; + +/// +/// +/// Whether this subclass supports cropping. +function TInvertedLuminanceSource.CropSupported: Boolean; +begin + Result := delegate.CropSupported; +end; + +/// +/// Returns a new object with cropped image data. Implementations may keep a reference to the +/// original data rather than a copy. Only callable if CropSupported is true. +/// +/// The left coordinate, 0 <= left < Width. +/// The top coordinate, 0 <= top <= Height. +/// The width of the rectangle to crop. +/// The height of the rectangle to crop. +/// +/// A cropped version of this object. +/// +function TInvertedLuminanceSource.crop(const left, top, + width, height: Integer): TLuminanceSource; +begin + Result := TInvertedLuminanceSource.Create(Self.delegate.crop(left, top, + width, height)); +end; + +function TInvertedLuminanceSource.invert: TLuminanceSource; +begin + Result := self.delegate; +end; + +function TInvertedLuminanceSource.rotateCounterClockwise(): TLuminanceSource; +begin + Result := TInvertedLuminanceSource.Create(Self.delegate.rotateCounterClockwise); +end; + +function TInvertedLuminanceSource.rotateCounterClockwise45(): TLuminanceSource; +begin + Result := TInvertedLuminanceSource.Create(Self.delegate.rotateCounterClockwise45); +end; + +function TInvertedLuminanceSource.RotateSupported: Boolean; +begin + Result := delegate.RotateSupported;; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.LuminanceSource.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.LuminanceSource.pas new file mode 100644 index 0000000..4c90fb3 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.LuminanceSource.pas @@ -0,0 +1,221 @@ +{ + * Copyright 2009 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: dswitkin@google.com (Daniel Switkin) + * Delphi Implementation by E.Spelt and K. Gossens +} + +unit ZXing.LuminanceSource; + +interface + +uses + System.SysUtils; + +type + /// + /// The purpose of this class hierarchy is to abstract different bitmap implementations across + /// platforms into a standard interface for requesting greyscale luminance values. The interface + /// only provides immutable methods; therefore crop and rotation create copies. This is to ensure + /// that one Reader does not modify the original luminance source and leave it in an unknown state + /// for other Readers in the chain. + /// + TLuminanceSource = class + protected + FWidth: Integer; + FHeight: Integer; + public + constructor Create(const width, height: Integer); virtual; + /// + /// Fetches luminance data for the underlying bitmap. Values should be fetched using: + /// int luminance = array[y * width + x] and 0xff + /// + /// + /// A row-major 2D array of luminance values. Do not use result.length as it may be + /// larger than width * height bytes on some platforms. Do not modify the contents + /// of the result. + /// + function Matrix: TArray; virtual; abstract; + /// + /// Fetches one row of luminance data from the underlying platform's bitmap. Values range from + /// 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have + /// to bitwise and with 0xff for each value. It is preferable for implementations of this method + /// to only fetch this row rather than the whole image, since no 2D Readers may be installed and + /// getMatrix() may never be called. + /// + /// The row to fetch, which must be in [0, bitmap height) + /// An optional preallocated array. If null or too small, it will be ignored. + /// Always use the returned object, and ignore the .length of the array. + /// + /// An array containing the luminance data. + function getRow(const y: Integer; row: TArray): TArray; + virtual; abstract; + + /// + /// Returns a new object with cropped image data. Implementations may keep a reference to the + /// original data rather than a copy. Only callable if CropSupported is true. + /// + /// The left coordinate, which must be in [0, Width) + /// The top coordinate, which must be in [0, Height) + /// The width of the rectangle to crop. + /// The height of the rectangle to crop. + /// A cropped version of this object. + function crop(const left, top, width, + height: Integer): TLuminanceSource; virtual; + function invert(): TLuminanceSource; virtual; + function ToString(): String; override; + + /// Whether this subclass supports counter-clockwise rotation. + function RotateSupported: Boolean; virtual; + /// Whether this subclass supports cropping. + function CropSupported(): Boolean; virtual; + /// Whether this subclass supports invertion. + function InversionSupported: Boolean; virtual; + + /// + /// Returns a new object with rotated image data by 90 degrees counterclockwise. + /// Only callable if is true. + /// + /// A rotated version of this object. + function rotateCounterClockwise(): TLuminanceSource; virtual; + /// + /// Returns a new object with rotated image data by 45 degrees counterclockwise. + /// Only callable if is true. + /// + /// A rotated version of this object. + function rotateCounterClockwise45(): TLuminanceSource; virtual; + + /// The height of the bitmap. + property Height: Integer read FHeight; + /// The width of the bitmap. + property Width: Integer read FWidth; + end; + +implementation + +constructor TLuminanceSource.Create(const width, height: Integer); +begin + FWidth := width; + FHeight := height; +end; + +function TLuminanceSource.CropSupported: Boolean; +begin + Result := False; +end; + +// Whether this subclass supports counter-clockwise rotation. +function TLuminanceSource.RotateSupported: Boolean; +begin + Result := False; +end; + +/// Whether this subclass supports invertion. +function TLuminanceSource.InversionSupported: Boolean; +begin + Result := False; +end; + +/// +/// Returns a new object with cropped image data. Implementations may keep a reference to the +/// original data rather than a copy. Only callable if CropSupported is true. +/// +/// The left coordinate, which must be in [0, Width) +/// The top coordinate, which must be in [0, Height) +/// The width of the rectangle to crop. +/// The height of the rectangle to crop. +/// A cropped version of this object. +function TLuminanceSource.Crop(const left, top, + width, height: Integer): TLuminanceSource; +begin + raise ENotImplemented.Create + ('This luminance source does not support cropping.'); +end; + +/// +/// Returns a new object with rotated image data by 90 degrees counterclockwise. +/// Only callable if is true. +/// +/// A rotated version of this object. +function TLuminanceSource.rotateCounterClockwise(): TLuminanceSource; +begin + raise ENotImplemented.Create + ('This luminance source does not support rotation.'); +end; + +/// +/// Returns a new object with rotated image data by 45 degrees counterclockwise. +/// Only callable if is true. +/// +/// A rotated version of this object. +function TLuminanceSource.rotateCounterClockwise45(): TLuminanceSource; +begin + raise ENotImplemented.Create + ('This luminance source does not support rotation by 45 degrees.'); +end; + +function TLuminanceSource.invert(): TLuminanceSource; +begin + raise ENotImplemented.Create + ('This luminance source does not support inversion.'); +end; + +function TLuminanceSource.ToString(): String; +var + row: TArray; + res: TStringBuilder; + x, y, + luminance: Integer; + c: char; +begin + row := TArray.Create(); + SetLength(row, FWidth); + + res := TStringBuilder.Create(height * (width + 1)); + try + for y := 0 to FHeight - 1 do + begin + row := GetRow(y, row); + for x := 0 to Pred(FWidth) do + begin + luminance := row[x] and $FF; + if (luminance < $40) + then + c := '#' + else + if (luminance < $80) + then + c := '+' + else + if (luminance < $C0) + then + c := '.' + else + c := ' '; + + res.Append(c); + end; + + res.Append(#10); + end; + finally + row := nil; // ES: can become a be a big memory hog, so release it as quickly as possible. + Result := res.ToString; + res.Free; + end; + +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.PlanarYUVLuminanceSource.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.PlanarYUVLuminanceSource.pas new file mode 100644 index 0000000..d14968c --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.PlanarYUVLuminanceSource.pas @@ -0,0 +1,327 @@ +{ + * Copyright 2009 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: dswitkin@google.com (Daniel Switkin) + * Delphi Implementation K. Gossens +} + +unit ZXing.PlanarYUVLuminanceSource; + +interface +uses + System.SysUtils, + System.UITypes, + System.TypInfo, + ZXing.LuminanceSource, + ZXing.BaseLuminanceSource; + +type + /// + /// Luminance source class which support different formats of images. + /// + TPlanarYUVLuminanceSource = class(TBaseLuminanceSource) + private + yuvData : TArray; + dataWidth, + dataHeight, + left, top : Integer; + + const + THUMBNAIL_SCALE_FACTOR : Integer = 2; + + procedure reverseHorizontal(const width, height: Integer); + protected + function CreateLuminanceSource(const newLuminances: TArray; + const width, height: Integer): TLuminanceSource; override; + public + constructor Create(const yuvData: TArray; + const dataWidth, dataHeight, left, top, width, height: Integer; + const reverseHoriz: Boolean); overload; + constructor Create(const luminances: TArray; + const width, height: Integer); overload; + + function getRow(const y: Integer; row: TArray): TArray; override; + function crop(const left, top, + width, height: Integer): TLuminanceSource; override; + + function Matrix: TArray; override; + function CropSupported: Boolean; override; + + function renderThumbnail(): TArray; + function ThumbnailWidth(): Integer; + function ThumbnailHeight(): Integer; + + end; + +implementation + +/// +/// Initializes a new instance of the class. +/// +/// The yuv data. +/// Width of the data. +/// Height of the data. +/// The left. +/// The top. +/// The width. +/// The height. +/// if set to true [reverse horiz]. +constructor TPlanarYUVLuminanceSource.Create(const yuvData: TArray; + const dataWidth, dataHeight, left, top, width, height: Integer; + const reverseHoriz: Boolean); +begin + inherited Create(width, height); + + if ((left + width > dataWidth) or (top + height > dataHeight)) + then + raise EArgumentException.Create('Crop rectangle does not fit within image data.'); + + Self.yuvData := yuvData; + Self.dataWidth := dataWidth; + Self.dataHeight := dataHeight; + Self.left := left; + Self.top := top; + if (reverseHoriz) + then + reverseHorizontal(width, height); +end; + +/// +/// Initializes a new instance of the class. +/// +/// The luminances. +/// The width. +/// The height. +constructor TPlanarYUVLuminanceSource.Create(const luminances: TArray; + const width, height: Integer); +begin + inherited Create(width, height); + + Self.yuvData := luminances; + Self.luminances := luminances; + Self.dataWidth := width; + Self.dataHeight := height; + Self.left := 0; + Self.top := 0; +end; + +/// +/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from +/// 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have +/// to bitwise and with 0xff for each value. It is preferable for implementations of this method +/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and +/// getMatrix() may never be called. +/// +/// The row to fetch, 0 <= y < Height. +/// An optional preallocated array. If null or too small, it will be ignored. +/// Always use the returned object, and ignore the .length of the array. +/// +/// An array containing the luminance data. +/// + function TPlanarYUVLuminanceSource.getRow(const y: Integer; + row: TArray): TArray; + var + width, + offset: Integer; + begin + if ((y < 0) or (y >= Height)) + then + raise EArgumentException.Create('Requested row is outside the image: ' + IntToStr(y)); + + width := Self.Width; + if ((row = nil) or (Length(row) < width)) then + begin + row := nil; + row := TArray.Create(); + SetLength(row, width); + end; + + offset := (y + top) * dataWidth + left; + row := Copy(yuvData, offset, width); + + Result := row; +end; + +/// +/// +/// +function TPlanarYUVLuminanceSource.Matrix: TArray; +var + width, + height, + area, y : Integer; + inputOffset, + outputOffset : Integer; + matrix, + yuv: TArray; +begin + width := Self.Width; + height := Self.Height; + + // If the caller asks for the entire underlying image, save the copy and give them the + // original data. The docs specifically warn that result.length must be ignored. + if ((width = dataWidth) and (height = dataHeight)) then + begin + Result := Self.yuvData; + exit; + end; + + area := width * height; + matrix := TArray.Create(); + SetLength(matrix, area); + inputOffset := (top * dataWidth) + left; + + // If the width matches the full width of the underlying data, perform a single copy. + if (width = dataWidth) then + begin + matrix := Copy(yuvData, inputOffset, area); + Result := matrix; + exit; + end; + + // Otherwise copy one cropped row at a time. + yuv := yuvData; + for y := 0 to Pred(height) do + begin + outputOffset := y * width; + Move(yuv[inputOffSet], matrix[outputOffset], width); + Inc(inputOffset, dataWidth); + end; + + Result := matrix; +end; + +/// +/// +/// Whether this subclass supports cropping. +function TPlanarYUVLuminanceSource.CropSupported: Boolean; +begin + Result := true; +end; + +/// +/// Returns a new object with cropped image data. Implementations may keep a reference to the +/// original data rather than a copy. Only callable if CropSupported is true. +/// +/// The left coordinate, 0 <= left < Width. +/// The top coordinate, 0 <= top <= Height. +/// The width of the rectangle to crop. +/// The height of the rectangle to crop. +/// +/// A cropped version of this object. +/// +function TPlanarYUVLuminanceSource.crop(const left, top, + width, height: Integer): TLuminanceSource; +begin + Result := TPlanarYUVLuminanceSource.Create(yuvData, + dataWidth, + dataHeight, + Self.left + left, + Self.top + top, + width, + height, + false); +end; + +/// +/// Renders the cropped greyscale bitmap. +/// +/// +function TPlanarYUVLuminanceSource.renderThumbnail(): TArray; +var + width, + height : Integer; + pixels : TArray; + yuv : TArray; + x, y, + inputOffset, + outputOffset : Integer; + grey : Byte; +begin + width := Self.Width div THUMBNAIL_SCALE_FACTOR; + height := Self.Height div THUMBNAIL_SCALE_FACTOR; + pixels := TArray.Create(); + SetLength(pixels, (width * height)); + + yuv := yuvData; + inputOffset := (top * dataWidth) + left; + + for y := 0 to Pred(height) do + begin + outputOffset := y * width; + for x := 0 to Pred(width) do + begin + grey := yuv[inputOffset + x * THUMBNAIL_SCALE_FACTOR] and $ff; + pixels[outputOffset + x] := (($00FF0000 shl 8) or (grey * $00010101)); + end; + Inc(inputOffset, (dataWidth * THUMBNAIL_SCALE_FACTOR)); + end; + Result := pixels; +end; + +/// +/// width of image from {@link #renderThumbnail()} +/// +function TPlanarYUVLuminanceSource.ThumbnailWidth(): Integer; +begin + Result := (Self.Width div THUMBNAIL_SCALE_FACTOR); +end; + +/// +/// height of image from {@link #renderThumbnail()} +/// +function TPlanarYUVLuminanceSource.ThumbnailHeight(): Integer; +begin + Result := (Self.Height div THUMBNAIL_SCALE_FACTOR); +end; + +procedure TPlanarYUVLuminanceSource.reverseHorizontal(const width, height: Integer); +var + yuvData : TArray; + y, + x1, x2, + middle, + rowStart : Integer; + temp : Byte; +begin + yuvData := Self.yuvData; + y := 0; + rowStart := ((self.top * self.dataWidth) + self.left); + while ((y < height)) do + begin + middle := (rowStart + (width div 2)); + x1 := rowStart; + x2 := ((rowStart + width) - 1); + while ((x1 < middle)) do + begin + temp := yuvData[x1]; + yuvData[x1] := yuvData[x2]; + yuvData[x2] := temp; + Inc(x1); + Dec(x2) + end; + Inc(y); + Inc(rowStart, self.dataWidth) + end; +end; + +function TPlanarYUVLuminanceSource.CreateLuminanceSource( + const newLuminances: TArray; + const width, height: Integer): TLuminanceSource; +begin + Result := TPlanarYUVLuminanceSource.Create(newLuminances, width, height); +end; + +end. diff --git a/android-client/ThirdParty/ZXing/Filtering/ZXing.RGBLuminanceSource.pas b/android-client/ThirdParty/ZXing/Filtering/ZXing.RGBLuminanceSource.pas new file mode 100644 index 0000000..4c824c1 --- /dev/null +++ b/android-client/ThirdParty/ZXing/Filtering/ZXing.RGBLuminanceSource.pas @@ -0,0 +1,565 @@ +{ + * Copyright 2012 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: dswitkin@google.com (Daniel Switkin) + * Delphi Implementation by E.Spelt and K. Gossens +} + +unit ZXing.RGBLuminanceSource; + +interface +uses + System.SysUtils, + System.UITypes, + System.TypInfo, +{$IFDEF FRAMEWORK_FMX} + FMX.Graphics, +{$ENDIF} +{$IFDEF FRAMEWORK_VCL} + Winapi.Windows, + VCL.Graphics, +{$ENDIF} + ZXing.LuminanceSource, + ZXing.BaseLuminanceSource, + ZXing.Common.Detector.MathUtils; + +type + /// + /// enumeration of supported bitmap format which the RGBLuminanceSource can process + /// + TBitmapFormat = ( + /// + /// format of the byte[] isn't known. RGBLuminanceSource tries to determine the best possible value + /// + Unknown, + /// + /// grayscale array, the byte array is a luminance array with 1 byte per pixel + /// + Gray8, + /// + /// 3 bytes per pixel with the channels red, green and blue + /// + RGB24, + /// + /// 4 bytes per pixel with the channels red, green and blue + /// + RGB32, + /// + /// 4 bytes per pixel with the channels alpha, red, green and blue + /// + ARGB32, + /// + /// 3 bytes per pixel with the channels blue, green and red + /// + BGR24, + /// + /// 4 bytes per pixel with the channels blue, green and red + /// + BGR32, + /// + /// 4 bytes per pixel with the channels blue, green, red and alpha + /// + BGRA32, + /// + /// 2 bytes per pixel, 5 bit red, 6 bits green and 5 bits blue + /// + RGB565, + /// + /// 4 bytes per pixel with the channels red, green, blue and alpha + /// + RGBA32); + + /// + /// Luminance source class which support different formats of images. + /// + TRGBLuminanceSource = class(TBaseLuminanceSource) + private + function DetermineBitmapFormat(const rgbRawBytes: TArray; + const width, height: Integer): TBitmapFormat; + + procedure CalculateLuminanceRGB24(const rgbRawBytes: TArray); + procedure CalculateLuminanceRGB32(const rgbRawBytes: TArray); + procedure CalculateLuminanceRGBA32(const rgbRawBytes: TArray); + procedure CalculateLuminanceRGB565(const rgb565RawData: TArray); + + procedure CalculateLuminanceBGR24(const rgbRawBytes: TArray); + procedure CalculateLuminanceBGR32(const rgbRawBytes: TArray); + procedure CalculateLuminanceBGRA32(const rgbRawBytes: TArray); + + procedure CalculateLuminanceARGB32(const rgbRawBytes: TArray); + + function GetBitmapFormat: TBitmapFormat; + protected + function CreateLuminanceSource(const newLuminances: TArray; + const width, height: Integer): TLuminanceSource; override; + procedure CalculateLuminance(const rgbRawBytes: TArray; + bitmapFormat: TBitmapFormat); + public + constructor Create(const width, height: Integer); overload; + constructor Create(const rgbRawBytes: TArray; + const width, height: Integer); overload; + constructor Create(const rgbRawBytes: TArray; + const width, height: Integer; const bitmapFormat: TBitmapFormat); overload; + constructor CreateFromBitmap(const sourceBitmap: TBitmap; + const width, height: Integer); + + property BitmapFormat : TBitmapFormat read GetBitmapFormat; + end; + +implementation +uses ZXing.Helpers; + +/// +/// Initializes a new instance of the class. +/// +/// The width. +/// The height. +constructor TRGBLuminanceSource.Create(const width, height: Integer); +begin + inherited Create(width, height); +end; + +/// +/// Initializes a new instance of the class. +/// It supports a byte array with 3 bytes per pixel (RGB24). +/// +/// The RGB raw bytes. +/// The width. +/// The height. +constructor TRGBLuminanceSource.Create(const rgbRawBytes: TArray; + const width, height: Integer); +begin + Create(rgbRawBytes, width, height, TBitmapFormat.RGB24); +end; + +/// +/// Initializes a new instance of the class. +/// It supports a byte array with 3 bytes per pixel (RGB24). +/// +/// The RGB raw bytes. +/// The width. +/// The height. +/// The bitmap format. +constructor TRGBLuminanceSource.Create(const rgbRawBytes: TArray; + const width, height: Integer; const bitmapFormat: TBitmapFormat); +begin + inherited Create(width, height); + CalculateLuminance(rgbRawBytes, bitmapFormat); +end; + +{$IFDEF FRAMEWORK_FMX} +// FMX TBitmap implementation +constructor TRGBLuminanceSource.CreateFromBitmap(const sourceBitmap: TBitmap; + const width, height: Integer); +var + x, y, + offset : Integer; + color : TAlphaColor; + r, g, b : Byte; + currentData: TBitmapData; +begin + Self.Create(width, height); + + // In order to measure pure decoding speed, we convert the entire image to a greyscale array + // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. + + if (sourceBitmap.Map(TMapAccess.Read, currentData)) then + begin + try + for y := 0 to FHeight - 1 do + begin + offset := y * FWidth; + for x := 0 to FWidth - 1 do + begin + color := currentData.GetPixel(x, y); + r := TAlphaColorRec(color).R; + g := TAlphaColorRec(color).G; + b := TAlphaColorRec(color).B; + luminances[offset + x] := TMathUtils.Asr(3482*r + 11721*g + 1181*b, 14); + end; + end; + finally + sourceBitmap.Unmap(currentData); + //sourceBitmap.DisposeOf(); + end; + end; +end; +{$ENDIF} +{$IFDEF FRAMEWORK_VCL} +// VCL TBitmap implementation +constructor TRGBLuminanceSource.CreateFromBitmap(const sourceBitmap: TBitmap; const width, height: Integer); +type + TRGBTripleArray = ARRAY[Word] of TRGBTriple; + pRGBTripleArray = ^TRGBTripleArray; // Use a PByteArray for pf8bit color. + +var + x, y, + offset : Integer; + r, g, b : Byte; + P: pRGBTripleArray; + +begin + Self.Create(width, height); + sourceBitmap.PixelFormat := pf24bit; + for y := 0 to sourceBitmap.Height - 1 do + begin + offset := y * FWidth; + P := sourceBitmap.ScanLine[y]; + for x := 0 to sourceBitmap.Width - 1 do + begin + r := P[x].rgbtRed; + g := P[x].rgbtGreen; + b := P[x].rgbtBlue; + luminances[offset + x] := TMathUtils.Asr(3482*r + 11721*g + 1181*b, 14); + end; + end; +end; +{$ENDIF} + +/// +/// Should create a new luminance source with the right class type. +/// The method is used in methods crop and rotate. +/// +/// The new luminances. +/// The width. +/// The height. +/// +function TRGBLuminanceSource.CreateLuminanceSource( + const newLuminances: TArray; + const width, height: Integer): TLuminanceSource; +begin + Result := TRGBLuminanceSource.Create(width, height); + luminances := newLuminances; +end; + +function TRGBLuminanceSource.DetermineBitmapFormat( + const rgbRawBytes: TArray; + const width, height: Integer): TBitmapFormat; +var + square, + byteperpixel : Integer; +begin + square := (width * height); + byteperpixel := (Length(rgbRawBytes) div square); + + case byteperpixel of + 1: Result := TBitmapFormat.Gray8; + 2: Result := TBitmapFormat.RGB565; + 3: Result := TBitmapFormat.RGB24; + 4: Result := TBitmapFormat.RGB32; + else + raise EArgumentException.Create('The bitmap format could not be determined. Please specify the correct value.'); + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminance(const rgbRawBytes: TArray; + bitmapFormat: TBitmapFormat); +var + len: Integer; +begin + if (bitmapFormat = TBitmapFormat.Unknown) + then + bitmapFormat := DetermineBitmapFormat(rgbRawBytes, self.Width, self.Height); + + case bitmapFormat of + TBitmapFormat.Gray8 : + begin + if (Length(rgbRawBytes) < Length(luminances)) + then + len := Length(rgbRawBytes) + else + len := Length(luminances); + + Copy(rgbRawBytes, 0, len); + end; + TBitmapFormat.RGB24 : + begin + CalculateLuminanceRGB24(rgbRawBytes); + end; + TBitmapFormat.RGB32 : + begin + CalculateLuminanceRGB32(rgbRawBytes); + end; + TBitmapFormat.ARGB32 : + begin + CalculateLuminanceARGB32(rgbRawBytes); + end; + TBitmapFormat.BGR24 : + begin + CalculateLuminanceBGR24(rgbRawBytes); + end; + TBitmapFormat.BGR32 : + begin + CalculateLuminanceBGR32(rgbRawBytes); + end; + TBitmapFormat.BGRA32 : + begin + CalculateLuminanceBGRA32(rgbRawBytes); + end; + TBitmapFormat.RGB565 : + begin + CalculateLuminanceRGB565(rgbRawBytes); + end; + TBitmapFormat.RGBA32 : + begin + CalculateLuminanceRGBA32(rgbRawBytes); + end; + else + raise EArgumentException.Create('The bitmap format isn''t supported.' + + GetEnumName(TypeInfo(TBitmapFormat), Ord(bitmapFormat))) + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminanceRGB565( + const rgb565RawData: TArray); +var + luminanceIndex, + index : Integer; + byte1, + byte2, + b5, g5, r5, + r8, g8, b8 : Byte; +begin + luminanceIndex := 0; + index := 0; + while (((index < Length(rgb565RawData)) and + (luminanceIndex < Length(luminances)))) do + begin + byte1 := rgb565RawData[index]; + byte2 := rgb565RawData[index + 1]; + + b5 := (byte1 and $1F); + g5 := (TMathUtils.Asr(byte1 and $E0 , 5) or ((byte2 and $03) shl 3)) and $1F; + r5 := TMathUtils.Asr(byte2, 2) and $1F; + r8 := TMathUtils.Asr(r5 * 527 + 23, 6); + g8 := TMathUtils.Asr(g5 * 527 + 23, 6); + b8 := TMathUtils.Asr(b5 * 527 + 23, 6); + + // cheap, not fully accurate conversion + //pixel := (byte2 shl 8) or byte1; + //b8 := (((pixel) and $001F) shl 3); + //g8 := (((pixel) and $07E0) shr 2) and $FF; + //r8 := (((pixel) and $F800) shr 8); + + luminances[luminanceIndex] := TMathUtils.Asr(RChannelWeight * r8 + GChannelWeight * g8 + + BChannelWeight * b8, ChannelWeight); + Inc(index, 2); + Inc(luminanceIndex); + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminanceRGB24( + const rgbRawBytes: TArray); +var + rgbIndex, + luminanceIndex, + r, g, b : Integer; +begin + rgbIndex := 0; + luminanceIndex := 0; + while (((rgbIndex < Length(rgbRawBytes)) and + (luminanceIndex < Length(luminances)))) do + begin + // Calculate luminance cheaply, favoring green. + r := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + g := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + b := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + luminances[luminanceIndex] := TMathUtils.Asr(RChannelWeight * r + GChannelWeight * g + + BChannelWeight * b,ChannelWeight); + inc(luminanceIndex) + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminanceBGR24( + const rgbRawBytes: TArray); +var + rgbIndex, + luminanceIndex, + b, g, r : Byte; +begin + rgbIndex := 0; + luminanceIndex := 0; + while (((rgbIndex < Length(rgbRawBytes)) and + (luminanceIndex < Length(luminances)))) do + begin + // Calculate luminance cheaply, favoring green. + b := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + g := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + r := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + luminances[luminanceIndex] := TMathUtils.Asr(RChannelWeight * r + GChannelWeight * g + + BChannelWeight * b,ChannelWeight); + Inc(luminanceIndex) + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminanceRGB32( + const rgbRawBytes: TArray); +var + rgbIndex, + luminanceIndex, + r, g, b : Byte; +begin + rgbIndex := 0; + luminanceIndex := 0; + while (((rgbIndex < Length(rgbRawBytes)) and + (luminanceIndex < Length(luminances)))) do + begin + // Calculate luminance cheaply, favoring green. + r := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + g := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + b := rgbRawBytes[rgbIndex]; + Inc(rgbIndex, 2); + luminances[luminanceIndex] := TMathUtils.Asr(RChannelWeight * r + GChannelWeight * g + + BChannelWeight * b, ChannelWeight); + Inc(luminanceIndex); + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminanceBGR32( + const rgbRawBytes: TArray); +var + rgbIndex, + luminanceIndex, + b, g, r : Byte; +begin + rgbIndex := 0; + luminanceIndex := 0; + while (((rgbIndex < Length(rgbRawBytes)) and + (luminanceIndex < Length(luminances)))) do + begin + // Calculate luminance cheaply, favoring green. + b := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + g := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + r := rgbRawBytes[rgbIndex]; + Inc(rgbIndex, 2); + luminances[luminanceIndex] := TMathUtils.Asr(RChannelWeight * r + GChannelWeight * g + + BChannelWeight * b, ChannelWeight); + Inc(luminanceIndex); + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminanceBGRA32( + const rgbRawBytes: TArray); +var + rgbIndex, + luminanceIndex, + b, g, r, + alpha : Byte; + luminance : Byte; +begin + rgbIndex := 0; + luminanceIndex := 0; + while (((rgbIndex < Length(rgbRawBytes)) and + (luminanceIndex < Length(luminances)))) do + begin + // Calculate luminance cheaply, favoring green. + b := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + g := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + r := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + alpha := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + + luminance := TMathUtils.Asr(RChannelWeight * r + GChannelWeight * g + + BChannelWeight * b, ChannelWeight); + luminances[luminanceIndex] := (TMathUtils.Asr(luminance * alpha, 8) + TMathUtils.Asr(255 * (255 - alpha), 8)); + Inc(luminanceIndex); + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminanceRGBA32( + const rgbRawBytes: TArray); +var + rgbIndex, + luminanceIndex, + r, g, b, + alpha : Byte; + luminance : Byte; +begin + rgbIndex := 0; + luminanceIndex := 0; + while (((rgbIndex < Length(rgbRawBytes)) and + (luminanceIndex < Length(luminances)))) do + begin + // Calculate luminance cheaply, favoring green. + r := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + g := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + b := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + alpha := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + + luminance := TMathUtils.Asr(RChannelWeight * r + GChannelWeight * g + + BChannelWeight * b, ChannelWeight); + luminances[luminanceIndex] := TMathUtils.Asr(luminance * alpha, 8) + TMathUtils.Asr(255 * (255 - alpha), 8); + Inc(luminanceIndex); + end; +end; + +procedure TRGBLuminanceSource.CalculateLuminanceARGB32( + const rgbRawBytes: TArray); +var + rgbIndex, + luminanceIndex, + r, g, b, + alpha : Byte; + luminance : Byte; +begin + rgbIndex := 0; + luminanceIndex := 0; + while (((rgbIndex < Length(rgbRawBytes)) and + (luminanceIndex < Length(luminances)))) do + begin + // Calculate luminance cheaply, favoring green. + alpha := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + r := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + g := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + b := rgbRawBytes[rgbIndex]; + Inc(rgbIndex); + + luminance := TMathUtils.Asr(RChannelWeight * r + GChannelWeight * g + + BChannelWeight * b, ChannelWeight); + luminances[luminanceIndex] := TMathUtils.Asr(luminance * alpha,8) + TMathUtils.Asr(255 * (255 - alpha),8); + Inc(luminanceIndex); + end; +end; + +function TRGBLuminanceSource.GetBitmapFormat: TBitmapFormat; +begin + try + Result := DetermineBitmapFormat(luminances, Width, Height); + except + Result := TBitmapFormat.Unknown; + end; +end; + +end. diff --git a/android-client/ThirdParty/ZXing/LICENSE b/android-client/ThirdParty/ZXing/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/android-client/ThirdParty/ZXing/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + diff --git a/android-client/ThirdParty/ZXing/ZXing.ScanManager.pas b/android-client/ThirdParty/ZXing/ZXing.ScanManager.pas new file mode 100644 index 0000000..d77e79e --- /dev/null +++ b/android-client/ThirdParty/ZXing/ZXing.ScanManager.pas @@ -0,0 +1,185 @@ +unit ZXing.ScanManager; + +interface + +uses + System.SysUtils, + System.Generics.Collections, +{$IFDEF FRAMEWORK_FMX} + FMX.Graphics, +{$ENDIF} +{$IFDEF FRAMEWORK_VCL} + VCL.Graphics, +{$ENDIF} + ZXing.LuminanceSource, + ZXing.RGBLuminanceSource, + ZXing.InvertedLuminanceSource, + ZXing.HybridBinarizer, + ZXing.BinaryBitmap, + ZXing.MultiFormatReader, + ZXing.BarcodeFormat, + ZXing.ResultPoint, + ZXing.ReadResult, + ZXing.DecodeHintType; + +type + TScanManager = class + private + FEnableInversion: Boolean; + FHints: TDictionary; + FResultPointEvent: TResultPointCallback; + FMultiFormatReader: TMultiFormatReader; + listFormats: TList; + + function GetMultiFormatReader(const format: TBarcodeFormat) + : TMultiFormatReader; + + procedure SetResultPointEvent(const AValue: TResultPointCallback); + public + destructor Destroy; override; + + function Scan(const pBitmapForScan: TBitmap): TReadResult; + constructor Create(const format: TBarcodeFormat; + Hints: TDictionary); + + property OnResultPoint: TResultPointCallback read FResultPointEvent + write SetResultPointEvent; + end; + +implementation + +constructor TScanManager.Create(const format: TBarcodeFormat; + Hints: TDictionary); +begin + inherited Create; + FEnableInversion := False; + FHints := Hints; + FMultiFormatReader := GetMultiFormatReader(format); +end; + +destructor TScanManager.Destroy; +var + hint: TPair; + o: TObject; +begin + if Assigned(FHints) then + begin + + for hint in FHints do + begin + o := hint.Value; + if Assigned(o) then + o.Free; + end; + + FHints.Clear(); + FreeAndNil(FHints); + end; + + FreeAndNil(FMultiFormatReader); + inherited; +end; + +procedure TScanManager.SetResultPointEvent(const AValue: TResultPointCallback); +var + ahKey: TDecodeHintType; + ahValue: TObject; +begin + FResultPointEvent := AValue; + + ahKey := TDecodeHintType.NEED_RESULT_POINT_CALLBACK; + if Assigned(FResultPointEvent) then + begin + ahValue := TResultPointEventObject.Create(FResultPointEvent); + FHints.AddOrSetValue(ahKey, ahValue); + end + else + begin + if Fhints.TryGetValue(ahKey, ahValue) then + begin + ahValue.Free; + ahValue := nil; + FHints.Remove(ahKey); + end; + end; +end; + +function TScanManager.GetMultiFormatReader(const format: TBarcodeFormat) + : TMultiFormatReader; +var + o: TObject; + +begin + Result := TMultiFormatReader.Create; + listFormats := nil; + + if FHints = nil then + FHints := TDictionary.Create(); + + if FHints.ContainsKey(ZXing.DecodeHintType.ENABLE_INVERSION) then + FEnableInversion := true; + + if format <> TBarcodeFormat.Auto then + begin + if (FHints.TryGetValue(ZXing.DecodeHintType.POSSIBLE_FORMATS, o)) then + listFormats := o as TList + else + begin + listFormats := TList.Create(); + FHints.Add(ZXing.DecodeHintType.POSSIBLE_FORMATS, listFormats); + end; + + if (listFormats.Count = 0) then + listFormats.Add(format) + else + listFormats.Insert(0, format); // favor the format parameter + + end; + + Result.Hints := FHints; +end; + +function TScanManager.Scan(const pBitmapForScan: TBitmap): TReadResult; +var + LuminanceSource, InvLuminanceSource: TLuminanceSource; + HybridBinarizer: THybridBinarizer; + BinaryBitmap: TBinaryBitmap; +begin + InvLuminanceSource := nil; + LuminanceSource := nil; + HybridBinarizer := nil; + BinaryBitmap := nil; + try + + LuminanceSource := TRGBLuminanceSource.CreateFromBitmap(pBitmapForScan, + pBitmapForScan.Width, pBitmapForScan.Height); + HybridBinarizer := THybridBinarizer.Create(LuminanceSource); + BinaryBitmap := TBinaryBitmap.Create(HybridBinarizer); + Result := FMultiFormatReader.Decode(BinaryBitmap, true); + + if (Result = nil) then + begin + if (FEnableInversion) then + begin + if (BinaryBitmap <> nil) then + FreeAndNil(BinaryBitmap); + + if (HybridBinarizer <> nil) then + FreeAndNil(HybridBinarizer); + + InvLuminanceSource := LuminanceSource.invert(); + HybridBinarizer := THybridBinarizer.Create(InvLuminanceSource); + BinaryBitmap := TBinaryBitmap.Create(HybridBinarizer); + Result := FMultiFormatReader.Decode(BinaryBitmap, true); + + end; + end; + finally + BinaryBitmap.Free; + HybridBinarizer.Free; + InvLuminanceSource.Free; + LuminanceSource.Free; + end; +end; + +end. diff --git a/android-client/web/app.html b/android-client/web/app.html index 861cbbb..4ae762f 100644 --- a/android-client/web/app.html +++ b/android-client/web/app.html @@ -588,7 +588,7 @@ type="password" autocomplete="off">
×
- +
The sync password never leaves this device. It is what encrypts the copy kept in the repository, so it must be the same on every @@ -1666,8 +1666,8 @@ function normalizeRepoUrl(u) { if (!m) return u; return m[1] + '/api/v1/repos/' + m[2] + '/' + m[3] + '/contents/' + (m[4] || 'vault-sync.json'); } -document.getElementById('sPaste').addEventListener('click', function () { - send('pastecfg'); +document.getElementById('sScan').addEventListener('click', function () { + send('scanqr'); }); document.getElementById('sSave').addEventListener('click', function () { var sUrl = document.getElementById('sUrl'); diff --git a/mainApk.pas b/mainApk.pas index 5ae7704..58ac9c2 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -36,7 +36,7 @@ uses FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Platform, FMX.Controls.Presentation, FMX.StdCtrls, FMX.Memo, FMX.Memo.Types, FMX.ScrollBox, FMX.Layouts, FMX.Edit, FMX.ListBox, FMX.Objects, - FMX.WebBrowser, System.Messaging, + FMX.WebBrowser, System.Messaging, FMX.Media, PMA.Vault; const @@ -341,7 +341,18 @@ type /// que le proprietaire ne connaitrait pas. procedure SetUnlockCode(const ANew: string); procedure PushUnlockMode; - procedure PasteSyncSettings; + // Scanner du QR affiche par le poste (ZXing.Delphi, Apache 2.0). + var + FScanning, FScanBusy: Boolean; + FScanFrame: Integer; + FScanLay: TLayout; + FScanImg: TImage; + FCam: TCameraComponent; + procedure StartScan; + procedure BeginScan; + procedure StopScan; + procedure DoCancelScan(Sender: TObject); + procedure OnCamFrame(Sender: TObject; const ATime: TMediaTime); function ApplySyncLink(const ALink: string): Boolean; {$IFDEF ANDROID} procedure OnActivityMessage(const Sender: TObject; const M: TMessage); @@ -385,10 +396,11 @@ implementation uses PMA.Crypto, PMA.SyncClient, PMA.Store, PMA.Biometric, PMA.Totp, PMA.ScreenGuard, PMA.Clipboard, PMA.Theme, PMA.WebUI, PMA.VaultPatch, - PMA.SaveFile, PMA.Favicon, System.JSON + PMA.SaveFile, PMA.Favicon, System.JSON, System.Permissions, + ZXing.ScanManager, ZXing.BarcodeFormat, ZXing.ReadResult {$IFDEF ANDROID} , Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.JavaTypes, - Androidapi.Helpers, FMX.Platform.Android + Androidapi.Helpers, FMX.Platform.Android, Androidapi.JNI.Os {$ENDIF}; {$R *.fmx} @@ -602,6 +614,12 @@ procedure TForm8.OnHardwareBack(Sender: TObject; var Key: Word; var KeyChar: WideChar; Shift: TShiftState); begin if Key <> vkHardwareBack then Exit; + if FScanning then + begin + StopScan; + Key := 0; + Exit; + end; if not FLayWeb.Visible then Exit; // LE CLAVIER D'ABORD. Quand il est deplie, cette touche est le bouton qui le // replie - c'est tout ce qu'elle veut dire. La vue web n'etant pas un champ @@ -1834,12 +1852,10 @@ begin SetUnlockCode(TNetEncoding.URL.Decode(Param('c'))); end - // REGLAGES COLLES DEPUIS LE QR DU POSTE. L'appareil photo a lu le QR et - // copie son texte : {"pmsync":1,"u":URL,"t":JETON}. On remplit les champs - // des reglages SANS enregistrer - Save reste le geste qui valide - et on - // vide le presse-papiers, qui porte le jeton. - else if LAction = 'pastecfg' then - PasteSyncSettings + // SCANNER LE QR DU POSTE depuis l'app : le scanner du systeme envoyait + // le lien a une recherche web ou demandait avec quoi l'ouvrir. + else if LAction = 'scanqr' then + StartScan else if LAction = 'pinclear' then ClearUnlockCode(TNetEncoding.URL.Decode(Param('c'))) @@ -2890,8 +2906,9 @@ begin // recentes : masquer ici, c'est ne pas y laisser la liste des comptes. // Le masquage est IMMEDIAT et sans condition - c'est lui qui protege. TApplicationEvent.WillBecomeInactive: - if FWebView <> 'unlock' then + if FScanning or (FWebView <> 'unlock') then begin + StopScan; // la camera ne reste pas ouverte en arriere-plan FWeb.Visible := False; FLayWeb.Visible := False; end; @@ -3225,12 +3242,154 @@ begin if HasLocalContainer then Result := 'vault password' else Result := 'sync password'; end; -procedure TForm8.PasteSyncSettings; +procedure TForm8.StartScan; begin - if ApplySyncLink(CurrentClipboard.Trim) then - ClearClipboard - else - WebCall('PM.toast("No settings in the clipboard - copy the link of the QR shown on the PC first")'); + if FScanning or FBusy then Exit; + {$IFDEF ANDROID} + PermissionsService.RequestPermissions( + [JStringToString(TJManifest_permission.JavaClass.CAMERA)], + procedure(const APermissions: TClassicStringDynArray; + const AGrantResults: TClassicPermissionStatusDynArray) + begin + if (Length(AGrantResults) = 1) and + (AGrantResults[0] = TPermissionStatus.Granted) then + BeginScan + else + WebCall('PM.toast("Camera not allowed - type the settings instead")'); + end); + {$ELSE} + BeginScan; + {$ENDIF} +end; + +/// L'apercu est FMX, pas web : la vue web est une vue native posee PAR-DESSUS +/// les controles FMX, il faut donc la masquer pendant le scan. +procedure TForm8.BeginScan; +var + LBg: TRectangle; + LBtn: TButton; + LLbl: TLabel; +begin + if FScanLay = nil then + begin + FScanLay := TLayout.Create(Self); + FScanLay.Parent := Self; + FScanLay.Align := TAlignLayout.Contents; + LBg := TRectangle.Create(FScanLay); + LBg.Parent := FScanLay; + LBg.Align := TAlignLayout.Contents; + LBg.Fill.Color := TAlphaColors.Black; + LBg.Stroke.Kind := TBrushKind.None; + LBg.HitTest := False; + LLbl := TLabel.Create(FScanLay); + LLbl.Parent := FScanLay; + LLbl.Align := TAlignLayout.Top; + LLbl.Height := 72; + LLbl.Margins.Top := 24; + LLbl.StyledSettings := []; + LLbl.TextSettings.FontColor := TAlphaColors.White; + LLbl.TextSettings.Font.Size := 16; + LLbl.TextSettings.HorzAlign := TTextAlign.Center; + LLbl.Text := 'Point the camera at the QR shown on the PC'; + LBtn := TButton.Create(FScanLay); + LBtn.Parent := FScanLay; + LBtn.Align := TAlignLayout.Bottom; + LBtn.Height := 56; + LBtn.Margins.Rect := TRectF.Create(24, 8, 24, 32); + LBtn.Text := 'Cancel'; + LBtn.OnClick := DoCancelScan; + FScanImg := TImage.Create(FScanLay); + FScanImg.Parent := FScanLay; + FScanImg.Align := TAlignLayout.Client; + FScanImg.WrapMode := TImageWrapMode.Fit; + FScanImg.HitTest := False; + FCam := TCameraComponent.Create(Self); + FCam.OnSampleBufferReady := OnCamFrame; + end; + HideSoftKeyboard; + FScanning := True; + FScanBusy := False; + FScanFrame := 0; + FLayWeb.Visible := False; + FScanLay.Visible := True; + FScanLay.BringToFront; + FCam.Active := False; + FCam.Kind := TCameraKind.BackCamera; + FCam.Quality := TVideoCaptureQuality.MediumQuality; + try + FCam.FocusMode := TFocusMode.ContinuousAutoFocus; + except + // Pas d'autofocus continu : l'image restera nette a bonne distance. + end; + FCam.Active := True; + Log('QR scan started'); +end; + +procedure TForm8.StopScan; +begin + if not FScanning then Exit; + FScanning := False; + if FCam <> nil then FCam.Active := False; + if FScanLay <> nil then FScanLay.Visible := False; + FLayWeb.Visible := True; +end; + +procedure TForm8.DoCancelScan(Sender: TObject); +begin + StopScan; +end; + +/// Une image sur quatre part au decodage, jamais deux a la fois : ZXing prend +/// quelques dizaines de ms, et empiler les images figerait l'apercu. +procedure TForm8.OnCamFrame(Sender: TObject; const ATime: TMediaTime); +begin + TThread.Synchronize(nil, + procedure + var + LBmp: TBitmap; + begin + if not FScanning then Exit; + FCam.SampleBufferToBitmap(FScanImg.Bitmap, True); + Inc(FScanFrame); + if FScanBusy or (FScanFrame mod 4 <> 0) then Exit; + FScanBusy := True; + LBmp := TBitmap.Create; + LBmp.Assign(FScanImg.Bitmap); + TThread.CreateAnonymousThread( + procedure + var + LMgr: TScanManager; + LRes: TReadResult; + LText: string; + begin + LText := ''; + LRes := nil; + LMgr := TScanManager.Create(TBarcodeFormat.QR_CODE, nil); + try + try + LRes := LMgr.Scan(LBmp); + if LRes <> nil then LText := LRes.Text; + except + LText := ''; + end; + finally + LRes.Free; + LMgr.Free; + LBmp.Free; + end; + TThread.Queue(nil, + procedure + begin + FScanBusy := False; + if (not FScanning) or (LText = '') then Exit; + if StartsText('pmserver://sync?', LText) then + begin + StopScan; + ApplySyncLink(LText); + end; + end); + end).Start; + end); end; /// pmserver://sync?u=URL&t=JETON -> champs des reglages remplis, RIEN diff --git a/pmserverApk.dproj b/pmserverApk.dproj index 47a1f89..2e48883 100644 --- a/pmserverApk.dproj +++ b/pmserverApk.dproj @@ -90,6 +90,7 @@ .\$(Platform)\$(Config) .\$(Platform)\$(Config) + android-client\ThirdParty\ZXing;android-client\ThirdParty\ZXing\1D Barcodes;android-client\ThirdParty\ZXing\2D Barcodes;android-client\ThirdParty\ZXing\2D Barcodes\Decoder;android-client\ThirdParty\ZXing\2D Barcodes\Detector;android-client\ThirdParty\ZXing\Common;android-client\ThirdParty\ZXing\Common\Detector;android-client\ThirdParty\ZXing\Common\ReedSolomon;android-client\ThirdParty\ZXing\Filtering;$(DCC_UnitSearchPath) false false false