log the brokenness of TOC items without urls
[objavi2.git] / bookland / scan13
blob09e3f72f9ce846ccdbfdc570d4a5bd2244988b06
1 #!/usr/bin/python
3 # scan13 - utility to read bar codes from EPS files.
5 # Should be able to handle all EAN-13 variants including ISBN with UPC5
6 # price code.
8 # usage:
9 # scan13 <filename.eps>
11 # Copyright (C) 2007 Judah Milgram
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; either version 2
16 # of the License, or (at your option) any later version.
18 # Because this program copies a portion of itself into its output
19 # file, its output files are also copyright the author and licensed
20 # under the GPL. Relevant provisions of the GPL notwithstanding,
21 # the author licenses users to use and redistribute output files
22 # generated by this program without restriction.
24 # This program is distributed in the hope that it will be useful,
25 # but WITHOUT ANY WARRANTY; without even the implied warranty of
26 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 # GNU General Public License for more details.
29 # You should have received a copy of the GNU General Public License along
30 # with this program; if not, write to the Free Software Foundation, Inc.,
31 # 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
35 import getopt
36 import os
37 import Image
38 import sys
39 import productcode
40 import re
41 import tempfile
44 YSIZE=2400
45 STRIPCOMMAND = "pstopnm -pbm -stdout -portrait -ysize %d -xborder 0 -yborder 0 %%s 2> /dev/null | pnmcut -top %d -bottom %d" % (YSIZE,YSIZE/2,YSIZE/2)
47 EPSFILE = re.compile(".*\.eps",re.I)
49 def eps2pixels(f):
50 if not EPSFILE.match(f):
51 raise Exception
52 tempfil = tempfile.mktemp()
53 s = os.popen("%s > %s" % (STRIPCOMMAND%f,tempfil)).readline()
54 z = Image.open(tempfil)
55 w,h = z.size
56 pix = z.load()
57 pixels = []
58 for i in range(w):
59 pixels.append(pix[i,0])
60 os.unlink(tempfil)
61 return pixels
63 def pixels2bars(pixels):
64 bars = []
65 p = 1
66 for i in range(1,len(pixels)):
67 if pixels[i]!= pixels[i-1]:
68 bars.append(p)
69 p = 1
70 else:
71 p+=1
72 bars.append(p)
73 # bars are in pixels
74 # reduce to module widths
75 i,a = ean13index(bars)
76 bars = bars[i:]
77 for j in range(len(bars)):
78 bars[j] = int(round(bars[j]/float(a)))
79 ean13bars = bars
80 i,a = upc5index(bars)
81 upc5bars = bars[i:]
82 return (ean13bars,upc5bars)
84 def upc5index(bars):
85 # Looking for 3 bars in ean13 right guard
86 # then long space
87 # then first two bars in upc5 left guard
88 for i in range(len(bars)):
89 candidates = bars[i:i+5]
90 a = min(candidates[:3] + candidates[4:])
91 b = max(candidates[:3] + candidates[4:])
92 c = candidates[3]
93 err = 0.20
94 nlong=8
95 # sorry for the hard-coded magic number (8) ...
96 if abs(1-float(a)/b) < err and c > nlong*a:
97 return i+4,a
98 return None
101 def ean13index(bars):
102 # index of EAN13 guard bars and module size
103 for i in range(len(bars)):
104 candidates = bars[i:i+3]
105 a = min(candidates)
106 b = max(candidates)
107 err = 0.20
108 if abs(1-float(a)/b) < err:
109 return i,a
110 return None
112 def bars2bits(bars):
113 val = 1
114 bits=[]
115 for bar in bars:
116 bits.extend(bar*[val])
117 # flip val:
118 val = val ^ 1
119 return bits
121 def upc5digit(bits):
122 bits = "".join(map(str,bits))
123 for i in range(len(productcode.UPC5BITS)):
124 dict = productcode.UPC5BITS[i]
125 keys = dict.keys()
126 for key in keys:
127 if dict[key]==bits:
128 return i,key
129 return None,None
131 def ean13digit(bits):
132 bits = "".join(map(str,bits))
133 for i in range(len(productcode.EAN13BITS)):
134 dict = productcode.EAN13BITS[i]
135 keys = dict.keys()
136 for key in keys:
137 if dict[key]==bits:
138 return i,key
141 if __name__=="__main__":
143 MYNAME="scan13"
144 MYVERSION="0.1"
145 COPYRIGHT="(C) 2007 J. Milgram"
146 VERSIONDATE = "Feb 2007"
147 MAINTAINER = "bookland-bugs@cgpp.com"
148 WARNING = "This is free software and comes with NO WARRANTY"
150 sys.stderr.write("%s\n" % WARNING)
152 filnam = sys.argv[1]
154 pixels = eps2pixels(filnam)
155 ean13bars,upc5bars = pixels2bars(pixels)
156 ean13bits = bars2bits(ean13bars)
157 upc5bits = bars2bits(upc5bars)
159 NLEFT=3
160 NCENTER=5
161 ean13digits=[]
162 ean13pattern=[]
163 for i in range(6):
164 i0 = i*7 + NLEFT
165 i1 = i0+7
166 digit,parity = ean13digit(ean13bits[i0:i1])
167 ean13digits.append(digit)
168 ean13pattern.append(parity)
169 for i in range(6,12):
170 i0 = i*7 + NLEFT + NCENTER
171 i1 = (i+1)*7 + NLEFT + NCENTER
172 digit,parity=ean13digit(ean13bits[i0:i1])
173 ean13digits.append(digit)
174 ean13pattern.append(parity)
175 ean13pattern = "".join(ean13pattern)
176 checkDigit = productcode.EAN13PARITY.index(ean13pattern)
177 ean13digits.insert(0,checkDigit)
178 ean13 = "".join(map(str,ean13digits))
180 NLEFT = 4
181 upc5digits=[]
182 upc5pattern=[]
183 for i in range(5):
184 # 9 = 7 bits + 2 "delineators"
185 i0=i*9 + NLEFT
186 i1=i0+9
187 digit,parity = upc5digit(upc5bits[i0:i0+7])
188 upc5digits.append(digit)
189 upc5pattern.append(parity)
190 upc5 = "".join(map(str,upc5digits))
193 print ean13,upc5