[PageD'Accueil] [IndexDesTitres] [IndexDesTermes

Générateur de code barres

J'ai cherché un moment un générateur de code barres qui fabrique des images, et je n'en ai pas trouvé, du coup j'ai décidé d'en écrire un, en espérant qu'il serve à quelqu'un.

Il génère des images (gif ou png) contenant des codes EAN, il nécessite l'installation de PIL (http://www.pythonware.com/products/pil/). Il génère aussi les codes barres au format HTML, dans ce cas PIL n'a pas besoin d'être installé.

Exemple de génération d'une image :

   1 from EANBarCode import EanBarCode
   2 bar = EanBarCode()
   3 bar.getImage("9782212110708",50,"gif")

Source du fichier EANBarCode.py

   1 """
   2 This class generate EAN bar code, it required PIL (python imaging library)
   3 installed.
   4 
   5 If the code has not checksum (12 digits), it added automatically.
   6 
   7 Create bar code sample :
   8    from EANBarCode import EanBarCode
   9    bar = EanBarCode()
  10    bar.getImage("9782212110708",50,"gif")
  11 
  12 """
  13 
  14 # courbB08.pil PIL Font file base64 encoded
  15 courB08_pil ="""eJztl91rFkcUxp+Zt7vGFYzVtiJKICgYlLRWkaBBVGgDraFGCH5gsQp+QMBqabAVRYJYAlakCkoh
  16 CpYgxaLkIu1NvLBeSAStglpqL6xQAsVe2AuL5u2buH3mzGaYPf9AKWTl8d3nl7MzZ2bnazvea9+9
  17 7+PurFWut5e0Zu+s7VybYfKavP7LK3X/5TlM4Q3/OWbyf1ARD/6mgb2SjwtPhbpnq0iKZ6ahrmCj
  18 wqbxdgamRnHOA69jimN5zvIS8cDcUEeVdYzRAw1FHcJYXgPvG4s6Jlgj7xeEequS3wLeNvGvnrEO
  19 tq+Jt82szT+b86+WHlgS2jHGuHF6YHnog1zaupxqCcy3t4X3rVG9iXhgjW+bsFQ80BaxRDywTrF1
  20 VId6toPaqOI2UlsV20ptV2w7tUuxXVSXYl3UvoIZ9kFFPPBJ6D/HLD3QXbwjyDjI6YHPiz5FXiN7
  21 SQ8cDu/N9/1h3veEOP/Oe6gvQnmuvYYe+NL3qYyNVDxw2seF8XKa+jrKJREPnFdx56l+xfqpS4pd
  22 ogZUeQPU91FcKh64GveBeOCaKu8adUM9e4O6reJuU/cUu0c9VM8+pB6r/B5TI+rZEerPUpyhB/6K
  23 5lsqHniuyntO1VR5Nb5CU86FHqZOsTqqXrF66o2ojlQ8zDwVN4+aX86FHqYpXg9YLeevWRzPc7LF
  24 ZG+V1wN6mKXxvMzH6GFaJua5zGNLD7MqmtNcc+hh1oT1oCb5cf6aNj92mbPMGXqY9jCPasLaqQ1h
  25 jMv8pYfZpOI2UR9GcYl4mB1RnMtvB9me8N583B5qb3mNoIf5NGJc1+hhPvPrrjybioc5op49Qh0L
  26 dfj8jlHHQ3s9O059Fc3zRDzMmVKcpYfpU+3oI/umxJyH+TYqLxUPc0X13xVqMMovFQ8zpPIbon6M
  27 WCoeZljVMUz9VIqz9DAP1Dt6QP0a9gpZ7+lhHhXjysreaOhhfiv1vaGH+T2Mv5rbU+hh/uAaOnlN
  28 Xv+Hy4/7mtv3OW5hnpTODIYe5mm0xqbiYf4OcbLv08NU1ZyuuqKLOEvm6sjhJkd8TjRustgkrO3u
  29 vFGjh60r1uyiPHrY6eH84tb7l/SwM8vrAT3snHgNY9wcsoby+Y8edn5UxxTxsIuitrlcFpG9GcVx
  30 /6CHXRrKk72MHrYl3stYB/ceu7I4X02wlWSrCmaF1ehhV7NrovWKHrattI4betj20Fc8r7E87kf2
  31 g+gcy32BHnZDfKZmHPco2xnl4vqlk2yz6r/N1EfRPpiKh90d7VGpeNi9inGPst2lNdbSwx4McS8k
  32 7iDVE/Ytz3qoXsV6qZOKnaTOBDYqjPuRPRfOkz7uHNUf4uQMQg/7XekMYulhB6JnE/GwP0T1JuJh
  33 ryrGM6G9HuWSiIcdDnPmhTs70sPeCuPes1vUXcXuUvcDGxV2n/olOisn4mEfhfOVby/3KDsSlZeI
  34 h32iGOe0faoY57R9ptgzajTKJREPOx7aJnOfHhUbxov0Mz0qU8v50aMyo/wu6VGZrdhsqqH8fnll
  35 HEEz4zj6DNMxK+4X+gyv8cszyoU+4zfmjNAO9zuXrNGXF1gj2ULFFpI1K9ZMtiww//22jGwFXg39
  36 535XkK0O+cl5gz7Du6iP5wd9hvfDs9LP9BnWR/U6tp6sU7FOsi1RLo5tIdsWled+t5HtVO3YSdal
  37 WBfZftW2/WQHVH4HyA6F9+GfPUR2VOV3lKxXsV6yE4qdIDul2Cmys6ptZ8n6Qi7+m7OP7ELoU/8t
  38 dIHsoo8L+V0ku6xyvkw2qNgg2VBgvg+GyK6XyrP0GW5ydE3EuXd5k+xOeOdVibtD9jNm/Qv15O4i"""
  39 
  40 # courbB08.pbm font file base64 encoded
  41 courB08_pbm ="""eJxNkntM01cUx8+P2/1apUAZEpECq4KRjKhF0E55FYEp4yG6mglz2Q8Q1BhERhhls/zKI+CID4wb
  42 IAPKpk4GAzqZPKKMX2GIUwGJG+ImtKwKjIzXcGuBtncV0Hn+uLnn5Nzv55xv7mdRkbusVjquBACr
  43 0N3B+wCQi/m+ijAf4LGl/wgAiwkNDpRIyyABSjGkBQ/fa3c1bfLs4U8ulDcYUs/502rTpIlO9pyc
  44 Kp/Buql6f3rmZ1NqvpO2SZXf0duY3j0563zjoZpW8AvHRmVeZ/Co36mFR8bERzlsxOMJ+oJshsS5
  45 7rlfzFzmnZFEFnIEZjTGizgLsLzjl4QtrNprBRu10e+u9GgePHjG63bPDw/H87uix0Vtsvkqg9qO
  46 lUimPLiOM4z69YfqIu5Pa2Sr/io6n9Xmf9e+57W1Iapo4lLQBdLSWc/z3KOSlgznDXTW/Flh21kX
  47 IeUIX8FZVL9dwP4NBH5jglYxkBNFmWgMcfsAxM/9gEL5TTwYpnfElR8qQ+WiCgeTHOAfb2bW/cQC
  48 /FozFOOQzAebtjRvQLI7HBtXvaZe25a3Q/1vZpPa+kd1XXKuflr5Cm48YUsUcjMXjsm/sf+22s6z
  49 QAbGZ8mEXMzSE4y9AHhRpltwB1N9ynz5H2MOi0MEi4E5O1ov9ogrFU5cMWAcdgQb3xHFtFK+0pkh
  50 VnYWxltx92j69p6jJ9OnHr+Cq5x5X6Mz70JcX2tEG5LIShM4EHIGoLIRsHzcvEuGwMYA4DZPn7gP
  51 MA1QIgltnt82cTu7j5n76mmz3TU5Bh3PFRTHku52aBgaTnJD7m1c0a3hNjbWWjBtMsP/OFac/LYA
  52 NAAWepdYodB58NBFIuOjNSQ4cgXplqP2RyOe8fd999T8weqBRwLwNFdQobHgA1/YTV8PH+TwV59v
  53 Bo7Y1J4rmHFv3T9e8rmmXdGSuPpSbBnhYJ7V8ICz6AfGcdTpRkpCUU8WcOT8wb+dSHIb6QZapx0M
  54 Y2DO4i7jYV2AUNkkErpQFHVYmFRmYD7OJhDyQSiow4IkrS3TbpQqFA9slE4jnj6peXMTC+N8buJ2
  55 0Uv5eOothuGIiluyCDtff3miBzJHjncOIC3bPT8FLabRPd0TCWy346Mmn9Rz23WyNMJcsnqhQani
  56 3CMFOZuYU7c20zTNVqNbGPNxALWnybeLEcTvXWpc10leI5ae/CI9qBqI686cnO6P6F33e2vAp0nz
  57 9+hnbNeueh/261UJK5aVeSf73ZSXA7dOBXvkXODEb9hVww4KtPNAbPvaZbi0q9kICCl+CiBJSzLv
  58 a8TlntYlC4UHvCRTlaXOy13VAbN0eae2v3hNesWXLsWPkjfOPq7e6zd1fOfc1TckDaylrvleinnT
  59 8Ui87ScLMVhhEx7SUJ8U2zKrRR2Z1dEqZlkr7kDTuhFjpkvse9ZXN0R9H+DlYA4TXVm6/kXDQMyT
  60 eGnJFXlLlSgva5iLUEcbiyDzNqf4Wr9kKYVUIcY40DrnsW4E4zW9QxnHVYx+bo64mIskDWjZgCrq
  61 eVQFrS7Sh/uFLftIidKWbgj6Oq652d4c3v88Dw2JDK7bSWX/ByuaLZI="""
  62 
  63 
  64 class EanBarCode:
  65    """ Compute the EAN bar code """
  66    def __init__(self):
  67       A = {0 : "0001101", 1 : "0011001", 2 : "0010011", 3 : "0111101", 4 : "0100011", 
  68            5 : "0110001", 6 : "0101111", 7 : "0111011", 8 : "0110111", 9 : "0001011"}
  69       B = {0 : "0100111", 1 : "0110011", 2 : "0011011", 3 : "0100001", 4 : "0011101",
  70            5 : "0111001", 6 : "0000101", 7 : "0010001", 8 : "0001001", 9 : "0010111"}
  71       C = {0 : "1110010", 1 : "1100110", 2 : "1101100", 3 : "1000010", 4 : "1011100",
  72            5 : "1001110", 6 : "1010000", 7 : "1000100", 8 : "1001000", 9 : "1110100"}
  73       self.groupC = C
  74 
  75       self.family = {0 : (A,A,A,A,A,A), 1 : (A,A,B,A,B,B), 2 : (A,A,B,B,A,B), 3 : (A,A,B,B,B,A), 4 : (A,B,A,A,B,B),
  76                      5 : (A,B,B,A,A,B), 6 : (A,B,B,B,A,A), 7 : (A,B,A,B,A,B), 8 : (A,B,A,B,B,A), 9 : (A,B,B,A,B,A)}
  77 
  78 
  79    def makeCode(self, code):
  80       """ Create the binary code
  81       return a string which contains "0" for white bar, "1" for black bar, "L" for long bar """
  82       
  83       # Convert code string in integer list
  84       self.EAN13 = []
  85       for digit in code:
  86          self.EAN13.append(int(digit))
  87          
  88       # If the code has already a checksum
  89       if len(self.EAN13) == 13:
  90          # Verify checksum
  91          self.verifyChecksum(self.EAN13)
  92       # If the code has not yet checksum
  93       elif len(self.EAN13) == 12:
  94          # Add checksum value
  95          self.EAN13.append(self.computeChecksum(self.EAN13))
  96       
  97       # Get the left codage class
  98       left = self.family[self.EAN13[0]]
  99       
 100       # Add start separator
 101       strCode = 'L0L'
 102       
 103       # Compute the left part of bar code
 104       for i in range(0,6):
 105          strCode += left[i][self.EAN13[i+1]]
 106       
 107       # Add middle separator 
 108       strCode += '0L0L0'
 109       
 110       # Compute the right codage class
 111       for i in range (7,13):
 112          strCode += self.groupC[self.EAN13[i]]
 113       
 114       # Add stop separator
 115       strCode += 'L0L'
 116       
 117       return strCode
 118 
 119 
 120    def computeChecksum(self, arg):
 121       """ Compute the checksum of bar code """
 122       # UPCA/EAN13
 123       weight=[1,3]*6
 124       magic=10
 125       sum = 0
 126       
 127       for i in range(12):         # checksum based on first 12 digits.
 128          sum = sum + int(arg[i]) * weight[i]
 129       z = ( magic - (sum % magic) ) % magic
 130       if z < 0 or z >= magic:
 131          return None
 132       return z
 133 
 134 
 135    def verifyChecksum(self, bits): 
 136       """ Verify the checksum """
 137       computedChecksum = self.computeChecksum(bits[:12])
 138       codeBarChecksum = bits[12]
 139       
 140       if codeBarChecksum != computedChecksum:
 141          raise Exception ("Bad checksum is %s and should be %s"%(codeBarChecksum, computedChecksum))
 142 
 143 
 144    def getImage(self, value, height = 50, extension = "PNG"):
 145       """ Get an image with PIL library 
 146       value code barre value
 147       height height in pixel of the bar code
 148       extension image file extension"""
 149       from PIL import Image, ImageFont, ImageDraw
 150       from string import lower, upper
 151       
 152       # Create a missing font file
 153       decodeFontFile(courB08_pil ,"courB08.pil")
 154       decodeFontFile(courB08_pbm ,"courB08.pbm")
 155       
 156       # Get the bar code list
 157       bits = self.makeCode(value)
 158       
 159       # Get thee bar code with the checksum added
 160       code = ""
 161       for digit in self.EAN13:
 162          code += "%d"%digit
 163       
 164       # Create a new image
 165       position = 8
 166       im = Image.new("1",(len(bits)+position,height))
 167       
 168       # Load font
 169       font = ImageFont.load("courB08.pil")
 170       
 171       # Create drawer
 172       draw = ImageDraw.Draw(im)
 173       
 174       # Erase image
 175       draw.rectangle(((0,0),(im.size[0],im.size[1])),fill=256)
 176       
 177       # Draw first part of number
 178       draw.text((0, height-9), code[0], font=font, fill=0)
 179       
 180       # Draw first part of number
 181       draw.text((position+7, height-9), code[1:7], font=font, fill=0)
 182          
 183       # Draw second part of number
 184       draw.text((len(bits)/2+6+position, height-9), code[7:], font=font, fill=0)
 185       
 186       # Draw the bar codes
 187       for bit in range(len(bits)):
 188          # Draw normal bar
 189          if bits[bit] == '1':
 190             draw.rectangle(((bit+position,0),(bit+position,height-10)),fill=0)
 191          # Draw long bar
 192          elif bits[bit] == 'L':
 193             draw.rectangle(((bit+position,0),(bit+position,height-3)),fill=0)
 194             
 195       # Save the result image
 196       im.save(code+"."+lower(extension), upper(extension))
 197 
 198 
 199    def getHtml(self, value, height = 50):
 200       """ Build an HTML bar code """
 201       result = ""
 202       
 203       # Get the bar code list
 204       bits = self.makeCode(value)
 205       
 206       # Get thee bar code with the checksum added
 207       code = ""
 208       for digit in self.EAN13:
 209          code += "%d"%digit
 210          
 211       result += '<table><tr><td><center><table cellspacing="0" cellpadding="0" border="0" bgcolor="white"><tr height=%d >'%height
 212       
 213       bitsList = []
 214       previousBit = ""
 215       for bit in bits:
 216          if bit == previousBit:
 217             if bit == "0":
 218                bitsList[-1] -= 1
 219             else:
 220                bitsList[-1] += 1
 221          else:
 222             if bit == "0":
 223                bitsList.append(-1)
 224             else:
 225                bitsList.append(1)
 226          
 227          previousBit = bit
 228          
 229       result += '<td width=10></td>'
 230       for bit in bitsList:
 231          if bit < 0:
 232             result += '<td width=%d></td>'%(-bit)
 233          else:
 234             result += '<td bgcolor="black" width=%d></td>'%(+bit)
 235             
 236       result += '<td width=10></td>'
 237       result += "</tr></table></center></td></tr><tr><td><center>%s</center></td></tr></table>"%(code)
 238       
 239       return result
 240       
 241 
 242 def decodeFontFile(data, file):
 243    """ Decode font file embedded in this script and create file """
 244    from zlib import decompress
 245    from base64 import decodestring
 246    from os.path import exists
 247    
 248    # If the font file is missing
 249    if not exists(file):
 250       # Write font file
 251       open (file, "wb").write(decompress(decodestring(data)))
 252 
 253 
 254 def testWithChecksum():
 255    """ Test bar code with checksum """
 256    bar = EanBarCode()
 257    assert(bar.makeCode('0000000000000')== 'L0L0001101000110100011010001101000110100011010L0L0111001011100101110010111001011100101110010L0L' )
 258    assert(bar.makeCode('1111111111116')== 'L0L0011001001100101100110011001011001101100110L0L0110011011001101100110110011011001101010000L0L' )
 259    assert(bar.makeCode('2222222222222')== 'L0L0010011001001100110110011011001001100110110L0L0110110011011001101100110110011011001101100L0L' )
 260    assert(bar.makeCode('3333333333338')== 'L0L0111101011110101000010100001010000101111010L0L0100001010000101000010100001010000101001000L0L' )
 261    assert(bar.makeCode('4444444444444')== 'L0L0100011001110101000110100011001110100111010L0L0101110010111001011100101110010111001011100L0L' )
 262    assert(bar.makeCode('5555555555550')== 'L0L0110001011100101110010110001011000101110010L0L0100111010011101001110100111010011101110010L0L' )
 263    assert(bar.makeCode('6666666666666')== 'L0L0101111000010100001010000101010111101011110L0L0101000010100001010000101000010100001010000L0L' )
 264    assert(bar.makeCode('7777777777772')== 'L0L0111011001000101110110010001011101100100010L0L0100010010001001000100100010010001001101100L0L' )
 265    assert(bar.makeCode('8888888888888')== 'L0L0110111000100101101110001001000100101101110L0L0100100010010001001000100100010010001001000L0L' )
 266    assert(bar.makeCode('9999999999994')== 'L0L0001011001011100101110001011001011100010110L0L0111010011101001110100111010011101001011100L0L' )   
 267 
 268 
 269 def testWithoutChecksum():
 270    """ Test bar code without checksum """
 271    bar = EanBarCode()
 272    assert(bar.makeCode('000000000000')== 'L0L0001101000110100011010001101000110100011010L0L0111001011100101110010111001011100101110010L0L' )
 273    assert(bar.makeCode('111111111111')== 'L0L0011001001100101100110011001011001101100110L0L0110011011001101100110110011011001101010000L0L' )
 274    assert(bar.makeCode('222222222222')== 'L0L0010011001001100110110011011001001100110110L0L0110110011011001101100110110011011001101100L0L' )
 275    assert(bar.makeCode('333333333333')== 'L0L0111101011110101000010100001010000101111010L0L0100001010000101000010100001010000101001000L0L' )
 276    assert(bar.makeCode('444444444444')== 'L0L0100011001110101000110100011001110100111010L0L0101110010111001011100101110010111001011100L0L' )
 277    assert(bar.makeCode('555555555555')== 'L0L0110001011100101110010110001011000101110010L0L0100111010011101001110100111010011101110010L0L' )
 278    assert(bar.makeCode('666666666666')== 'L0L0101111000010100001010000101010111101011110L0L0101000010100001010000101000010100001010000L0L' )
 279    assert(bar.makeCode('777777777777')== 'L0L0111011001000101110110010001011101100100010L0L0100010010001001000100100010010001001101100L0L' )
 280    assert(bar.makeCode('888888888888')== 'L0L0110111000100101101110001001000100101101110L0L0100100010010001001000100100010010001001000L0L' )
 281    assert(bar.makeCode('999999999999')== 'L0L0001011001011100101110001011001011100010110L0L0111010011101001110100111010011101001011100L0L' )   
 282 
 283 
 284 def testImage():
 285    """ Test images generation with PIL """
 286    bar = EanBarCode()
 287    bar.getImage("9782212110708",50,"gif")
 288    bar.getImage("978221211070",50,"png")
 289 
 290 
 291 def testHtml():
 292    """ Test HTML generation """
 293    bar = EanBarCode()
 294    open("9782212110708.html","w").write(bar.getHtml("9782212110708",50))
 295    assert(bar.getHtml("9782212110708",50) == '<table><tr><td><center><table cellspacing="0" cellpadding="0" border="0" bgcolor="white"><tr height=50 ><td width=10></td><td bgcolor="black" width=1></td><td width=1></td><td bgcolor="black" width=1></td><td width=1></td><td bgcolor="black" width=3></td><td width=1></td><td bgcolor="black" width=2></td><td width=3></td><td bgcolor="black" width=1></td><td width=2></td><td bgcolor="black" width=1></td><td width=2></td><td bgcolor="black" width=2></td><td width=1></td><td bgcolor="black" width=2></td><td width=2></td><td bgcolor="black" width=1></td><td width=2></td><td bgcolor="black" width=2></td><td width=1></td><td bgcolor="black" width=2></td><td width=2></td><td bgcolor="black" width=2></td><td width=2></td><td bgcolor="black" width=1></td><td width=2></td><td bgcolor="black" width=2></td><td width=1></td><td bgcolor="black" width=1></td><td width=1></td><td bgcolor="black" width=1></td><td width=1></td><td bgcolor="black" width=2></td><td width=2></td><td bgcolor="black" width=2></td><td width=1></td><td bgcolor="black" width=2></td><td width=2></td><td bgcolor="black" width=2></td><td width=1></td><td bgcolor="black" width=3></td><td width=2></td><td bgcolor="black" width=1></td><td width=1></td><td bgcolor="black" width=1></td><td width=3></td><td bgcolor="black" width=1></td><td width=2></td><td bgcolor="black" width=3></td><td width=2></td><td bgcolor="black" width=1></td><td width=1></td><td bgcolor="black" width=1></td><td width=2></td><td bgcolor="black" width=1></td><td width=3></td><td bgcolor="black" width=1></td><td width=1></td><td bgcolor="black" width=1></td><td width=10></td></tr></table></center></td></tr><tr><td><center>9782212110708</center></td></tr></table>')
 296 
 297 
 298 def test():
 299    """ Execute all tests """
 300    testWithChecksum()
 301    testWithoutChecksum()
 302    testHtml()
 303    testImage()
 304 
 305 
 306 if __name__ == "__main__":
 307    test()

Liens

alternatives libres

- http://www.cgpp.com/bookland/ en Python également (utilise TeX)

- http://www.kbarcode.net/ pour créer des codes barre sous KDE et les enregistrer au format vectoriel (EPS).

information complémentaire

- http://fr.wikipedia.org/wiki/Code_barre


2016-06-05 21:42