-
Notifications
You must be signed in to change notification settings - Fork 209
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed EAN13 bugs, added EAN8, unit tests and extended test projects
- Loading branch information
Showing
30 changed files
with
1,455 additions
and
791 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ | |
* Original Authors: [email protected] (Daniel Switkin), Sean Owen and | ||
* [email protected] (Alasdair Mackintosh) | ||
* Delphi Implementation by K. Gossens | ||
* Delphi Implementation by K. Gossens, E. Spelt | ||
} | ||
|
||
unit ZXing.OneD.EAN13Reader; | ||
|
@@ -46,32 +46,32 @@ TEAN13Reader = class(TUPCEANReader) | |
// 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 | ||
// 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 | ||
// Odd Even Even Odd Odd Even | ||
// in binary: | ||
// 0 1 1 0 0 1 == 0x19 | ||
// 0 1 1 0 0 1 == 0x19 | ||
// | ||
class var | ||
FIRST_DIGIT_ENCODINGS : TArray<Integer>; | ||
decodeMiddleCounters : TArray<Integer>; | ||
class var | ||
FIRST_DIGIT_ENCODINGS: TArray<Integer>; | ||
decodeMiddleCounters: TArray<Integer>; | ||
|
||
/// <summary> | ||
/// Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded | ||
|
@@ -80,7 +80,7 @@ TEAN13Reader = class(TUPCEANReader) | |
/// </summary> | ||
/// <param name="resultString">string to insert decoded first digit into</param> | ||
/// <param name="lgPatternFound">int whose bits indicates the pattern of odd/even L/G patterns used to</param> | ||
/// encode digits | ||
/// encode digits | ||
/// <return>-1 if first digit cannot be determined</return> | ||
class function determineFirstDigit(const resultString: TStringBuilder; | ||
const lgPatternFound: Integer): Boolean; static; | ||
|
@@ -99,8 +99,8 @@ TEAN13Reader = class(TUPCEANReader) | |
/// horizontal offset of first pixel after the "middle" that was decoded or -1 if decoding could not complete successfully | ||
/// </returns> | ||
class function decodeMiddle(const row: IBitArray; | ||
const startRange: TArray<Integer>; | ||
const resultString: TStringBuilder): Integer; override; | ||
const startRange: TArray<Integer>; const resultString: TStringBuilder) | ||
: Integer; override; | ||
public | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TEAN13Reader"/> class. | ||
|
@@ -122,10 +122,12 @@ implementation | |
constructor TEAN13Reader.Create(); | ||
begin | ||
inherited; | ||
SetLength(decodeMiddleCounters, 4); | ||
end; | ||
|
||
destructor TEAN13Reader.Destroy; | ||
begin | ||
decodeMiddleCounters := nil; | ||
inherited; | ||
end; | ||
|
||
|
@@ -136,13 +138,10 @@ class function TEAN13Reader.decodeMiddle(const row: IBitArray; | |
bestMatch: Integer; | ||
counter: Integer; | ||
ending: Integer; | ||
counters, | ||
middleRange : TArray<Integer>; | ||
rowOffset, x, | ||
lgPatternFound: Integer; | ||
counters, middleRange: TArray<Integer>; | ||
rowOffset, x, lgPatternFound: Integer; | ||
begin | ||
Result := -1; | ||
|
||
counters := decodeMiddleCounters; | ||
counters[0] := 0; | ||
counters[1] := 0; | ||
|
@@ -157,33 +156,29 @@ class function TEAN13Reader.decodeMiddle(const row: IBitArray; | |
begin | ||
if (not decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS, bestMatch)) | ||
then | ||
exit; | ||
resultString.Append('0' + IntToStr(bestMatch mod 10)); | ||
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)); | ||
if (bestMatch >= 10) then | ||
lgPatternFound := lgPatternFound or (1 shl (5 - x)); | ||
Inc(x); | ||
end; | ||
|
||
if (not determineFirstDigit(resultString, lgPatternFound)) | ||
then | ||
exit; | ||
if (not determineFirstDigit(resultString, lgPatternFound)) then | ||
exit; | ||
|
||
middleRange := findGuardPattern(row, rowOffset, true, MIDDLE_PATTERN); | ||
if (middleRange = nil) | ||
then | ||
exit; | ||
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('0' + IntToStr(bestMatch)); | ||
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); | ||
|
@@ -197,8 +192,8 @@ function TEAN13Reader.BarcodeFormat: TBarcodeFormat; | |
Result := TBarcodeFormat.EAN_13; | ||
end; | ||
|
||
class function TEAN13Reader.determineFirstDigit( | ||
const resultString: TStringBuilder; const lgPatternFound: Integer): Boolean; | ||
class function TEAN13Reader.determineFirstDigit(const resultString | ||
: TStringBuilder; const lgPatternFound: Integer): Boolean; | ||
var | ||
d: Integer; | ||
begin | ||
|
@@ -207,7 +202,7 @@ class function TEAN13Reader.determineFirstDigit( | |
begin | ||
if (lgPatternFound = FIRST_DIGIT_ENCODINGS[d]) then | ||
begin | ||
resultString.Insert(0, '0' + IntToStr(d)); | ||
resultString.Insert(0, IntToStr(d)); | ||
Result := true; | ||
break; | ||
end; | ||
|
@@ -216,19 +211,21 @@ class function TEAN13Reader.determineFirstDigit( | |
|
||
class procedure TEAN13Reader.InitializeClass; | ||
begin | ||
FIRST_DIGIT_ENCODINGS := TArray<Integer>.Create($00, $0B, $0D, $0E, $13, | ||
$19, $1C, $15, $16, $1A); | ||
decodeMiddleCounters := TArray<Integer>.Create(0, 0, 0, 0); | ||
FIRST_DIGIT_ENCODINGS := TArray<Integer>.Create($00, $0B, $0D, $0E, $13, $19, | ||
$1C, $15, $16, $1A); | ||
end; | ||
|
||
class procedure TEAN13Reader.FinalizeClass; | ||
begin | ||
decodeMiddleCounters := nil; | ||
FIRST_DIGIT_ENCODINGS := nil; | ||
end; | ||
|
||
initialization | ||
TEAN13Reader.InitializeClass; | ||
|
||
TEAN13Reader.InitializeClass; | ||
|
||
finalization | ||
TEAN13Reader.FinalizeClass; | ||
|
||
TEAN13Reader.FinalizeClass; | ||
|
||
end. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
{ | ||
* 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: [email protected] (Daniel Switkin), Sean Owen and | ||
* [email protected] (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 | ||
/// <summary> | ||
/// <p>Implements decoding of the EAN-8 format.</p> | ||
/// </summary> | ||
TEAN8Reader = class(TUPCEANReader) | ||
|
||
private | ||
class var decodeMiddleCounters: TArray<Integer>; | ||
protected | ||
class function decodeMiddle(const row: IBitArray; | ||
const startRange: TArray<Integer>; const resultString: TStringBuilder) | ||
: Integer; override; | ||
public | ||
function BarcodeFormat: TBarcodeFormat; override; | ||
constructor Create; override; | ||
destructor Destroy; override; | ||
end; | ||
|
||
implementation | ||
|
||
function TEAN8Reader.BarcodeFormat: TBarcodeFormat; | ||
begin | ||
result:=TBarcodeFormat.EAN_8; | ||
end; | ||
|
||
constructor TEAN8Reader.Create; | ||
begin | ||
inherited; | ||
SetLength(decodeMiddleCounters, 4); | ||
end; | ||
|
||
destructor TEAN8Reader.Destroy; | ||
begin | ||
decodeMiddleCounters := nil; | ||
inherited; | ||
end; | ||
|
||
class function TEAN8Reader.DecodeMiddle(const row: IBitArray; | ||
const startRange: TArray<Integer>; | ||
const resultString: TStringBuilder): Integer; | ||
var | ||
ending, rowOffset, x, bestMatch: Integer; | ||
counter: Integer; | ||
counters, middleRange: TArray<Integer>; | ||
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; | ||
|
||
|
||
|
||
end. |
Oops, something went wrong.