{ * 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.