#1 2010-06-09 15:25

Simonz
Member
Registered: 2010-06-09
Posts: 2

EAN-13 barcode checksum calculation

Hi, i've this problem

I've a series of files like:

002010000000.png
002010000001.png
002010000002.png
002010000003.png


Each of them is a barcode image, but the name lacks of the last char, the check digit number

Examples:

002010000000.png is the barcode 0020100000007
002010000001.png is the barcode 0020100000014
002010000002.png is the barcode 0020100000021

The problem is to add to filename the check digit number like:

002010000000.png > 0020100000007.png
002010000001.png > 0020100000014.png
002010000002.png > 0020100000021.png

The check digit number is a result of an algorithm, the Mod10

This algorithm is applied for the check digit number in barcode standard EAN-13, see the wiki:

EAN-13

The number is read from right to left. Since the last digit is the checksum, the second digit from the right is the first digit when we make the calculation.

EAN-13 mod 10

1.Remove the last digit from the number.
2.Reverse the rest of the number.
3.Multiply the digits in odd positions with 3 and add the results together.
4.Add the digits in even position together.
5.Calculation = (odd sum + even sum) MOD 10.
6.If calculation is 0 then 0 is the checksum.
7.Else checksum = 10 - calculation.

EAN-13 checksum example

1.EAN-13 number = 5701291191822
2.Checksum = 2
3.Number without checksum reversed = 281911921075
4.Odd positions = 2*3 + 1*3 + 1*3 + 9*3 + 1*3 + 7*3 = 6 + 3 + 3 + 27 + 3 + 21 = 63
5.Even positions = 8 + 9 + 1 + 2 + 0 + 5 = 25
6.Calculation = (63 + 25) MOD 10 = 88 MOD 10 = 8
7.Recalculated checksum =
if (calculation != 0) then (10 - calculation) else 0
In our example: 10 - 8 = 2
8.UPC is valid if recalculated checksum (2) = checksum (2)

I've found a script:

function Mod10(const Value: string): Integer;
var
  i, intOdd, intEven: Integer;
begin
  {add all odd seq numbers}
  intOdd := 0;
  i := 1;
  while (i < Length(Value)) do
  begin
    Inc(intOdd, StrToIntDef(Value[i], 0));
    Inc(i, 2);
  end;

  {add all even seq numbers}
  intEven := 0;
  i := 2;
  while (i < Length(Value)) do
  begin
    Inc(intEven, StrToIntDef(Value[i], 0));
    Inc(i, 2);
  end;

  Result := 3*intOdd + intEven;
  {modulus by 10 to get}
  Result := Result mod 10;
  if Result <> 0 then
    Result := 10 - Result
end;

But it doesn't work (error in Inc function)

Can anyone post me a valid script to add the check digit number at the end of filename? THANKS!!!!!!!

Offline

#2 2010-06-09 18:36

den4b
Administrator
From: den4b.com
Registered: 2006-04-06
Posts: 3,068

Re: EAN-13 barcode checksum calculation

I've made it into a script available from wiki: wiki/ReNamer:Scripts:EAN-13.

The script will calculate the checksum digit for the EAN-13 barcode and append it to the base name of the file. Please double check the resulting checksum.

var
  I, Digit: Integer;
  Odd: Boolean;
  Sum: Integer;
begin
  Sum := 0;
  Odd := True;
  for I := Length(EAN13) downto 1 do
  begin
    Digit := StrToIntDef(EAN13[i], 0);
    if Odd then
      Sum := Sum + Digit * 3
    else
      Sum := Sum + Digit;
   Odd := not Odd;
  end;
  Result := Sum mod 10;
  if Result <> 0 then
    Result := 10 - Result;
end;
 
var
  BaseName, Ext: WideString;
  Checksum: Integer;
 
begin
  BaseName := WideExtractBaseName(FileName);
  Ext := WideExtractFileExt(FileName);
  Checksum := EAN13Checksum(BaseName);
  FileName := BaseName + IntToStr(Checksum) + Ext;
end.

------------

Simonz wrote:

But it doesn't work (error in Inc function)

The Inc error can be fixed by replacing "Inc(i, 2);" with "I := I + 2;". Your code is also flawed at "while" loops.

Last edited by den4b (2010-06-09 23:14)

Offline

#3 2010-06-09 19:46

Andrew
Senior Member
Registered: 2008-05-22
Posts: 542

Re: EAN-13 barcode checksum calculation

Here's your original code modified to work properly:

Deleted code (see below).

Some things I myself would like to be clarified:

1) Doesn't PascalScript have an in-built string reversal function like StrRev() and WideStrRev()?

2) For string reversal, normally the following should work:

for i := 1 to Length(Str) do
  Str[i] := Str[Length(Str)-(i-1)];

But modifying the same string like this doesn't seem to work properly, which is why in the code above I had to use another string variable. Does anyone know what's wrong with modifying the string itself to reverse it?

Last edited by Andrew (2010-06-10 13:58)

Offline

#4 2010-06-09 23:35

den4b
Administrator
From: den4b.com
Registered: 2006-04-06
Posts: 3,068

Re: EAN-13 barcode checksum calculation

Andrew, the code is flawed and works only accidentally!

Both while loops are always missing the last digit: "while (i < Length(Value)) do" should be "while (i <= Length(Value)) do" (notice the equal sign). Accidentally the first digit in the examples is 0, i.e.: 002010000000 produces produces a valid check digit 7, but so as 102010000000, 202010000000, 302010000000, etc - for which correct check digit would be different.

Have you looked at the code that I posted on Wiki?

Andrew wrote:

1) Doesn't PascalScript have an in-built string reversal function like StrRev() and WideStrRev()?

PascalScript only has bare bones for executing scripts. I define/code all the functions. No, there is no string reversal function. For the exercise above you can simple use reverse loop "for..downto..do" or a while loop counting down.

Andrew wrote:

2) String reversal doesn't seem to work properly.

for i := 1 to Length(Str) do
  Str[i] := Str[Length(Str)-(i-1)];

It doesn't work because the first half of the loop erases the characters which are to be used in the second half of the loop. It will produce a mirrored half of the original string.

A correct version of the string reverse function would be:

function WideReverseStr(const S: WideString): WideString;
var
  I, Count: Integer;
begin
  Count := Length(S);
  SetLength(Result, Count);
  for I := 1 to Count do
    Result[i] := S[Count - I + 1];
end;

Offline

#5 2010-06-10 07:09

Simonz
Member
Registered: 2010-06-09
Posts: 2

Re: EAN-13 barcode checksum calculation

WOW! Fast as a Ferrari wink Thanks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Offline

#6 2010-06-10 14:32

Andrew
Senior Member
Registered: 2008-05-22
Posts: 542

Re: EAN-13 barcode checksum calculation

den4b wrote:

Both while loops are always missing the last digit: "while (i < Length(Value)) do" should be "while (i <= Length(Value)) do" (notice the equal sign).

Serves me right for mixing up Pascal(Script) with other languages and not testing thoroughly! Have to properly remember which language I'm working with currently and whether strings/arrays are 0-based or not. roll

den4b wrote:

It doesn't work because the first half of the loop erases the characters which are to be used in the second half of the loop. It will produce a mirrored half of the original string.

Ah yes, so it does. Thanks for clarifying that Denis. Don't know what I was thinking. roll

Also, won't fixing the while loops so as not to skip the last digit fix the code I posted? The code below seems to give the same result as yours in any case:

function Mod10(const Name: WideString): Integer;
var
  Value: WideString;
  i, intOdd, intEven: Integer;
begin
  {reverse the string}
  SetLength(Value, Length(Name));
  for i := 1 to Length(Name) do
    Value[i] := Name[Length(Name)-(i-1)];

  {add all odd position digits}
  intOdd := 0;
  i := 1;
  while (i <= Length(Value)) do
  begin
    intOdd := intOdd + StrToIntDef(Value[i], 0);
    i := i + 2;
  end;

  {add all even position digits}
  intEven := 0;
  i := 2;
  while (i <= Length(Value)) do
  begin
    intEven := intEven + StrToIntDef(Value[i], 0);
    i := i + 2;
  end;

  Result := 3*intOdd + intEven;
  Result := Result mod 10;
  if Result <> 0 then
    Result := 10 - Result
end;

begin
  FileName := WideExtractBaseName(FileName) +
    IntToStr(Mod10(WideExtractBaseName(FileName))) +
    WideExtractFileExt(FileName);
end.

Yup, I had a look at your code which was quite compact and worked beautifully. Was just trying to fix the code the OP posted (with as few changes as possible instead of re-writing it completely), and seems I really got muddled up in the process! tongue

Last edited by Andrew (2010-06-10 17:12)

Offline

Board footer

Powered by FluxBB